Merge branch 'libdexed-d' into 'master'

Add a D library to replace various D programs from the toolchain

See merge request basile.b/dexed!6
This commit is contained in:
Basile.B 2020-04-17 12:16:16 +00:00
commit dd238100fd
42 changed files with 774 additions and 1136 deletions

2
.gitignore vendored
View File

@ -28,3 +28,5 @@ public
dcd dcd
d-scanner d-scanner
extract_last_changelog_part extract_last_changelog_part
dexed-d/.dub
dub.selections.json

View File

@ -21,14 +21,13 @@ release:
GIT_SUBMODULE_STRATEGY: normal GIT_SUBMODULE_STRATEGY: normal
before_script: before_script:
- apt-get update -y - apt-get update -y
- apt-get install -y dpkg
- apt-get install -y rpm - apt-get install -y rpm
- apt-get install -y git - apt-get install -y git
- apt-get install -y zip - apt-get install -y zip
- apt-get install -y libcurl4-openssl-dev - apt-get install -y libcurl4-openssl-dev
- curl -JLO https://sourceforge.net/projects/lazarus/files/Lazarus%20Linux%20amd64%20DEB/Lazarus%202.0.6/fpc-laz_3.0.4-1_amd64.deb/download && apt install -y ./fpc-laz_3.0.4-1_amd64.deb - curl -JLO https://sourceforge.net/projects/lazarus/files/Lazarus%20Linux%20amd64%20DEB/Lazarus%202.0.8/fpc-laz_3.0.4-1_amd64.deb/download && apt install -y ./fpc-laz_3.0.4-1_amd64.deb
- curl -JLO https://sourceforge.net/projects/lazarus/files/Lazarus%20Linux%20amd64%20DEB/Lazarus%202.0.6/fpc-src_3.0.4-2_amd64.deb/download && apt install -y ./fpc-src_3.0.4-2_amd64.deb - curl -JLO https://sourceforge.net/projects/lazarus/files/Lazarus%20Linux%20amd64%20DEB/Lazarus%202.0.8/fpc-src_3.0.4-2_amd64.deb/download && apt install -y ./fpc-src_3.0.4-2_amd64.deb
- curl -JLO https://sourceforge.net/projects/lazarus/files/Lazarus%20Linux%20amd64%20DEB/Lazarus%202.0.6/lazarus-project_2.0.6-0_amd64.deb/download && apt install -y ./lazarus-project_2.0.6-0_amd64.deb - curl -JLO https://sourceforge.net/projects/lazarus/files/Lazarus%20Linux%20amd64%20DEB/Lazarus%202.0.8/lazarus-project_2.0.8-0_amd64.deb/download && apt install -y ./lazarus-project_2.0.8-0_amd64.deb
script: script:
- bash setup/build-release.sh - bash setup/build-release.sh
artifacts: artifacts:

View File

@ -1,3 +1,12 @@
# v3.9.0-dev
## Other
- Toolchain: removed he background tool _dastworx_ and replaced it with a library called _libdexed-d_. Although this will not change the user experience:
- Thousands of system calls to create the process and read its streams are saved.
- ddemangle not required anymore.
- crash in the new library will be fatal, i.e the IDE will have to be relaunched, while previously the tool was launched again, without significant impact on the IDE.
# v3.8.4 # v3.8.4
## Bugs fixed ## Bugs fixed

View File

@ -1,32 +0,0 @@
:: D compiler and arch
if "%dc%"=="" set dc=dmd
if "%mflags%"=="" set mflags=-m32
::iz sources
set iz=
for /r "../etc/iz/import/" %%F in (*.d) do call set iz=%%iz%% "%%F"
::dparse sources
set dparse=
for /r "../etc/libdparse/src/" %%F in (*.d) do call set dparse=%%dparse%% "%%F"
::stdxalloc sources
set stdxalloc=
for /r "../etc/stdx-allocator/source/" %%F in (*.d) do call set stdxalloc=%%stdxalloc%% "%%F"
::dast sources
set dast=
for /r "src/" %%F in (*.d) do call set dast=%%dast%% "%%F"
echo building...
::build
%dc% %dast% %dparse% %iz% %stdxalloc% ^
-O -release -inline -boundscheck=off %mflags% ^
-Isrc -I"..\etc\iz\import" -I"..\etc\libdparse\src" ^ -I"..\etc\stdx-allocator\source" ^
-of"..\bin\dastworx.exe"
::cleanup
del ..\bin\dastworx.obj
echo ...done

View File

@ -1,38 +0,0 @@
if [[ -z "$DC" ]]; then DC=dmd; fi
if [[ "$DC" == "ldc" ]]; then DC=ldmd2; fi
if [[ "$DC" == "ldc2" ]]; then DC=ldmd2; fi
if [[ "$DC" == "gdc" ]]; then DC=gdmd; fi
if [[ -z "$MFLAGS" ]]; then MFLAGS=-m64; fi
#iz sources
cd ../etc/iz/import/
iz=$(find `pwd` -type f -name \*.d)
cd ../../../dastworx
#dparse sources
cd ../etc/libdparse/src/
dparse=$(find `pwd` -type f -name \*.d)
cd ../../../dastworx
#stdx-alloc sources
cd ../etc/stdx-allocator/source/
stdxalloc=$(find `pwd` -type f -name \*.d)
cd ../../../dastworx
#dast sources
cd src/
dast=$(find `pwd` -type f -name \*.d)
cd ../
echo building dastworx using $DC...
#build
$DC ${dast[@]} ${dparse[@]} ${iz[@]} ${stdxalloc[@]} \
-O -release -inline -boundscheck=off $MFLAGS \
-Isrc -I../etc/iz/import -I../etc/libdparse/src -I../etc/stdx-allocator/source \
-of../bin/dastworx
#cleanup
rm ../bin/dastworx.o
echo ...done

View File

@ -1,52 +0,0 @@
object CurrentProject: TCENativeProject
OptionsCollection = <
item
name = 'devel'
debugingOptions.generateInfos = True
outputOptions.boundsCheck = onAlways
outputOptions.versionIdentifiers.Strings = (
'devel'
)
pathsOptions.outputFilename = '../bin/dastworx'
pathsOptions.extraSources.Strings = (
'../etc/iz/import/*'
'../etc/libdparse/src/*'
'../etc/stdx-allocator/source/*'
)
pathsOptions.importModulePaths.Strings = (
'../etc/iz/import'
'../etc/libdparse/src'
'../etc/stdx-allocator/source'
)
runOptions.options = [poUsePipes, poStderrToOutPut]
end
item
name = 'release'
outputOptions.boundsCheck = offAlways
outputOptions.optimizations = True
outputOptions.release = True
pathsOptions.outputFilename = '../bin/dastworx'
pathsOptions.extraSources.Strings = (
'../etc/iz/import/*'
'../etc/libdparse/src/*'
'../etc/stdx-allocator/source/*'
)
pathsOptions.importModulePaths.Strings = (
'../etc/iz/import'
'../etc/libdparse/src'
'../etc/stdx-allocator/source'
)
runOptions.options = [poUsePipes, poStderrToOutPut]
end>
Sources.Strings = (
'src/main.d'
'src/todos.d'
'src/symlist.d'
'src/imports.d'
'src/mainfun.d'
'src/common.d'
'src/halstead.d'
'src/ddoc_template.d'
)
ConfigurationIndex = 1
end

View File

@ -1,22 +0,0 @@
## Dastworx
_D AST works_ is a tool that processes the AST of a D module to extract several information used by dexed.
It's notably used by the _symbol list_ and the _todo list_ widgets.
## Build
If dexed is build manually you certainly have to build _dastworx_ too.
Two options exist.
#### Using dexed & the submodules
- If you've cloned this repository, make sure that the submodule are also here with `git submodule update --init`.
- In Dexed open the project `dastworx.dxp`.
- Select the `release` configuration.
- Click `Compile project`
#### Using the scripts
- Windows: `build.bat`
- Linux: `sh ./build.sh`

View File

@ -1,126 +0,0 @@
module imports;
import
std.stdio, std.algorithm, std.array, std.file, std.functional;
import
iz.memory;
import
dparse.lexer, dparse.ast, dparse.parser, dparse.rollback_allocator;
import
common;
/**
* Lists the modules imported by a module
*
* On the first line writes the module name or # between double quotes then
* each import is written in a new line. Import detection is not accurate,
* the imports injected by a mixin template or by a string variable are not detected,
* the imports deactivated by a static condition neither.
*
* The results are used by to detect which are the static libraries used by a
* runnable module.
*/
void listImports(const(Module) mod)
in
{
assert(mod);
}
body
{
mixin(logCall);
if (mod.moduleDeclaration)
writeln('"', mod.moduleDeclaration.moduleName.identifiers
.map!(a => a.text).join("."), '"');
else
writeln("\"#\"");
construct!(ImportLister).visit(mod);
}
/**
* Lists the modules imported by several modules
*
* The output consists of several consecutive lists, as formated for
* listImports. When no moduleDeclaration is available, the first line of
* a list matches the filename.
*
* The results are used by to detect which are the static libraries used by a
* runnable module.
*/
void listFilesImports(string[] files)
{
mixin(logCall);
RollbackAllocator allocator;
StringCache cache = StringCache(StringCache.defaultBucketCount);
LexerConfig config = LexerConfig("", StringBehavior.source);
ImportLister il = construct!(ImportLister);
foreach(fname; files)
{
ubyte[] source = cast(ubyte[]) std.file.read(fname);
Module mod = parseModule(getTokensForParser(source, config, &cache),
fname, &allocator, toDelegate(&ignoreErrors));
if (mod.moduleDeclaration)
writeln('"', mod.moduleDeclaration.moduleName.identifiers
.map!(a => a.text).join("."), '"');
else
writeln('"', fname, '"');
il.visit(mod);
}
}
private final class ImportLister: ASTVisitor
{
alias visit = ASTVisitor.visit;
size_t mixinDepth;
override void visit(const(Module) mod)
{
mixinDepth = 0;
mod.accept(this);
}
override void visit(const ConditionalDeclaration decl)
{
bool acc = true;
if (decl.compileCondition)
{
const ver = decl.compileCondition.versionCondition;
if (ver && ver.token.text in badVersions)
acc = false;
}
if (acc)
decl.accept(this);
}
override void visit(const(ImportDeclaration) decl)
{
foreach (const(SingleImport) si; decl.singleImports)
{
if (!si.identifierChain.identifiers.length)
continue;
si.identifierChain.identifiers.map!(a => a.text).join(".").writeln;
}
if (decl.importBindings) with (decl.importBindings.singleImport)
identifierChain.identifiers.map!(a => a.text).join(".").writeln;
}
override void visit(const(MixinExpression) mix)
{
++mixinDepth;
mix.accept(this);
--mixinDepth;
}
override void visit(const PrimaryExpression primary)
{
if (mixinDepth && primary.primary.type.isStringLiteral)
{
assert(primary.primary.text.length > 1);
size_t startIndex = 1;
startIndex += primary.primary.text[0] == 'q';
parseAndVisit!(ImportLister)(primary.primary.text[startIndex..$-1]);
}
primary.accept(this);
}
}

View File

@ -1,156 +0,0 @@
module dastworx;
import
core.memory;
import
std.array, std.getopt, std.stdio, std.path, std.algorithm, std.functional,
std.file;
import
iz.memory: construct;
import
iz.options: Argument, ArgFlags, ArgFlag, handleArguments, CantThrow;
import
dparse.lexer, dparse.parser, dparse.ast, dparse.rollback_allocator;
import
common, todos, symlist, imports, mainfun, halstead, ddoc_template;
void main(string[] args)
{
foreach(ref buffer; stdin.byChunk(4096))
Launcher.source.put(buffer);
handleArguments!(CantThrow, Launcher)(args[1..$]);
}
struct Launcher
{
static this()
{
GC.disable;
source.reserve(1024^^2);
}
__gshared @Argument("-l") int caretLine;
__gshared @Argument("-o") bool option1;
__gshared Appender!(ubyte[]) source;
__gshared string[] files;
// -o : deep visit the symbols
// alias deepSymList = option1;
// -o : outputs /++ +/ ddoc instead of /** */
// alias plusComment = option1;
/// Writes the list of files to process
@Argument("-f")
static void setFiles(string value)
{
files = value
.splitter(pathSeparator)
.filter!exists
.array;
}
/// Writes the symbol list
@Argument("-s", "", ArgFlags(ArgFlag.stopper))
static void handleSymListOption()
{
mixin(logCall);
static Appender!(AstErrors) errors;
static void handleErrors(string fname, size_t line, size_t col, string message, bool err)
{
errors ~= construct!(AstError)(cast(ErrorType) err, message, line, col);
}
RollbackAllocator alloc;
StringCache cache = StringCache(StringCache.defaultBucketCount);
LexerConfig config = LexerConfig("", StringBehavior.source);
source.data
.getTokensForParser(config, &cache)
.parseModule("", &alloc, &handleErrors)
.listSymbols(errors.data, option1);
}
/// Writes the list of todo comments
@Argument("-t", "", ArgFlags(ArgFlag.stopper))
static void handleTodosOption()
{
mixin(logCall);
if (files.length)
getTodos(files);
}
/// Writes the import list
@Argument("-i", "", ArgFlags(ArgFlag.stopper))
static void handleImportsOption()
{
mixin(logCall);
if (files.length)
{
listFilesImports(files);
}
else
{
RollbackAllocator alloc;
StringCache cache = StringCache(StringCache.defaultBucketCount);
LexerConfig config = LexerConfig("", StringBehavior.source);
source.data
.getTokensForParser(config, &cache)
.parseModule("", &alloc, toDelegate(&ignoreErrors))
.listImports();
}
}
/// Writes if a main() is present in the module
@Argument("-m", "", ArgFlags(ArgFlag.stopper))
static void handleMainfunOption()
{
mixin(logCall);
RollbackAllocator alloc;
StringCache cache = StringCache(StringCache.defaultBucketCount);
LexerConfig config = LexerConfig("", StringBehavior.source);
source.data
.getTokensForParser(config, &cache)
.parseModule("", &alloc, toDelegate(&ignoreErrors))
.detectMainFun();
}
/// Writes the halstead metrics
@Argument("-H", "", ArgFlags(ArgFlag.stopper))
static void handleHalsteadOption()
{
mixin(logCall);
RollbackAllocator alloc;
StringCache cache = StringCache(StringCache.defaultBucketCount);
LexerConfig config = LexerConfig("", StringBehavior.source);
source.data
.getTokensForParser(config, &cache)
.parseModule("", &alloc, toDelegate(&ignoreErrors))
.performHalsteadMetrics;
}
/// Writes the ddoc template for a given declaration
@Argument("-K", "", ArgFlags(ArgFlag.stopper))
static void handleDdocTemplateOption()
{
mixin(logCall);
RollbackAllocator alloc;
StringCache cache = StringCache(StringCache.defaultBucketCount);
LexerConfig config = LexerConfig("", StringBehavior.source);
source.data
.getTokensForParser(config, &cache)
.parseModule("", &alloc, toDelegate(&ignoreErrors))
.getDdocTemplate(caretLine, option1);
}
}

17
dexed-d/dub.json Normal file
View File

@ -0,0 +1,17 @@
{
"name" : "dexed-d",
"targetType" : "dynamicLibrary",
"targetPath" : "../bin",
"targetName" : "dexed-d",
"dependencies" : {
"libdparse" : {
"path" : "../etc/libdparse"
},
"iz" : {
"path" : "../etc/iz"
}
},
"dflags" : [
"-link-defaultlib-shared=false"
]
}

View File

@ -1,7 +1,9 @@
module common; module common;
import import
std.array, std.traits, std.meta, std.conv; core.stdc.string;
import
std.array, std.traits, std.meta, std.conv, std.algorithm, std.file, std.path;
import import
dparse.lexer, dparse.ast, dparse.parser, dparse.rollback_allocator; dparse.lexer, dparse.ast, dparse.parser, dparse.rollback_allocator;
import import
@ -385,7 +387,7 @@ unittest
* This function is used to handle the content of a MixinExpression in an * This function is used to handle the content of a MixinExpression in an
* ASTVisitor. * ASTVisitor.
*/ */
T parseAndVisit(T : ASTVisitor)(const(char)[] source) T parseAndVisit(T : ASTVisitor, A...)(const(char)[] source, A a)
{ {
import std.functional; import std.functional;
@ -394,7 +396,7 @@ T parseAndVisit(T : ASTVisitor)(const(char)[] source)
StringCache cache = StringCache(StringCache.defaultBucketCount); StringCache cache = StringCache(StringCache.defaultBucketCount);
const(Token)[] tokens = getTokensForParser(cast(ubyte[]) source, config, &cache); const(Token)[] tokens = getTokensForParser(cast(ubyte[]) source, config, &cache);
Module mod = parseModule(tokens, "", &allocator, toDelegate(&ignoreErrors)); Module mod = parseModule(tokens, "", &allocator, toDelegate(&ignoreErrors));
T result = construct!(T); T result = construct!(T)(a);
result.visit(mod); result.visit(mod);
return result; return result;
} }
@ -403,6 +405,14 @@ T parseAndVisit(T : ASTVisitor)(const(char)[] source)
* By default libdparse outputs errors and warnings to the standard streams. * By default libdparse outputs errors and warnings to the standard streams.
* This function prevents that. * This function prevents that.
*/ */
void ignoreErrors(string, size_t, size_t, string, bool) @system void ignoreErrors(string, size_t, size_t, string, bool) @system {}
{}
/**
* Split a C string representing a list of filenames into an array of strings.
* The filenames are separated with the system path separator.
*/
alias joinedFilesToFiles = (const char* a) => a[0 .. a.strlen]
.splitter(pathSeparator)
.filter!exists
.filter!(b => b != "")
.array;

37
dexed-d/src/ddemangle.d Normal file
View File

@ -0,0 +1,37 @@
module ddemangle;
import core.demangle : demangle;
import std.regex : replaceAll, Captures, regex, Regex;
import core.stdc.string : strlen;
import std.string : toStringz;
extern(C):
const(char)* ddemangle(const(char)* line)
{
__gshared Regex!char reDemangle;
__gshared bool reInit;
if (!reInit)
{
reInit = true;
reDemangle = regex(r"\b_?_D[0-9a-zA-Z_]+\b");
}
return replaceAll!(demangleMatch)(line[0 .. line.strlen], reDemangle).toStringz;
}
extern(D): private:
const(char)[] demangleMatch(Captures!(const(char)[]) m)
{
// If the second character is an underscore, it may be a D symbol with double leading underscore;
if (m.hit.length > 0 && m.hit[1] != '_')
{
return demangle(m.hit);
}
else
{
auto result = demangle(m.hit[1..$]);
return result == m.hit[1..$] ? m.hit : result;
}
}

View File

@ -1,20 +1,47 @@
module ddoc_template; module ddoc_template;
import import
std.stdio; core.stdc.string;
import
std.array, std.conv, std.string;
import import
iz.memory, iz.sugar; iz.memory, iz.sugar;
import import
dparse.ast, dparse.lexer, dparse.parser, dparse.rollback_allocator; dparse.ast, dparse.lexer, dparse.parser, dparse.rollback_allocator;
import
common;
/** /**
* Finds the declaration at caretLine and write its ddoc template * Finds the declaration at caretLine and write its ddoc template
* in the standard output. * and returns its DDOC template as a C string.
*
* Params:
* src = the module source code, as a C string.
* caretLine = the line where the declaration is located.
* plusComment = indicates if the template use the "*" or the "+" decoration.
*/ */
void getDdocTemplate(const(Module) mod, int caretLine, bool plusComment) extern(C) const(char)* ddocTemplate(const(char)* src, int caretLine, bool plusComment)
{ {
LexerConfig config;
RollbackAllocator rba;
StringCache sCache = StringCache(StringCache.defaultBucketCount);
scope mod = src[0 .. src.strlen]
.getTokensForParser(config, &sCache)
.parseModule("", &rba, &ignoreErrors);
DDocTemplateGenerator dtg = construct!DDocTemplateGenerator(caretLine, plusComment); DDocTemplateGenerator dtg = construct!DDocTemplateGenerator(caretLine, plusComment);
scope(exit) destruct(dtg);
dtg.visit(mod); dtg.visit(mod);
return dtg.result;
}
private void putLine(T...)(ref Appender!string a, T t)
{
static foreach (i; 0 .. T.length)
a.put(t[i].to!string);
a.put("\n");
} }
final class DDocTemplateGenerator: ASTVisitor final class DDocTemplateGenerator: ASTVisitor
@ -26,6 +53,7 @@ private:
immutable int _caretline; immutable int _caretline;
immutable char c1; immutable char c1;
immutable char[2] c2; immutable char[2] c2;
Appender!string app;
bool _throws; bool _throws;
public: public:
@ -37,6 +65,8 @@ public:
c2 = plusComment ? "++" : "**"; c2 = plusComment ? "++" : "**";
} }
const(char)* result() { return app.data.toStringz(); }
override void visit(const(ThrowStatement) ts) override void visit(const(ThrowStatement) ts)
{ {
_throws = true; _throws = true;
@ -53,26 +83,26 @@ public:
if (decl.name.line == _caretline) if (decl.name.line == _caretline)
{ {
decl.accept(this); decl.accept(this);
writeln("/", c2, "\n ", c1, " <short description> \n ", c1, " \n ", c1, " <detailed description>", c1); app.putLine("/", c2, "\n ", c1, " <short description> \n ", c1, " \n ", c1, " <detailed description>", c1);
const TemplateParameterList tpl = safeAccess(decl).templateParameters.templateParameterList; const TemplateParameterList tpl = safeAccess(decl).templateParameters.templateParameterList;
if ((tpl && tpl.items.length) || if ((tpl && tpl.items.length) ||
(decl.parameters && decl.parameters.parameters.length)) (decl.parameters && decl.parameters.parameters.length))
{ {
writeln(" ", c1, " \n ", c1, " Params:"); app.putLine(" ", c1, " \n ", c1, " Params:");
if (tpl) if (tpl)
{ {
foreach(const TemplateParameter p; tpl.items) foreach(const TemplateParameter p; tpl.items)
{ {
if (p.templateAliasParameter) if (p.templateAliasParameter)
writeln(" ", c1, " ", p.templateAliasParameter.identifier.text, " = <description>"); app.putLine(" ", c1, " ", p.templateAliasParameter.identifier.text, " = <description>");
else if (p.templateTupleParameter) else if (p.templateTupleParameter)
writeln(" ", c1, " ", p.templateTupleParameter.identifier.text, " = <description>"); app.putLine(" ", c1, " ", p.templateTupleParameter.identifier.text, " = <description>");
else if (p.templateTypeParameter) else if (p.templateTypeParameter)
writeln(" ", c1, " ", p.templateTypeParameter.identifier.text, " = <description>"); app.putLine(" ", c1, " ", p.templateTypeParameter.identifier.text, " = <description>");
else if (p.templateValueParameter) else if (p.templateValueParameter)
writeln(" ", c1, " ", p.templateValueParameter.identifier.text, " = <description>"); app.putLine(" ", c1, " ", p.templateValueParameter.identifier.text, " = <description>");
} }
} }
if (decl.parameters) if (decl.parameters)
@ -80,9 +110,9 @@ public:
foreach(i, const Parameter p; decl.parameters.parameters) foreach(i, const Parameter p; decl.parameters.parameters)
{ {
if (p.name.text != "") if (p.name.text != "")
writeln(" ", c1, " ", p.name.text, " = <description>"); app.putLine(" ", c1, " ", p.name.text, " = <description>");
else else
writeln(" ", c1, " __param", i, " = <description>"); app.putLine(" ", c1, " __param", i, " = <description>");
} }
} }
} }
@ -90,15 +120,15 @@ public:
if (const Type2 tp2 = safeAccess(decl).returnType.type2) if (const Type2 tp2 = safeAccess(decl).returnType.type2)
{ {
if (tp2.builtinType != tok!"void") if (tp2.builtinType != tok!"void")
writeln(" ", c1, " \n ", c1, " Returns: <return description>"); app.putLine(" ", c1, " \n ", c1, " Returns: <return description>");
} }
if (_throws) if (_throws)
{ {
writeln(" ", c1, " \n ", c1, " Throws: <exception type as hint for catch>"); app.putLine(" ", c1, " \n ", c1, " Throws: <exception type as hint for catch>");
} }
writeln(" ", c1, "/"); app.putLine(" ", c1, "/");
} }
else if (decl.name.line > _caretline) else if (decl.name.line > _caretline)
@ -141,26 +171,26 @@ public:
if (_caretline == line) if (_caretline == line)
{ {
writeln("/", c2, "\n ", c1, " <short description> \n ", c1, " \n ", c1, " <detailed description>", c1); app.putLine("/", c2, "\n ", c1, " <short description> \n ", c1, " \n ", c1, " <detailed description>", c1);
const TemplateParameterList tpl = safeAccess(decl).templateParameters.templateParameterList; const TemplateParameterList tpl = safeAccess(decl).templateParameters.templateParameterList;
if (tpl && tpl.items.length) if (tpl && tpl.items.length)
{ {
writeln(" ", c1, " \n ", c1, " Params:"); app.putLine(" ", c1, " \n ", c1, " Params:");
foreach(const TemplateParameter p; tpl.items) foreach(const TemplateParameter p; tpl.items)
{ {
if (p.templateAliasParameter) if (p.templateAliasParameter)
writeln(" ", c1, " ", p.templateAliasParameter.identifier.text, " = <description>"); app.putLine(" ", c1, " ", p.templateAliasParameter.identifier.text, " = <description>");
else if (p.templateTupleParameter) else if (p.templateTupleParameter)
writeln(" ", c1, " ", p.templateTupleParameter.identifier.text, " = <description>"); app.putLine(" ", c1, " ", p.templateTupleParameter.identifier.text, " = <description>");
else if (p.templateTypeParameter) else if (p.templateTypeParameter)
writeln(" ", c1, " ", p.templateTypeParameter.identifier.text, " = <description>"); app.putLine(" ", c1, " ", p.templateTypeParameter.identifier.text, " = <description>");
else if (p.templateValueParameter) else if (p.templateValueParameter)
writeln(" ", c1, " ", p.templateValueParameter.identifier.text, " = <description>"); app.putLine(" ", c1, " ", p.templateValueParameter.identifier.text, " = <description>");
} }
} }
writeln(" ", c1, "/"); app.putLine(" ", c1, "/");
} }
else if (line > _caretline) else if (line > _caretline)
@ -169,61 +199,3 @@ public:
} }
} }
version(unittest)
{
DDocTemplateGenerator parseAndVisit(const(char)[] source, int caretLine, bool p = false)
{
writeln;
RollbackAllocator allocator;
LexerConfig config = LexerConfig("", StringBehavior.source, WhitespaceBehavior.skip);
StringCache cache = StringCache(StringCache.defaultBucketCount);
const(Token)[] tokens = getTokensForParser(cast(ubyte[]) source, config, &cache);
Module mod = parseModule(tokens, "", &allocator);
DDocTemplateGenerator result = construct!(DDocTemplateGenerator)(caretLine, p);
result.visit(mod);
return result;
}
}
unittest
{
q{ module a;
void foo(A...)(A a){}
}.parseAndVisit(2, true);
}
unittest
{
q{ module a;
void foo()(){}
}.parseAndVisit(2);
}
unittest
{
q{ module a;
int foo(int){}
}.parseAndVisit(2, true);
}
unittest
{
q{ module a;
class Foo(T, A...){}
}.parseAndVisit(2);
}
unittest
{
q{ module a;
struct Foo(alias Fun, A...){}
}.parseAndVisit(2);
}
unittest
{
q{ module a;
enum trait(alias Variable) = whatever;
}.parseAndVisit(2);
}

View File

@ -1,7 +1,9 @@
module halstead; module halstead;
import import
std.algorithm, std.conv, std.json, std.meta; core.stdc.string;
import
std.algorithm, std.conv, std.json, std.meta, std.string;
import import
std.stdio, std.ascii, std.digest.crc, std.range: iota; std.stdio, std.ascii, std.digest.crc, std.range: iota;
import import
@ -13,14 +15,36 @@ version(unittest){} else import
/** /**
* Retrieves the count and unique count of the operands and operators of * Retrieves the count and unique count of the operands and operators of
* each function (inc. methods) of a module. After the call the results are * each function (inc. member functions) of a module, allowing the compute
* serialized as JSON in te standard output. * the halstead complexity of the functions.
*
* Params:
* src = The source code of the module to analyze, as a C string.
*
* Returns: a string representing a JSON array named "functions".
* Each array item is a JSON object containing
* - a function name, named "name" (as JSONString)
* - a line number, named "line" (as JSONNumber)
* - the count of operators, named "n1count" (as JSONNumber)
* - the sum of operators, named "n1sum" (as JSONNumber)
* - the count of operands, named "n2count" (as JSONNumber)
* - the sum of operands, named "n2sum" (as JSONNumber)
*/ */
void performHalsteadMetrics(const(Module) mod) extern(C) const(char)* halsteadMetrics(const(char)* src)
{ {
LexerConfig config;
RollbackAllocator rba;
StringCache sCache = StringCache(StringCache.defaultBucketCount);
scope mod = src[0 .. src.strlen]
.getTokensForParser(config, &sCache)
.parseModule("", &rba, &ignoreErrors);
HalsteadMetric hm = construct!(HalsteadMetric); HalsteadMetric hm = construct!(HalsteadMetric);
scope (exit) destruct(hm);
hm.visit(mod); hm.visit(mod);
hm.serialize; return hm.serialize();
} }
private struct Function private struct Function
@ -57,11 +81,6 @@ private final class HalsteadMetric: ASTVisitor
void processCallChain() void processCallChain()
{ {
version(none)
{
import std.array : join;
writeln("chain: ", chain.map!(a => a.identifier.text).join("."));
}
if (chain.length) if (chain.length)
{ {
static Token getIdent(const(IdentifierOrTemplateInstance) i) static Token getIdent(const(IdentifierOrTemplateInstance) i)
@ -115,11 +134,11 @@ private final class HalsteadMetric: ASTVisitor
inFunctionCallChain.length++; inFunctionCallChain.length++;
} }
void serialize() const(char)* serialize()
{ {
JSONValue js; JSONValue js;
js["functions"] = fs; js["functions"] = fs;
js.toString.write; return js.toString.toStringz();
} }
override void visit(const(PragmaExpression)){} override void visit(const(PragmaExpression)){}

152
dexed-d/src/imports.d Normal file
View File

@ -0,0 +1,152 @@
module imports;
import
core.stdc.string;
import
std.algorithm, std.array, std.file, std.functional;
import
iz.memory;
import
dparse.lexer, dparse.ast, dparse.parser, dparse.rollback_allocator;
import
common;
private alias moduleDeclarationToText = (ModuleDeclaration md) => md.moduleName
.identifiers
.map!(a => a.text)
.join(".");
/**
* Lists the modules imported by a module
*
* On the first line writes the module name or # between double quotes then
* each import is written on a new line. Import detection is not accurate,
* the imports injected by a mixin template or by a string variable are not detected,
* the imports deactivated by a static condition neither.
*
* The results are used by to automatically detect the static libraries used by a
* dexed runnable module.
*/
extern(C) string[] listImports(const(char)* src)
{
string[] result;
LexerConfig config;
RollbackAllocator rba;
StringCache sCache = StringCache(StringCache.defaultBucketCount);
scope mod = src[0 .. src.strlen]
.getTokensForParser(config, &sCache)
.parseModule("", &rba, &ignoreErrors);
if (auto md = mod.moduleDeclaration)
result ~= '"' ~ moduleDeclarationToText(md) ~ '"';
else
result ~= "\"#\"";
ImportLister il = construct!(ImportLister)(&result);
scope (exit) destruct(il);
il.visit(mod);
return result;
}
/**
* Lists the modules imported by several modules
*
* The output consists of several consecutive lists, as formated for
* listImports. When no moduleDeclaration is available, the first line of
* a list matches the filename.
*
* The results are used by to build a key value store linking libraries to other
* libraries, which is part of dexed "libman".
*/
extern(C) string[] listFilesImports(const(char)* joinedFiles)
{
string[] result;
RollbackAllocator rba;
StringCache sCache = StringCache(StringCache.defaultBucketCount);
LexerConfig config = LexerConfig("", StringBehavior.source);
ImportLister il = construct!(ImportLister)(&result);
scope(exit) destruct(il);
foreach(fname; joinedFilesToFiles(joinedFiles))
{
scope mod = readText(fname)
.getTokensForParser(config, &sCache)
.parseModule("", &rba, &ignoreErrors);
if (auto md = mod.moduleDeclaration)
result ~= '"' ~ moduleDeclarationToText(md) ~ '"';
else
result ~= '"' ~ cast(string)fname ~ '"';
il.visit(mod);
}
return result;
}
private final class ImportLister: ASTVisitor
{
alias visit = ASTVisitor.visit;
size_t mixinDepth;
string[]* results;
this(string[]* results)
{
assert(results);
this.results = results;
}
override void visit(const(Module) mod)
{
mixinDepth = 0;
mod.accept(this);
}
override void visit(const ConditionalDeclaration decl)
{
bool acc = true;
if (decl.compileCondition)
{
const ver = decl.compileCondition.versionCondition;
if (ver && ver.token.text in badVersions)
acc = false;
}
if (acc)
decl.accept(this);
}
override void visit(const(ImportDeclaration) decl)
{
foreach (const(SingleImport) si; decl.singleImports)
{
if (!si.identifierChain.identifiers.length)
continue;
*results ~= si.identifierChain.identifiers.map!(a => a.text).join(".");
}
if (decl.importBindings) with (decl.importBindings.singleImport)
*results ~= identifierChain.identifiers.map!(a => a.text).join(".");
}
override void visit(const(MixinExpression) mix)
{
++mixinDepth;
mix.accept(this);
--mixinDepth;
}
override void visit(const PrimaryExpression primary)
{
if (mixinDepth && primary.primary.type.isStringLiteral)
{
assert(primary.primary.text.length > 1);
size_t startIndex = 1;
startIndex += primary.primary.text[0] == 'q';
auto il = parseAndVisit!(ImportLister)(primary.primary.text[startIndex..$-1], results);
destruct(il);
}
primary.accept(this);
}
}

View File

@ -5,33 +5,40 @@ import
import import
iz.memory, iz.sugar; iz.memory, iz.sugar;
import import
dparse.lexer, dparse.ast, dparse.parser; core.stdc.string;
import
dparse.lexer, dparse.parser, dparse.ast, dparse.rollback_allocator;
import import
common; common;
/** /**
* Detects wether a main function is declared in a module. * Params:
* * src = The source code for the module, as a null terminated string.
* Writes "1" if a main is found otherwise "0". The detection is not accurate, * Returns:
* if the main is injected by a mixin template or by a string it is not detected, * wether a module contains the main function.
* if the main is deactivated by a static condition neither.
*
* The result is used to determine if the "-main" switch has to be passed to
* the compiler when a runnable module is executed or a module tested.
*/ */
void detectMainFun(const(Module) mod) extern(C) bool hasMainFun(const(char)* src)
{ {
mixin(logCall); LexerConfig config;
RollbackAllocator rba;
StringCache sCache = StringCache(StringCache.defaultBucketCount);
scope mod = src[0 .. src.strlen]
.getTokensForParser(config, &sCache)
.parseModule("", &rba, &ignoreErrors);
MainFunctionDetector mfd = construct!(MainFunctionDetector); MainFunctionDetector mfd = construct!(MainFunctionDetector);
scope (exit) destruct(mfd);
mfd.visit(mod); mfd.visit(mod);
write(mfd.hasMain); return mfd.hasMain;
} }
private final class MainFunctionDetector: ASTVisitor private final class MainFunctionDetector: ASTVisitor
{ {
alias visit = ASTVisitor.visit; alias visit = ASTVisitor.visit;
ubyte hasMain; bool hasMain;
override void visit(const ConditionalDeclaration decl) override void visit(const ConditionalDeclaration decl)
{ {

View File

@ -1,28 +1,53 @@
module symlist; module symlist;
import import
std.stdio, std.array, std.traits, std.conv, std.json, std.format, core.stdc.string;
std.algorithm;
import import
iz.memory: construct; std.array, std.traits, std.conv, std.json, std.format,
std.algorithm, std.string;
import
iz.memory: construct, destruct;
import import
iz.containers : Array; iz.containers : Array;
import import
dparse.lexer, dparse.ast, dparse.parser, dparse.formatter : Formatter; dparse.lexer, dparse.ast, dparse.parser, dparse.formatter : Formatter;
import
dparse.rollback_allocator;
import import
common; common;
/** /**
* Serializes the symbols in the standard output * Visit and enumerate all the declaration of a module.
*
* Params:
* src = The module to visit, as source code.
* deep = Defines if the nested declarations are visited.
* Returns:
* The serialized symbols, as a C string.
*/ */
void listSymbols(const(Module) mod, AstErrors errors, bool deep = true) extern(C) const(char)* listSymbols(const(char)* src, bool deep)
{ {
mixin(logCall); Appender!(AstErrors) errors;
void handleErrors(string fname, size_t line, size_t col, string message, bool err)
{
errors ~= construct!(AstError)(cast(ErrorType) err, message, line, col);
}
LexerConfig config;
RollbackAllocator rba;
StringCache sCache = StringCache(StringCache.defaultBucketCount);
scope mod = src[0 .. src.strlen]
.getTokensForParser(config, &sCache)
.parseModule("", &rba, &handleErrors);
alias SL = SymbolListBuilder!(ListFmt.Pas); alias SL = SymbolListBuilder!(ListFmt.Pas);
SL.addAstErrors(errors); SL sl = construct!(SL)(errors, deep);
SL sl = construct!(SL)(deep); scope(exit) destruct(sl);
sl.visit(mod); sl.visit(mod);
sl.serialize.writeln; return sl.serialize();
} }
private: private:
@ -68,27 +93,22 @@ final class SymbolListBuilder(ListFmt Fmt): ASTVisitor
static if (Fmt == ListFmt.Pas) static if (Fmt == ListFmt.Pas)
{ {
static Appender!string pasStream; Appender!(char[]) pasStream;
} }
else else
{ {
static JSONValue json; JSONValue json;
static JSONValue* jarray; JSONValue* jarray;
} }
static Array!(char) funcNameApp; Array!char funcNameApp;
static Formatter!(typeof(&funcNameApp)) fmtVisitor; Formatter!(Array!char*) fmtVisitor;
static uint utc; uint utc;
this(bool deep) this(Appender!(AstErrors) errors, bool deep)
{ {
_deep = deep; _deep = deep;
} funcNameApp.length = 0;
alias visit = ASTVisitor.visit;
static this()
{
static if (Fmt == ListFmt.Pas) static if (Fmt == ListFmt.Pas)
{ {
pasStream.put("object TSymbolList\rsymbols=<"); pasStream.put("object TSymbolList\rsymbols=<");
@ -99,9 +119,12 @@ final class SymbolListBuilder(ListFmt Fmt): ASTVisitor
jarray = &json; jarray = &json;
} }
fmtVisitor = construct!(typeof(fmtVisitor))(&funcNameApp); fmtVisitor = construct!(typeof(fmtVisitor))(&funcNameApp);
addAstErrors(errors.data);
} }
static void addAstErrors(AstErrors errors) alias visit = ASTVisitor.visit;
void addAstErrors(AstErrors errors)
{ {
foreach(error; errors) foreach(error; errors)
{ {
@ -129,21 +152,21 @@ final class SymbolListBuilder(ListFmt Fmt): ASTVisitor
} }
} }
string serialize() const(char)* serialize()
{ {
static if (Fmt == ListFmt.Pas) static if (Fmt == ListFmt.Pas)
{ {
pasStream.put(">\rend"); pasStream.put(">\rend");
return pasStream.data; return pasStream.data.toStringz;
} }
else else
{ {
JSONValue result = parseJSON("{}"); JSONValue result = parseJSON("{}");
result["items"] = json; result["items"] = json;
version (assert) version (assert)
return result.toPrettyString; return result.toPrettyString.toStringz;
else else
return result.toString; return result.toString.toStringz;
} }
} }

View File

@ -8,27 +8,27 @@ import
import import
common; common;
private __gshared Appender!string stream; extern(C) const(char)* todoItems(const(char)* joinedFiles)
void getTodos(string[] files)
{ {
mixin(logCall); scope Appender!string stream;
stream.reserve(32 + 256 * files.length); stream.reserve(32);
stream.put("object TTodoItems\ritems=<"); stream.put("object TTodoItems\ritems=<");
foreach(fname; files) foreach(fname; joinedFilesToFiles(joinedFiles))
{ {
StringCache cache = StringCache(StringCache.defaultBucketCount); stream.reserve(256);
LexerConfig config = LexerConfig(fname, StringBehavior.source); scope StringCache cache = StringCache(StringCache.defaultBucketCount);
scope LexerConfig config = LexerConfig("", StringBehavior.source);
ubyte[] source = cast(ubyte[]) std.file.read(fname); ubyte[] source = cast(ubyte[]) std.file.read(fname);
foreach(ref token; DLexer(source, config, &cache).array foreach(ref token; DLexer(source, config, &cache)
.array
.filter!((a) => a.type == tok!"comment")) .filter!((a) => a.type == tok!"comment"))
analyze(token, fname); analyze(token, fname, stream);
} }
stream.put(">end"); stream.put(">end");
writeln(stream.data); return stream.data.toStringz();
} }
private void analyze(const(Token) token, string fname) private void analyze(const(Token) token, const(char)[] fname, ref Appender!string stream)
{ {
string text = token.text.strip.patchPascalString; string text = token.text.strip.patchPascalString;
string identifier; string identifier;

View File

@ -3,16 +3,15 @@ title: Build Dexed
header-includes: <script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/4.2.2/anchor.min.js"></script> header-includes: <script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/4.2.2/anchor.min.js"></script>
--- ---
## Dexed
Dexed is mostly programmed in Object Pascal, using the the [Lazarus development platform](http://www.lazarus-ide.org/). Dexed is mostly programmed in Object Pascal, using the the [Lazarus development platform](http://www.lazarus-ide.org/).
* [Download](http://lazarus.freepascal.org/index.php?page=downloads) and setup the latest Lazarus version (2.0.0) and FPC + FPC sources (3.0.4) for your platform. * [Download](http://lazarus.freepascal.org/index.php?page=downloads) and setup the latest Lazarus version (2.0.5) and FPC + FPC sources (3.0.4) for your platform.
* Windows: the three packages are bundled in an installer. * Windows: the three packages are bundled in an installer.
* Linux: the three packages must be downloaded and setup individually. It's recommended to download the packages from _SourceForge_ and not from the official repository of the distribution because they don't always propose the latest version. * Linux: the three packages must be downloaded and setup individually. It's recommended to download the packages from _SourceForge_ and not from the official repository of the distribution because they don't always propose the latest version.
* [Download](https://github.com/ldc-developers/ldc/releases) and setup LDC2, the LLVM-based D compiler. It is used to compile the part of IDE written in D, a library called _libdexed-d_. the binaries must be visible in the system PATH variable. Note that building _libdexed-d_ is automatic.
* `cd <user dir where to clone>` * `cd <user dir where to clone>`
* `git clone https://github.com/Basile-z/dexed.git` * `git clone https://gitlab.com/basile.b/dexed.git`
* `git submodule update --init`, to clone the dependencies used by the background tool. * `git submodule update --init`, to clone the dependencies used by libdexed-d.
The Lazarus LCL and the FreePascal FCL may require patches that fix bugs or regressions present in the latest Lazarus release and for which Dexed cannot include workarounds. The Lazarus LCL and the FreePascal FCL may require patches that fix bugs or regressions present in the latest Lazarus release and for which Dexed cannot include workarounds.
Any `.patch` file located in the `patches/` folder should be applied. On linux you'll have to set the write permissions to `/usr/lib64/fpc` and `/usr/lib64/lazarus`. Any `.patch` file located in the `patches/` folder should be applied. On linux you'll have to set the write permissions to `/usr/lib64/fpc` and `/usr/lib64/lazarus`.
@ -31,19 +30,8 @@ You're now ready to build Dexed. This can be done in the IDE or using the _lazbu
* in the **project** menu, click *open...* and select the file **dexed.lpi**, which is located in the sub-folder **lazproj**. * in the **project** menu, click *open...* and select the file **dexed.lpi**, which is located in the sub-folder **lazproj**.
* in the menu **Execute** click **Create**. * in the menu **Execute** click **Create**.
After what Dexed should be build. The executable is output to the _bin_ folder. After what Dexed should be build. The executable and the library are output to the _bin_ folder.
The library might have to be copied to a specific path, e.g _/lib64/_ under linux.
## Dastworx
The background tool used by the IDE is a D program.
* [Download](https://dlang.org/download.html#dmd) and setup latest DMD version. Other D compiler are also supported. For example to compile with LDC, set the encironment variable DC: `DC=ldc2`.
* In the repository, browse to the `dastworx` folder.
* Windows: double click `build.bat`
* Linux: `bash ./build.sh`
You can also build it in dexed using the project file _dastworx.dprj_.
## Third party tools ## Third party tools
Additionally you'll have to build [the completion daemon **DCD**](https://github.com/dlang-community/DCD#setup) and the [D linter **Dscanner**](https://github.com/dlang-community/Dscanner#building-and-installing). Additionally you'll have to build [the completion daemon **DCD**](https://github.com/dlang-community/DCD#setup) and the [D linter **Dscanner**](https://github.com/dlang-community/Dscanner#building-and-installing).

View File

@ -4,7 +4,6 @@ header-includes: <script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/4
--- ---
This list displays the symbols declared in the D module that has the focus (imports, classes, variables, etc). This list displays the symbols declared in the D module that has the focus (imports, classes, variables, etc).
The widget is a GUI front-end for one the [_dastworx_](https://gitlab.com/basile.b/dexed/-/tree/master/dastworx) feature.
It can be used to quickly find and go to the declaration of a symbol but also as a basic linter since the syntactic errors are displayed (almost immediately if the option _refresh on change_ is checked). It can be used to quickly find and go to the declaration of a symbol but also as a basic linter since the syntactic errors are displayed (almost immediately if the option _refresh on change_ is checked).

View File

@ -409,52 +409,7 @@
</Target> </Target>
<SearchPaths> <SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/> <IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="..\src;..\etc\terminal"/> <Libraries Value="..\bin"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<IncludeAssertionCode Value="True"/>
<CPPInline Value="False"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<Checks>
<IOChecks Value="True"/>
<RangeChecks Value="True"/>
<OverflowChecks Value="True"/>
<StackChecks Value="True"/>
</Checks>
<Optimizations>
<OptimizationLevel Value="0"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<UseHeaptrc Value="True"/>
</Debugging>
</Linking>
<Other>
<CompilerMessages>
<IgnoredMessages idx5024="True"/>
</CompilerMessages>
<CustomOptions Value="-dDEBUG"/>
<OtherDefines Count="2">
<Define0 Value="RELEASE"/>
<Define1 Value="GTK_REMOVE_CLIPBOARD_NULL"/>
</OtherDefines>
</Other>
</CompilerOptions>
</Item2>
<Item3 Name="LeaksCheck">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="..\bin\dexed"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="..\src;..\etc\terminal"/> <OtherUnitFiles Value="..\src;..\etc\terminal"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths> </SearchPaths>
@ -480,6 +435,60 @@
<UseHeaptrc Value="True"/> <UseHeaptrc Value="True"/>
</Debugging> </Debugging>
<Options> <Options>
<LinkerOptions Value="-L..\bin --verbose"/>
</Options>
</Linking>
<Other>
<CompilerMessages>
<IgnoredMessages idx5024="True"/>
</CompilerMessages>
<CustomOptions Value="-dDEBUG"/>
<OtherDefines Count="2">
<Define0 Value="RELEASE"/>
<Define1 Value="GTK_REMOVE_CLIPBOARD_NULL"/>
</OtherDefines>
<ExecuteBefore>
<Command Value="bash dside.sh DEBUG"/>
</ExecuteBefore>
</Other>
</CompilerOptions>
</Item2>
<Item3 Name="LeaksCheck">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="..\bin\dexed"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<Libraries Value="..\bin"/>
<OtherUnitFiles Value="..\src;..\etc\terminal"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<IncludeAssertionCode Value="True"/>
<CPPInline Value="False"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<Checks>
<IOChecks Value="True"/>
<RangeChecks Value="True"/>
<OverflowChecks Value="True"/>
<StackChecks Value="True"/>
</Checks>
<Optimizations>
<OptimizationLevel Value="0"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<UseHeaptrc Value="True"/>
</Debugging>
<Options>
<LinkerOptions Value="-L..\bin --verbose"/>
<Win32> <Win32>
<GraphicApplication Value="True"/> <GraphicApplication Value="True"/>
</Win32> </Win32>
@ -487,6 +496,9 @@
</Linking> </Linking>
<Other> <Other>
<CustomOptions Value="-dDEBUG"/> <CustomOptions Value="-dDEBUG"/>
<ExecuteBefore>
<Command Value="bash dside.sh"/>
</ExecuteBefore>
</Other> </Other>
</CompilerOptions> </CompilerOptions>
</Item3> </Item3>
@ -495,9 +507,20 @@
<Version Value="2"/> <Version Value="2"/>
</PublishOptions> </PublishOptions>
<RunParams> <RunParams>
<environment>
<UserOverrides Count="1">
<Variable0 Name="LD_LIBRARY_PATH" Value="./"/>
</UserOverrides>
</environment>
<FormatVersion Value="2"/> <FormatVersion Value="2"/>
<Modes Count="1"> <Modes Count="1">
<Mode0 Name="default"/> <Mode0 Name="default">
<environment>
<UserOverrides Count="1">
<Variable0 Name="LD_LIBRARY_PATH" Value="./"/>
</UserOverrides>
</environment>
</Mode0>
</Modes> </Modes>
</RunParams> </RunParams>
<RequiredPackages Count="8"> <RequiredPackages Count="8">
@ -526,7 +549,7 @@
<PackageName Value="LCL"/> <PackageName Value="LCL"/>
</Item8> </Item8>
</RequiredPackages> </RequiredPackages>
<Units Count="61"> <Units Count="60">
<Unit0> <Unit0>
<Filename Value="dexed.lpr"/> <Filename Value="dexed.lpr"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
@ -789,63 +812,59 @@
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit49> </Unit49>
<Unit50> <Unit50>
<Filename Value="..\src\u_dastworx.pas"/> <Filename Value="..\src\u_dbgitf.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit50> </Unit50>
<Unit51> <Unit51>
<Filename Value="..\src\u_dbgitf.pas"/> <Filename Value="..\src\u_ddemangle.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit51> </Unit51>
<Unit52> <Unit52>
<Filename Value="..\src\u_ddemangle.pas"/>
<IsPartOfProject Value="True"/>
</Unit52>
<Unit53>
<Filename Value="..\src\u_compilers.pas"/> <Filename Value="..\src\u_compilers.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<ComponentName Value="CompilersPathsEditor"/> <ComponentName Value="CompilersPathsEditor"/>
<HasResources Value="True"/> <HasResources Value="True"/>
<ResourceBaseClass Value="Form"/> <ResourceBaseClass Value="Form"/>
</Unit53> </Unit52>
<Unit54> <Unit53>
<Filename Value="..\src\u_halstead.pas"/> <Filename Value="..\src\u_halstead.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit54> </Unit53>
<Unit55> <Unit54>
<Filename Value="..\src\u_diff.pas"/> <Filename Value="..\src\u_diff.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<ComponentName Value="DiffViewer"/> <ComponentName Value="DiffViewer"/>
<HasResources Value="True"/> <HasResources Value="True"/>
<ResourceBaseClass Value="Form"/> <ResourceBaseClass Value="Form"/>
</Unit55> </Unit54>
<Unit56> <Unit55>
<Filename Value="..\src\u_profileviewer.pas"/> <Filename Value="..\src\u_profileviewer.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<ComponentName Value="ProfileViewerWidget"/> <ComponentName Value="ProfileViewerWidget"/>
<HasResources Value="True"/> <HasResources Value="True"/>
<ResourceBaseClass Value="Form"/> <ResourceBaseClass Value="Form"/>
</Unit56> </Unit55>
<Unit57> <Unit56>
<Filename Value="..\src\u_semver.pas"/> <Filename Value="..\src\u_semver.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit57> </Unit56>
<Unit58> <Unit57>
<Filename Value="..\src\u_term.pas"/> <Filename Value="..\src\u_term.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<ComponentName Value="TermWidget"/> <ComponentName Value="TermWidget"/>
<HasResources Value="True"/> <HasResources Value="True"/>
<ResourceBaseClass Value="Form"/> <ResourceBaseClass Value="Form"/>
</Unit58> </Unit57>
<Unit59> <Unit58>
<Filename Value="..\src\u_newdubproj.pas"/> <Filename Value="..\src\u_newdubproj.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<ComponentName Value="CeNewDubProject"/> <ComponentName Value="CeNewDubProject"/>
<ResourceBaseClass Value="Form"/> <ResourceBaseClass Value="Form"/>
</Unit59> </Unit58>
<Unit60> <Unit59>
<Filename Value="..\src\u_simpleget.pas"/> <Filename Value="..\src\u_simpleget.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit60> </Unit59>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>
@ -856,6 +875,7 @@
</Target> </Target>
<SearchPaths> <SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/> <IncludeFiles Value="$(ProjOutDir)"/>
<Libraries Value="..\bin"/>
<OtherUnitFiles Value="..\src;..\etc\terminal"/> <OtherUnitFiles Value="..\src;..\etc\terminal"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths> </SearchPaths>
@ -871,6 +891,7 @@
</Debugging> </Debugging>
<LinkSmart Value="True"/> <LinkSmart Value="True"/>
<Options> <Options>
<LinkerOptions Value="-L..\bin --verbose"/>
<Win32> <Win32>
<GraphicApplication Value="True"/> <GraphicApplication Value="True"/>
</Win32> </Win32>
@ -880,13 +901,20 @@
<Verbosity> <Verbosity>
<ShowHints Value="False"/> <ShowHints Value="False"/>
</Verbosity> </Verbosity>
<ConfigFile>
<StopAfterErrCount Value="10"/>
</ConfigFile>
<CompilerMessages> <CompilerMessages>
<IgnoredMessages idx5024="True"/> <IgnoredMessages idx5024="True"/>
</CompilerMessages> </CompilerMessages>
<CustomOptions Value="-dRELEASE"/> <CustomOptions Value="-dRELEASE"/>
<OtherDefines Count="1"> <OtherDefines Count="2">
<Define0 Value="RELEASE"/> <Define0 Value="RELEASE"/>
<Define1 Value="GTK_REMOVE_CLIPBOARD_NULL"/>
</OtherDefines> </OtherDefines>
<ExecuteBefore>
<Command Value="bash dside.sh RELEASE"/>
</ExecuteBefore>
</Other> </Other>
</CompilerOptions> </CompilerOptions>
<Debugging> <Debugging>

View File

@ -7,12 +7,12 @@ uses
cthreads, cthreads,
{$ENDIF}{$ENDIF} {$ENDIF}{$ENDIF}
Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, anchordockpkg, Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, anchordockpkg,
tachartlazaruspkg, u_sharedres, u_observer, u_libman, u_symstring, tachartlazaruspkg, u_sharedres, u_dexed_d, u_observer, u_libman,
u_tools, u_dcd, u_main, u_writableComponent, u_symstring, u_tools, u_dcd, u_main, u_writableComponent,
u_inspectors, u_editoroptions, u_dockoptions, u_shortcutseditor, u_mru, u_inspectors, u_editoroptions, u_dockoptions, u_shortcutseditor, u_mru,
u_processes, u_dialogs, u_dubprojeditor, u_controls, u_dfmt, u_processes, u_dialogs, u_dubprojeditor, u_controls, u_dfmt,
u_lcldragdrop, u_stringrange, u_dlangmaps, u_projgroup, u_projutils, u_lcldragdrop, u_stringrange, u_dlangmaps, u_projgroup, u_projutils,
u_d2synpresets, u_dastworx, u_dbgitf, u_ddemangle, u_dubproject, u_d2synpresets, u_dbgitf, u_ddemangle, u_dubproject,
u_halstead, u_diff, u_profileviewer, u_semver, u_term, u_simpleget; u_halstead, u_diff, u_profileviewer, u_semver, u_term, u_simpleget;
{$R *.res} {$R *.res}

11
lazproj/dside.sh Normal file
View File

@ -0,0 +1,11 @@
cd ../dexed-d
if [ "$1" == "RELEASE" ]; then
dub build --build=release --compiler=ldc2
elif [ "$1" == "DEBUG" ]; then
dub build --build=debug --compiler=ldc2
elif [ "$1" == "" ]; then
dub build --compiler=ldc2
fi
cd ../lazproj

View File

@ -8,9 +8,25 @@ dcd_ver=""
dscanner_ver="" dscanner_ver=""
echo "building dexed release" $ver echo "building dexed release" $ver
# dastworx # libdexed-d shared objects
cd dastworx if [ ! -d "./bin" ]; then
bash build.sh mkdir "./bin"
fi
DEXED_BIN_PATH=$(readlink --canonicalize "./bin")
SEARCH_PATH_LDC=$(find "/" -iname "libdruntime-ldc.a" 2>/dev/null | grep -m 1 "libdruntime")
SEARCH_PATH_LDC=$(dirname $SEARCH_PATH_LDC)
export LIBRARY_PATH="$LIBRARY_PATH":"$SEARCH_PATH_LDC":"$DEXED_BIN_PATH"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$SEARCH_PATH_LDC":"$DEXED_BIN_PATH"
# libdexed-d
cd dexed-d
dub build --build=release --compiler=ldc2
if [ ! -f "../bin/libdexed-d.so" ]; then
echo "this explains linking issues..."
exit 1
fi
cp "../bin/libdexed-d.so" "/lib64/libdexed-d.so"
cp "../bin/libdexed-d.so" "/lib/libdexed-d.so"
cd .. cd ..
# dexed # dexed
@ -30,12 +46,12 @@ else
cd dcd cd dcd
git pull git pull
fi fi
git submodule update --init --recursive
git fetch --tags git fetch --tags
if [ ! -z "$dcd_ver" ]; then if [ ! -z "$dcd_ver" ]; then
git checkout $dcd_ver git checkout $dcd_ver
fi fi
make ldc dub build --build=release --config=client --compiler=$DC
dub build --build=release --config=server --compiler=$DC
echo "...done" echo "...done"
cd .. cd ..
@ -48,12 +64,11 @@ else
cd d-scanner cd d-scanner
git pull git pull
fi fi
git submodule update --init --recursive
git fetch --tags git fetch --tags
if [ ! -z "$dscanner_ver" ]; then if [ ! -z "$dscanner_ver" ]; then
git checkout $dscanner_ver git checkout $dscanner_ver
fi fi
make ldc dub build --build=release --compiler=$DC
echo "...done" echo "...done"
cd .. cd ..
@ -62,7 +77,7 @@ echo "moving files and binaries..."
if [ ! -d setup/nux64 ]; then if [ ! -d setup/nux64 ]; then
mkdir setup/nux64 mkdir setup/nux64
fi fi
mv bin/dastworx setup/nux64/ mv bin/libdexed-d.so setup/nux64/
mv bin/dexed setup/nux64/ mv bin/dexed setup/nux64/
mv dcd/bin/dcd-server setup/nux64/ mv dcd/bin/dcd-server setup/nux64/
mv dcd/bin/dcd-client setup/nux64/ mv dcd/bin/dcd-client setup/nux64/
@ -83,7 +98,11 @@ bash deb.sh
echo "...done" echo "...done"
SETUP_APP_NAME="dexed.$ver.linux64.setup" SETUP_APP_NAME="dexed.$ver.linux64.setup"
echo "building the custom setup program..." echo "building the custom setup program..."
ldmd2 setup.d -O -release -Jnux64 -J./ -of"output/"$SETUP_APP_NAME SETUP_DC=$DC
if [ "$SETUP_DC" = ldc2 ]; then
SETUP_DC=ldmd2
fi
$SETUP_DC setup.d -O -release -Jnux64 -J./ -of"output/"$SETUP_APP_NAME
bash zip-nux64.sh bash zip-nux64.sh
bash setupzip-nux-noarch.sh $SETUP_APP_NAME bash setupzip-nux-noarch.sh $SETUP_APP_NAME
echo "...done" echo "...done"
@ -102,7 +121,7 @@ if [ ! -z "$GITLAB_CI" ]; then
ZP2_NAME="dexed.$ver.linux64.zip" ZP2_NAME="dexed.$ver.linux64.zip"
# read the log # read the log
ldc2 extract_last_changelog_part.d $DC extract_last_changelog_part.d
LOG=$(./extract_last_changelog_part) LOG=$(./extract_last_changelog_part)
LOG=$(echo "$LOG" | sed -z 's/\n/\\n/g' | sed -z 's/\"/\\"/g') LOG=$(echo "$LOG" | sed -z 's/\n/\\n/g' | sed -z 's/\"/\\"/g')

View File

@ -17,16 +17,18 @@ cfgdir=$basdir/DEBIAN
bindir=$basdir/usr/bin bindir=$basdir/usr/bin
pixdir=$basdir/usr/share/pixmaps pixdir=$basdir/usr/share/pixmaps
shcdir=$basdir/usr/share/applications shcdir=$basdir/usr/share/applications
libdir=$basdir/usr/lib64
mkdir -p $basdir mkdir -p $basdir
mkdir -p $cfgdir mkdir -p $cfgdir
mkdir -p $bindir mkdir -p $bindir
mkdir -p $pixdir mkdir -p $pixdir
mkdir -p $shcdir mkdir -p $shcdir
mkdir -p $libdir
cp nux64/dexed $bindir cp nux64/dexed $bindir
cp nux64/dastworx $bindir
cp nux64/dexed.png $pixdir cp nux64/dexed.png $pixdir
cp nux64/libdexed-d.so $libdir
echo "[Desktop Entry] echo "[Desktop Entry]
Categories=Application;IDE;Development; Categories=Application;IDE;Development;

View File

@ -5,12 +5,14 @@ This folder contains the files necessary to manually build dexed and its toolcha
### Building ### Building
- git - git
- Freepascal 3.0.4
- Lazarus 2.0.8
- ldc2 - ldc2
### Releaseing ### Releasing
Same tools as to build plus:
- git
- ldc2
- rpm - rpm
- dpkg - dpkg
- zip - zip

View File

@ -37,15 +37,17 @@ buildroot=$HOME/rpmbuild/BUILDROOT/$name_and_ver
bindir=$buildroot/usr/bin bindir=$buildroot/usr/bin
pixdir=$buildroot/usr/share/pixmaps pixdir=$buildroot/usr/share/pixmaps
shcdir=$buildroot/usr/share/applications shcdir=$buildroot/usr/share/applications
libdir=$buildroot/usr/lib64
mkdir -p $buildroot mkdir -p $buildroot
mkdir -p $bindir mkdir -p $bindir
mkdir -p $pixdir mkdir -p $pixdir
mkdir -p $shcdir mkdir -p $shcdir
mkdir -p $libdir
cp nux64/dexed $bindir cp nux64/dexed $bindir
cp nux64/dastworx $bindir
cp nux64/dexed.png $pixdir cp nux64/dexed.png $pixdir
cp nux64/libdexed-d.so $libdir
echo "[Desktop Entry] echo "[Desktop Entry]
Categories=Application;IDE;Development; Categories=Application;IDE;Development;
@ -71,8 +73,8 @@ Requires: gtk2, glibc, cairo, libX11, vte
Dexed is an IDE for the DMD D compiler. Dexed is an IDE for the DMD D compiler.
%files %files
/usr/bin/dastworx
/usr/bin/dexed /usr/bin/dexed
/usr/lib64/libdexed-d.so
/usr/share/applications/dexed.desktop /usr/share/applications/dexed.desktop
/usr/share/pixmaps/dexed.png /usr/share/pixmaps/dexed.png

View File

@ -11,9 +11,14 @@ version(X86) version(Windows)version = win32;
version(Windows) version(Windows)
{ {
enum exeExt = ".exe"; enum exeExt = ".exe";
enum libExt = ".dll";
pragma(lib, "ole32.lib"); pragma(lib, "ole32.lib");
} }
else enum exeExt = ""; else
{
enum exeExt = "";
enum libExt = ".so";
}
alias ImpType = immutable ubyte[]; alias ImpType = immutable ubyte[];
alias ResType = immutable Resource; alias ResType = immutable Resource;
@ -35,8 +40,8 @@ struct Resource
immutable Resource[] ceResources = immutable Resource[] ceResources =
[ [
Resource(cast(ImpType) import("dexed" ~ exeExt), "dexed" ~ exeExt, Kind.exe), Resource(cast(ImpType) import("dexed" ~ exeExt), "dexed" ~ exeExt, Kind.exe),
Resource(cast(ImpType) import("dastworx" ~ exeExt), "dastworx" ~ exeExt, Kind.exe), Resource(cast(ImpType) import("libdexed-d" ~ libExt), "libdexed-d" ~ libExt, Kind.exe),
Resource(cast(ImpType) import("dexed.ico"), "dexed.ico", Kind.dat), Resource(cast(ImpType) import("dexed.ico"), "dexed.ico", Kind.dat),
Resource(cast(ImpType) import("dexed.png"), "dexed.png", Kind.dat), Resource(cast(ImpType) import("dexed.png"), "dexed.png", Kind.dat),
Resource(cast(ImpType) import("dexed.license.txt"), "dexed.license.txt", Kind.doc) Resource(cast(ImpType) import("dexed.license.txt"), "dexed.license.txt", Kind.doc)
@ -54,6 +59,7 @@ immutable Resource[] oldResources =
[ [
Resource(cast(ImpType) [], "cesyms" ~ exeExt, Kind.exe), Resource(cast(ImpType) [], "cesyms" ~ exeExt, Kind.exe),
Resource(cast(ImpType) [], "cetodo" ~ exeExt, Kind.exe), Resource(cast(ImpType) [], "cetodo" ~ exeExt, Kind.exe),
Resource(cast(ImpType) [], "dastworx" ~ exeExt, Kind.exe),
]; ];
version(Windows) version(Windows)
@ -428,7 +434,7 @@ void postInstall()
f.writeln("[Desktop Entry]"); f.writeln("[Desktop Entry]");
f.writeln("Name=dexed"); f.writeln("Name=dexed");
f.writeln("Path=" ~ exePath); f.writeln("Path=" ~ exePath);
f.writeln("Exec=" ~ exePath ~ "dexed %f"); f.writeln("Exec=env LD_LIBRARY_PATH="~ exePath ~ " "~ exePath ~ "dexed %f");
f.writeln("Icon=" ~ datPath ~ "dexed.png"); f.writeln("Icon=" ~ datPath ~ "dexed.png");
f.writeln("Type=Application"); f.writeln("Type=Application");
f.writeln("Categories=Application;IDE;Development;"); f.writeln("Categories=Application;IDE;Development;");

View File

@ -6,7 +6,7 @@ cp * $fld/
zip -9 \ zip -9 \
../output/dexed.${ver:1:100}.linux32.zip \ ../output/dexed.${ver:1:100}.linux32.zip \
$fld/dcd.license.txt $fld/dexed.license.txt \ $fld/dcd.license.txt $fld/dexed.license.txt \
$fld/dexed $fld/dastworx \ $fld/dexed libdexed-d.so \
$fld/dexed.ico $fld/dexed.png \ $fld/dexed.ico $fld/dexed.png \
$fld/dcd-server $fld/dcd-client $fld/dscanner $fld/dcd-server $fld/dcd-client $fld/dscanner
rm -rf dexed-x86 rm -rf dexed-x86

View File

@ -6,7 +6,7 @@ cp * $fld/
zip -9 \ zip -9 \
../output/dexed.${ver:1:100}.linux64.zip \ ../output/dexed.${ver:1:100}.linux64.zip \
$fld/dcd.license.txt $fld/dexed.license.txt \ $fld/dcd.license.txt $fld/dexed.license.txt \
$fld/dexed $fld/dastworx \ $fld/dexed $fld/libdexed-d.so \
$fld/dexed.ico $fld/dexed.png \ $fld/dexed.ico $fld/dexed.png \
$fld/dcd-server $fld/dcd-client $fld/dscanner $fld/dcd-server $fld/dcd-client $fld/dscanner
rm -rf dexed-x86_64 rm -rf dexed-x86_64

View File

@ -5,7 +5,7 @@ cd win32
7z a -tzip -mx9^ 7z a -tzip -mx9^
..\output\dexed.%ver%.win32.zip^ ..\output\dexed.%ver%.win32.zip^
dcd.license.txt dexed.license.txt^ dcd.license.txt dexed.license.txt^
dexed.exe dastworx.exe^ dexed.exe dexed-d.dll^
dexed.ico dexed.png^ dexed.ico dexed.png^
dcd-server.exe dcd-client.exe dscanner.exe^ dcd-server.exe dcd-client.exe dscanner.exe^
libeay32.dll ssleay32.dll libeay32.dll ssleay32.dll

View File

@ -5,7 +5,7 @@ cd win64
7z a -tzip -mx9^ 7z a -tzip -mx9^
..\output\dexed.%ver%.win64.zip^ ..\output\dexed.%ver%.win64.zip^
dcd.license.txt dexed.license.txt^ dcd.license.txt dexed.license.txt^
dexed.exe dastworx.exe^ dexed.exe dexed-d.dll^
dexed.ico dexed.png^ dexed.ico dexed.png^
dcd-server.exe dcd-client.exe dscanner.exe^ dcd-server.exe dcd-client.exe dscanner.exe^
libeay32.dll ssleay32.dll libeay32.dll ssleay32.dll

View File

@ -13,7 +13,7 @@ uses
{$ENDIF} {$ENDIF}
Classes, SysUtils, process, strUtils, RegExpr, Classes, SysUtils, process, strUtils, RegExpr,
u_common, u_writableComponent, u_dmdwrap, u_observer, u_interfaces, u_common, u_writableComponent, u_dmdwrap, u_observer, u_interfaces,
u_processes, LazFileUtils, u_dastworx; u_processes, LazFileUtils, u_dexed_d;
type type

View File

@ -1,198 +0,0 @@
unit u_dastworx;
{$I u_defines.inc}
interface
uses
Classes, SysUtils, process, jsonscanner, fpjson, jsonparser,
u_common;
(**
* Gets the module name and the imports of the source code located in
* "source". The first line of "import" contains the module name, double quoted.
* Each following line contain an import.
*)
procedure getModuleImports(source, imports: TStrings);
(**
* Gets the module names and the imports of the sources in "files".
* source. Each line in "import" that contains double quoted text indicates
* that a new group of import starts.
*)
procedure getModulesImports(files: string; results: TStrings);
procedure getHalsteadMetrics(source: TStrings; out jsn: TJSONObject);
procedure getDdocTemplate(source, res: TStrings;caretLine: integer; plusComment: boolean);
implementation
var
toolname: string;
function getToolName: string;
begin
if toolname = '' then
toolname := exeFullName('dastworx' + exeExt);
exit(toolname);
end;
procedure getModuleImports(source, imports: TStrings);
var
str: string;
prc: TProcess;
begin
str := getToolName;
if str.isEmpty then
exit;
prc := TProcess.Create(nil);
try
prc.Executable := str;
prc.Parameters.Add('-i');
prc.Options := [poUsePipes{$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
prc.ShowWindow := swoHIDE;
prc.Execute;
str := source.Text;
prc.Input.Write(str[1], str.length);
prc.CloseInput;
processOutputToStrings(prc, imports);
while prc.Running do ;
{$IFDEF DEBUG}
tryRaiseFromStdErr(prc);
{$ENDIF}
finally
prc.free;
end;
end;
procedure getModulesImports(files: string; results: TStrings);
var
str: string;
prc: TProcess;
{$ifdef WINDOWS}
cdr: string = '';
itm: string;
spl: TStringList;
i: integer;
{$endif}
begin
str := getToolName;
if str.isEmpty then
exit;
{$ifdef WINDOWS}
if files.length > 32760{not 8 : "-f -i" length} then
begin
spl := TStringList.Create;
try
spl.LineBreak := ';';
spl.AddText(files);
cdr := commonFolder(spl);
if not cdr.dirExists then
begin
dlgOkError('Impossible to find the common directory in the list to analyze the imports: ' + shortenPath(files, 200));
exit;
end;
for i:= 0 to spl.count-1 do
begin
itm := spl.strings[i];
spl.strings[i] := itm[cdr.length + 2 .. itm.length];
end;
files := spl.strictText;
if files.length > 32760 then
begin
dlgOkError('Too much files in the list to analyze the imports: ' + shortenPath(files, 200));
exit;
end;
finally
spl.Free;
end;
end;
{$endif}
prc := TProcess.Create(nil);
try
prc.Executable := str;
prc.Parameters.Add('-f' + files);
prc.Parameters.Add('-i');
prc.Options := [poUsePipes {$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
prc.ShowWindow := swoHIDE;
{$ifdef WINDOWS}
if cdr.isNotEmpty then
prc.CurrentDirectory := cdr;
{$endif}
prc.Execute;
prc.CloseInput;
processOutputToStrings(prc, results);
while prc.Running do ;
{$IFDEF DEBUG}
tryRaiseFromStdErr(prc);
{$ENDIF}
finally
prc.free;
end;
end;
procedure getHalsteadMetrics(source: TStrings; out jsn: TJSONObject);
var
prc: TProcess;
prs: TJSONParser;
jps: TJSONData;
str: string;
lst: TStringList;
begin
str := getToolName;
if str.isEmpty then
exit;
prc := TProcess.Create(nil);
lst := TStringList.create;
try
prc.Executable := str;
prc.Parameters.Add('-H');
prc.Options := [poUsePipes {$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
prc.ShowWindow := swoHIDE;
prc.Execute;
str := source.Text;
prc.Input.Write(str[1], str.length);
prc.CloseInput;
processOutputToStrings(prc, lst);
prs := TJSONParser.Create(lst.Text, [joIgnoreTrailingComma, joUTF8]);
jps := prs.Parse;
if jps.isNotNil and (jps.JSONType = jtObject) then
jsn := TJSONObject(jps.Clone);
jps.Free;
while prc.Running do ;
finally
prs.Free;
prc.Free;
lst.free;
end;
end;
procedure getDdocTemplate(source, res: TStrings; caretLine: integer; plusComment: boolean);
var
prc: TProcess;
str: string;
begin
str := getToolName;
if str.isEmpty then
exit;
prc := TProcess.Create(nil);
try
prc.Executable := str;
prc.Parameters.Add('-l' + caretLine.ToString);
if plusComment then
prc.Parameters.Add('-o');
prc.Parameters.Add('-K');
prc.Options := [poUsePipes {$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
prc.ShowWindow := swoHIDE;
prc.Execute;
str := source.Text;
prc.Input.Write(str[1], str.length);
prc.CloseInput;
processOutputToStrings(prc, res);
finally
prc.Free;
end;
end;
end.

View File

@ -6,23 +6,7 @@ interface
uses uses
Classes, SysUtils, process, forms, Classes, SysUtils, process, forms,
u_processes, u_common, u_stringrange; u_dexed_d;
type
TDDemangler = class
strict private
fActive: boolean;
fProc: TDexedProcess;
fList, fOut: TStringList;
procedure procTerminate(sender: TObject);
public
constructor create;
destructor destroy; override;
procedure demangle(const value: string);
property output: TStringList read fList;
property active: boolean read fActive;
end;
// demangle a D name // demangle a D name
function demangle(const value: string): string; function demangle(const value: string): string;
@ -31,96 +15,33 @@ procedure demangle(values, output: TStrings);
implementation implementation
var
demangler: TDDemangler;
constructor TDDemangler.create;
begin
fList := TStringList.Create;
fOut := TStringList.Create;
fProc := TDexedProcess.create(nil);
fProc.Options:= [poUsePipes];
fProc.OnTerminate:=@procTerminate;
fProc.ShowWindow:= swoHIDE;
fProc.Executable := exeFullName('ddemangle' + exeExt);
{$IFDEF POSIX}
// Arch Linux users can have the tool setup w/o DMD
if fProc.Executable.isEmpty then
fProc.Executable := exeFullName('dtools-ddemangle');
{$ENDIF}
if fProc.Executable.isNotEmpty and
fProc.Executable.fileExists then
begin
fProc.execute;
fActive := true;
end;
fActive := fProc.Running;
end;
destructor TDDemangler.destroy;
begin
if fProc.Running then
fProc.Terminate(0);
fProc.Free;
fOut.Free;
fList.Free;
inherited;
end;
procedure TDDemangler.procTerminate(sender: TObject);
begin
fActive := false;
end;
procedure TDDemangler.demangle(const value: string);
var
nb: integer;
begin
if value.isNotEmpty then
fProc.Input.Write(value[1], value.length);
fProc.Input.WriteByte(10);
while true do
begin
nb := fProc.NumBytesAvailable;
if nb <> 0 then
break;
end;
fProc.fillOutputStack;
fProc.getFullLines(fOut);
if fOut.Count <> 0 then
fList.Add(fOut[0]);
end;
function demangle(const value: string): string; function demangle(const value: string): string;
var
s: pchar;
begin begin
if demangler.active and (pos('_D', value) > 0) then if (value.Length > 0) and (pos('_D', value) > 0) then
begin begin
demangler.output.Clear; s := pchar(value);
demangler.demangle(value); // note, assign to result has for effect to alloc a FPC string
if demangler.output.Count <> 0 then // (by implicit convertion) so the D memory is not used.
result := demangler.output[0] result := ddemangle(s);
else
result := value;
end end
else result := value; else
result := value;
end; end;
procedure demangle(values, output: TStrings); procedure demangle(values, output: TStrings);
var var
i: integer;
value: string; value: string;
begin begin
if demangler.active then for i := 0 to values.Count-1 do
begin begin
for value in values do value := values[i];
demangler.demangle(value); if pos('_D', value) > 0 then
output.AddStrings(demangler.output); value := demangle(PChar(value));
demangler.output.Clear; output.AddStrings(value);
end end;
else output.AddStrings(values);
end; end;
initialization
demangler := TDDemangler.create;
finalization
demangler.Free;
end. end.

121
src/u_dexed_d.pas Normal file
View File

@ -0,0 +1,121 @@
// ObjFPC counterpart for the libdexed-d library.
unit u_dexed_d;
{$I u_defines.inc}
interface
uses
Classes, SysUtils;
type
(**
* Provides a view on D builtin dynamic arrays.
*
* Note that it is only partially read-only.
* The content should never be modified as it's likely to be
* allocated in D GC memory pool.
*)
generic TDArray<T> = record
type
PT = ^T;
strict private
fLength: PtrUInt;
fPtr: PT;
function getItem(index: PtrUint): T;
public
// The count of elements
property length: PtrUInt read fLength;
// Pointer to the first element.
property ptr: PT read fPtr;
// overload "[]"
property item[index: PtrUint]: T read getItem; default;
end;
// Give a view on D `char[]`
TDString = specialize TDArray<char> ;
// Give a view on D `char[][]`
TDStrings = specialize TDArray<TDString>;
// Necessary to start the GC, run the static constructors, etc
procedure rt_init(); cdecl; external 'libdexed-d';
// Cleanup
procedure rt_term(); cdecl; external 'libdexed-d';
// Demangle a line possibly containing a D mangled name.
function ddemangle(const text: PChar): PChar; cdecl; external 'libdexed-d';
// Detects wether the source code for the module `src` contains the main() function.
function hasMainFun(const src: PChar): Boolean; cdecl; external 'libdexed-d';
// Returns the DDOC template for the declaration location at `caretLine` in the source code `src`.
function ddocTemplate(const src: PChar; caretLine: integer; plusComment: Boolean): PChar; cdecl; external 'libdexed-d';
// List the imports of the module represented by `src`.
function listImports(const src: PChar): TDStrings; cdecl; external 'libdexed-d';
// List the imports of the modules located in `files` (list of files joined with pathseparaotr and null terminated)
function listFilesImports(const files: PChar): TDStrings; cdecl; external 'libdexed-d';
// Get the variables necessary to compute the Halstead metrics of the functions within a module.
function halsteadMetrics(const src: PChar): PChar; cdecl; external 'libdexed-d';
// Get the list of declarations within a module.
function listSymbols(const src: PChar; deep: Boolean): PChar; cdecl; external 'libdexed-d';
// Get the TODO items located in `files` (list of files joined with pathseparaotr and null terminated)
function todoItems(joinedFiles: PChar): PChar; cdecl; external 'libdexed-d';
(**
* Gets the module name and the imports of the source code located in
* "source". The first line of "import" contains the module name, double quoted.
* Each following line contain an import.
*)
procedure getModuleImports(source, imports: TStrings);
(**
* Gets the module names and the imports of the sources in "files".
* source. Each line in "import" that contains double quoted text indicates
* that a new group of import starts.
*)
procedure getModulesImports(files: string; results: TStrings);
implementation
function TDArray.getItem(index: PtrUint): T;
begin
result := (fPtr + index)^;
end;
procedure getModuleImports(source, imports: TStrings);
var
i: TDStrings;
e: TDstring;
j: integer;
s: string;
begin
i := listImports(PChar(source.Text));
for j := 0 to i.length-1 do
begin
e := i[j];
s := e.ptr[0 .. e.length-1];
imports.Add(s);
end;
end;
procedure getModulesImports(files: string; results: TStrings);
var
i: TDStrings;
e: TDstring;
j: integer;
s: string;
begin
i := listFilesImports(PChar(files));
for j := 0 to i.length-1 do
begin
e := i[j];
s := e.ptr[0 .. e.length-1];
results.Add(s);
end;
end;
initialization
rt_init();
finalization
rt_term();
end.

View File

@ -5,8 +5,8 @@ unit u_halstead;
interface interface
uses uses
Classes, SysUtils, fpjson, math, Classes, SysUtils, fpjson, math, jsonscanner, jsonparser,
u_common, u_observer, u_interfaces, u_dastworx, u_writableComponent, u_common, u_observer, u_interfaces, u_dexed_d, u_writableComponent,
u_synmemo; u_synmemo;
type type
@ -65,6 +65,24 @@ begin
result := fMetrics; result := fMetrics;
end; end;
procedure getHalsteadMetrics(source: TStrings; out jsn: TJSONObject);
var
prs: TJSONParser;
jps: TJSONData;
str: string;
begin
str := halsteadMetrics(PChar(source.Text));
prs := TJSONParser.Create(str, [joIgnoreTrailingComma, joUTF8]);
try
jps := prs.Parse();
if jps.isNotNil and (jps.JSONType = jtObject) then
jsn := TJSONObject(jps.Clone);
jps.Free;
finally
prs.Free;
end;
end;
constructor THalsteadMetricsBase.create(aOwner: TComponent); constructor THalsteadMetricsBase.create(aOwner: TComponent);
begin begin
inherited; inherited;

View File

@ -7,7 +7,7 @@ interface
uses uses
Classes, SysUtils, FileUtil, u_common, u_writableComponent, LazFileUtils, Classes, SysUtils, FileUtil, u_common, u_writableComponent, LazFileUtils,
ghashmap, ghashset, ghashmap, ghashset,
u_dcd, u_projutils, u_interfaces, u_dlang, u_dastworx, u_dcd, u_projutils, u_interfaces, u_dlang, u_dexed_d,
u_compilers; u_compilers;
type type

View File

@ -15,7 +15,7 @@ uses
u_search, u_miniexplorer, u_libman, u_libmaneditor, u_todolist, u_observer, u_search, u_miniexplorer, u_libman, u_libmaneditor, u_todolist, u_observer,
u_toolseditor, u_procinput, u_optionseditor, u_symlist, u_mru, u_processes, u_toolseditor, u_procinput, u_optionseditor, u_symlist, u_mru, u_processes,
u_infos, u_dubproject, u_dialogs, u_dubprojeditor,{$IFDEF UNIX} u_gdb,{$ENDIF} u_infos, u_dubproject, u_dialogs, u_dubprojeditor,{$IFDEF UNIX} u_gdb,{$ENDIF}
u_dfmt, u_lcldragdrop, u_projgroup, u_projutils, u_stringrange, u_dastworx, u_dfmt, u_lcldragdrop, u_projgroup, u_projutils, u_stringrange,
u_halstead, u_profileviewer, u_semver, u_dsgncontrols, u_term, u_newdubproj; u_halstead, u_profileviewer, u_semver, u_dsgncontrols, u_term, u_newdubproj;
type type

View File

@ -8,7 +8,7 @@ uses
Classes, SysUtils, TreeFilterEdit, Forms, Controls, Graphics, ExtCtrls, Menus, Classes, SysUtils, TreeFilterEdit, Forms, Controls, Graphics, ExtCtrls, Menus,
ComCtrls, u_widget, jsonparser, process, actnlist, Buttons, Clipbrd, LCLProc, ComCtrls, u_widget, jsonparser, process, actnlist, Buttons, Clipbrd, LCLProc,
u_common, u_observer, u_synmemo, u_interfaces, u_writableComponent, u_common, u_observer, u_synmemo, u_interfaces, u_writableComponent,
u_processes, u_sharedres, u_dsgncontrols; u_processes, u_sharedres, u_dsgncontrols, u_dexed_d;
type type
@ -70,7 +70,7 @@ type
public public
constructor create(aOwner: TCOmponent); override; constructor create(aOwner: TCOmponent); override;
destructor destroy; override; destructor destroy; override;
procedure LoadFromTool(str: TStream); procedure LoadFromString(const s: string);
end; end;
TSymbolListOptions = class(TWritableLfmTextComponent) TSymbolListOptions = class(TWritableLfmTextComponent)
@ -122,7 +122,6 @@ type
fOptions: TSymbolListOptions; fOptions: TSymbolListOptions;
fSyms: TSymbolList; fSyms: TSymbolList;
fMsgs: IMessagesDisplay; fMsgs: IMessagesDisplay;
fToolProc: TDexedProcess;
fActCopyIdent: TAction; fActCopyIdent: TAction;
fActRefresh: TAction; fActRefresh: TAction;
fActRefreshOnChange: TAction; fActRefreshOnChange: TAction;
@ -154,7 +153,6 @@ type
procedure checkIfHasToolExe; procedure checkIfHasToolExe;
procedure callToolProc; procedure callToolProc;
procedure toolTerminated(sender: TObject);
procedure docNew(document: TDexedMemo); procedure docNew(document: TDexedMemo);
procedure docClosing(document: TDexedMemo); procedure docClosing(document: TDexedMemo);
@ -236,15 +234,18 @@ begin
fSymbols.Assign(value); fSymbols.Assign(value);
end; end;
procedure TSymbolList.LoadFromTool(str: TStream); procedure TSymbolList.LoadFromString(const s: string);
var var
txt: TmemoryStream;
bin: TMemoryStream; bin: TMemoryStream;
begin begin
txt := TMemoryStream.Create;
bin := TMemoryStream.Create; bin := TMemoryStream.Create;
try try
str.Position:=0; txt.Write(s[1], s.length);
txt.Position:=0;
try try
ObjectTextToBinary(str, bin); ObjectTextToBinary(txt, bin);
except except
exit; exit;
end; end;
@ -252,6 +253,7 @@ begin
bin.ReadComponent(self); bin.ReadComponent(self);
finally finally
bin.Free; bin.Free;
txt.Free;
end; end;
end; end;
{$ENDREGION} {$ENDREGION}
@ -449,13 +451,9 @@ end;
destructor TSymbolListWidget.destroy; destructor TSymbolListWidget.destroy;
begin begin
EntitiesConnector.removeObserver(self); EntitiesConnector.removeObserver(self);
killProcess(fToolProc);
fSyms.Free; fSyms.Free;
fOptions.saveToFile(getDocPath + OptsFname); fOptions.saveToFile(getDocPath + OptsFname);
fOptions.Free; fOptions.Free;
inherited; inherited;
end; end;
@ -573,8 +571,6 @@ procedure TSymbolListWidget.docClosing(document: TDexedMemo);
begin begin
if fDoc <> document then if fDoc <> document then
exit; exit;
if fToolProc.Running then
fToolProc.Terminate(0);
fDoc := nil; fDoc := nil;
clearTree; clearTree;
updateVisibleCat; updateVisibleCat;
@ -745,36 +741,6 @@ begin
end; end;
procedure TSymbolListWidget.callToolProc; procedure TSymbolListWidget.callToolProc;
var
str: string;
begin
if not fHasToolExe or fDoc.isNil then
exit;
if (fDoc.Lines.Count = 0) or not fDoc.isDSource then
begin
clearTree;
updateVisibleCat;
exit;
end;
killProcess(fToolProc);
fToolProc := TDexedProcess.Create(nil);
fToolProc.ShowWindow := swoHIDE;
fToolProc.Options := [poUsePipes];
fToolProc.Executable := fToolExeName;
fToolProc.OnTerminate := @toolTerminated;
fToolProc.CurrentDirectory := Application.ExeName.extractFileDir;
if fDeep then
fToolProc.Parameters.Add('-o');
fToolProc.Parameters.Add('-s');
fToolProc.Execute;
str := fDoc.Text;
fToolProc.Input.Write(str[1], str.length);
fToolProc.CloseInput;
end;
procedure TSymbolListWidget.toolTerminated(sender: TObject);
function getCatNode(node: TTreeNode; stype: TSymbolType ): TTreeNode; function getCatNode(node: TTreeNode; stype: TSymbolType ): TTreeNode;
function newCat(const aCat: string): TTreeNode; function newCat(const aCat: string): TTreeNode;
@ -856,24 +822,29 @@ procedure TSymbolListWidget.toolTerminated(sender: TObject);
end; end;
var var
s: string;
i: Integer; i: Integer;
f: string; f: string;
n: TTreeNode; n: TTreeNode;
begin begin
if ndAlias.isNil then
exit;
clearTree;
updateVisibleCat;
if fDoc.isNil then if fDoc.isNil then
exit; exit;
fToolProc.OnTerminate := nil; if (fDoc.Lines.Count = 0) or not fDoc.isDSource then
fToolProc.OnReadData := nil; begin
fToolProc.StdoutEx.Position:=0; clearTree;
if fToolProc.StdoutEx.Size = 0 then updateVisibleCat;
exit; exit;
fSyms.LoadFromTool(fToolProc.StdoutEx); end;
s := fDoc.Lines.Text;
s := listSymbols(PChar(s), fDeep);
if s.isEmpty or ndAlias.isNil then
exit;
clearTree;
updateVisibleCat;
fSyms.LoadFromString(s);
f := TreeFilterEdit1.Filter; f := TreeFilterEdit1.Filter;
TreeFilterEdit1.Text := ''; TreeFilterEdit1.Text := '';
tree.BeginUpdate; tree.BeginUpdate;

View File

@ -12,7 +12,7 @@ uses
md5, Spin, LCLIntf, LazFileUtils, LMessages, SynHighlighterCpp, math, md5, Spin, LCLIntf, LazFileUtils, LMessages, SynHighlighterCpp, math,
//SynEditMarkupFoldColoring, //SynEditMarkupFoldColoring,
Clipbrd, fpjson, jsonparser, LazUTF8, LazUTF8Classes, Buttons, StdCtrls, Clipbrd, fpjson, jsonparser, LazUTF8, LazUTF8Classes, Buttons, StdCtrls,
u_common, u_writableComponent, u_d2syn, u_txtsyn, u_dialogs, u_dastworx, u_common, u_writableComponent, u_d2syn, u_txtsyn, u_dialogs,
u_sharedres, u_dlang, u_stringrange, u_dbgitf, u_observer, u_diff, u_sharedres, u_dlang, u_stringrange, u_dbgitf, u_observer, u_diff,
u_processes; u_processes;
@ -482,7 +482,7 @@ var
implementation implementation
uses uses
u_interfaces, u_dcd, SynEditHighlighterFoldBase, u_lcldragdrop; u_interfaces, u_dcd, SynEditHighlighterFoldBase, u_lcldragdrop, u_dexed_d;
const const
DcdCompletionKindStrings: array[TDCDCompletionKind] of string = ( DcdCompletionKindStrings: array[TDCDCompletionKind] of string = (
@ -2402,30 +2402,8 @@ begin
end; end;
function TDexedMemo.implementMain: THasMain; function TDexedMemo.implementMain: THasMain;
var
res: char = '0';
prc: TProcess;
src: string;
begin begin
if fDastWorxExename.length = 0 then case hasMainFun(PChar(self.Text)) of
exit(mainDefaultBehavior);
src := Lines.Text;
prc := TProcess.Create(nil);
try
prc.Executable:= fDastWorxExename;
prc.Parameters.Add('-m');
prc.Options := [poUsePipes{$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
prc.ShowWindow := swoHIDE;
prc.Execute;
prc.Input.Write(src[1], src.length);
prc.CloseInput;
prc.Output.Read(res, 1);
while prc.Running do
sleep(1);
finally
prc.Free;
end;
case res = '1' of
false:result := mainNo; false:result := mainNo;
true: result := mainYes; true: result := mainYes;
end; end;
@ -2629,7 +2607,7 @@ var
begin begin
d := TStringList.Create; d := TStringList.Create;
try try
getDdocTemplate(lines, d, CaretY, fInsertPlusDdoc); d.Text := ddocTemplate(PChar(lines.Text), caretY, fInsertPlusDdoc);
if d.Text.isNotEmpty then if d.Text.isNotEmpty then
begin begin
BeginUndoBlock; BeginUndoBlock;

View File

@ -8,7 +8,7 @@ uses
Classes, SysUtils, FileUtil, ListFilterEdit, Forms, Controls, Classes, SysUtils, FileUtil, ListFilterEdit, Forms, Controls,
strutils, Graphics, Dialogs, ExtCtrls, Menus, Buttons, ComCtrls, strutils, Graphics, Dialogs, ExtCtrls, Menus, Buttons, ComCtrls,
u_widget, process, u_common, u_interfaces, u_synmemo, u_processes, u_widget, process, u_common, u_interfaces, u_synmemo, u_processes,
u_writableComponent, u_observer, u_sharedres, u_writableComponent, u_observer, u_sharedres, u_dexed_d,
u_dsgncontrols; u_dsgncontrols;
type type
@ -90,7 +90,6 @@ type
fColumns: TTodoColumns; fColumns: TTodoColumns;
fProj: ICommonProject; fProj: ICommonProject;
fDoc: TDexedMemo; fDoc: TDexedMemo;
fToolProc: TDexedProcess;
fTodos: TTodoItems; fTodos: TTodoItems;
fMsgs: IMessagesDisplay; fMsgs: IMessagesDisplay;
fOptions: TTodoOptions; fOptions: TTodoOptions;
@ -114,10 +113,7 @@ type
function optionedOptionsModified: boolean; function optionedOptionsModified: boolean;
// TODOlist things // TODOlist things
function getContext: TTodoContext; function getContext: TTodoContext;
procedure killToolProcess;
procedure callToolProcess; procedure callToolProcess;
procedure toolTerminated(Sender: TObject);
procedure procOutputDbg(Sender: TObject);
procedure clearTodoList; procedure clearTodoList;
procedure fillTodoList; procedure fillTodoList;
procedure lstItemsColumnClick(Sender: TObject; Column: TListColumn); procedure lstItemsColumnClick(Sender: TObject; Column: TListColumn);
@ -243,7 +239,6 @@ end;
destructor TTodoListWidget.Destroy; destructor TTodoListWidget.Destroy;
begin begin
fOptions.saveToFile(getDocPath + OptFname); fOptions.saveToFile(getDocPath + OptFname);
killToolProcess;
inherited; inherited;
end; end;
@ -348,7 +343,6 @@ begin
fDoc := nil; fDoc := nil;
if Visible and fAutoRefresh then if Visible and fAutoRefresh then
clearTodoList; clearTodoList;
killToolProcess();
end; end;
{$ENDREGION} {$ENDREGION}
@ -407,27 +401,15 @@ begin
exit(tcFile); exit(tcFile);
end; end;
procedure TTodoListWidget.killToolProcess;
begin
if fToolProc.isNil then
exit;
fToolProc.Terminate(0);
fToolProc.Free;
fToolProc := nil;
end;
procedure TTodoListWidget.callToolProcess; procedure TTodoListWidget.callToolProcess;
var var
ctxt: TTodoContext; ctxt: TTodoContext;
i,j: integer; i,j: integer;
nme: string; nme: string;
str: string = ''; str: string = '';
txt: TMemoryStream;
begin begin
clearTodoList; clearTodoList;
if not exeInSysPath(ToolExeName) then
exit;
killToolProcess;
ctxt := getContext; ctxt := getContext;
case ctxt of case ctxt of
@ -438,12 +420,6 @@ begin
exit; exit;
end; end;
fToolProc := TDexedProcess.Create(nil);
fToolProc.Executable := exeFullName(ToolExeName);
fToolProc.Options := [poUsePipes];
fToolProc.ShowWindow := swoHIDE;
fToolProc.CurrentDirectory := Application.ExeName.extractFileDir;
fToolProc.OnTerminate := @toolTerminated;
// files passed to the tool argument // files passed to the tool argument
if (ctxt = tcProject) then if (ctxt = tcProject) then
begin begin
@ -460,46 +436,19 @@ begin
end; end;
end end
else str := fDoc.fileName; else str := fDoc.fileName;
fToolProc.Parameters.Add('-f' + str);
fToolProc.Parameters.Add('-t');
fToolProc.Execute; str := todoItems(PChar(str));
fToolProc.CloseInput; if str.length < 10 then
end;
procedure TTodoListWidget.procOutputDbg(Sender: TObject);
var
str: TStringList;
msg: string;
ctxt: TTodoContext;
begin
getMessageDisplay(fMsgs);
str := TStringList.Create;
try
processOutputToStrings(fToolProc, str);
ctxt := getContext;
for msg in str do
case ctxt of
tcNone: fMsgs.message(msg, nil, amcMisc, amkAuto);
tcFile: fMsgs.message(msg, fDoc, amcEdit, amkAuto);
tcProject: fMsgs.message(msg, fProj, amcProj, amkAuto);
end;
finally
str.Free;
end;
end;
procedure TTodoListWidget.toolTerminated(Sender: TObject);
begin
fToolProc.StdoutEx.Position := 0;
try
fTodos.loadFromTxtStream(fToolProc.StdoutEx);
except
fToolProc.OnTerminate := nil;
exit; exit;
txt := TMemoryStream.create;
try
txt.Write(str[1], str.length);
txt.Position:=0;
fTodos.loadFromTxtStream(txt);
fillTodoList;
finally
txt.free;
end; end;
fillTodoList;
fToolProc.OnTerminate := nil;
end; end;
procedure TTodoListWidget.clearTodoList; procedure TTodoListWidget.clearTodoList;