custom tools, removed chainAfter/Before and added more powerful chaining system.

- it allows to redirected output stream to next chain item input stream.
- previous cahin are reloaded once then never saved again.
This commit is contained in:
Basile Burg 2015-12-07 01:14:05 +01:00
parent e2af8f7ce3
commit daa90d33be
5 changed files with 138 additions and 101 deletions

View File

@ -268,7 +268,7 @@ string targetFilename(Resource resource)
}
}
/// Extracts and write a resource to a file.
/// Extracts and writes a resource to a file.
bool installResource(Resource resource)
{
const string fname = resource.targetFilename;
@ -293,7 +293,7 @@ bool installResource(Resource resource)
return true;
}
/// Deletes the file creates for a resource
/// Deletes the file created for a resource
bool uninstallResource(Resource resource)
{
const string fname = resource.targetFilename;

View File

@ -20,6 +20,9 @@ type
procedure SetVisible(Value: Boolean); override;
end;
//TODO-crefact: moves the macro recorded to TCESynMemo, + add visual feedback + declare shortcuts ecXXXX
{ TCEEditorWidget }
TCEEditorWidget = class(TCEWidget, ICEMultiDocObserver, ICEMultiDocHandler)

View File

@ -11,8 +11,12 @@ uses
type
TCEToolItems = class;
TCEToolItem = class(TCollectionItem)
private
fToolItems: TCEToolItems;
fNextToolAlias: string;
fProcess: TCEProcess;
fExecutable: TCEFilename;
fWorkingDir: TCEPathname;
@ -23,17 +27,17 @@ type
fQueryParams: boolean;
fClearMessages: boolean;
fEditorToInput: boolean;
fChainBefore: TStringList;
fChainAfter: TStringList;
fOutputToNext: boolean;
fShortcut: TShortcut;
fMsgs: ICEMessagesDisplay;
procedure setParameters(aValue: TStringList);
procedure setChainBefore(aValue: TStringList);
procedure setChainAfter(aValue: TStringList);
procedure setParameters(value: TStringList);
procedure processOutput(sender: TObject);
procedure execute;
procedure setToolAlias(value: string);
//
procedure setChainBefore(value: TStringList);
procedure setChainAfter(value: TStringList);
published
property toolAlias: string read fToolAlias write fToolAlias;
property toolAlias: string read fToolAlias write setToolAlias;
property options: TProcessOptions read fOpts write fOpts;
property executable: TCEFilename read fExecutable write fExecutable;
property workingDirectory: TCEPathname read fWorkingDir write fWorkingDir;
@ -42,22 +46,33 @@ type
property queryParameters: boolean read fQueryParams write fQueryParams;
property clearMessages: boolean read fClearMessages write fClearMessages;
property editorToInput: boolean read fEditorToInput write fEditorToInput;
property chainBefore: TStringList read fChainBefore write setchainBefore;
property chainAfter: TStringList read fChainAfter write setChainAfter;
property shortcut: TShortcut read fShortcut write fShortcut;
property nextToolAlias: string read fNextToolAlias write fNextToolAlias;
property outputToNext: boolean read fOutputToNext write fOutputToNext;
//
property chainBefore: TStringList write setChainBefore stored false; deprecated;
property chainAfter: TStringList write setChainAfter stored false; deprecated;
public
constructor create(ACollection: TCollection); override;
destructor destroy; override;
procedure assign(Source: TPersistent); override;
//
procedure execute(previous: TCEToolItem);
property process: TCEProcess read fProcess;
end;
TCEToolItems = class(TCollection)
public
function findTool(const value: string): TCEToolItem;
end;
TCETools = class(TWritableLfmTextComponent, ICEMainMenuProvider, ICEEditableShortcut, ICEMultiDocObserver)
private
fTools: TCollection;
fTools: TCEToolItems;
fShctCount: Integer;
fDoc: TCESynMemo;
function getTool(index: Integer): TCEToolItem;
procedure setTools(const aValue: TCollection);
procedure setTools(value: TCEToolItems);
//
procedure menuDeclare(item: TMenuItem);
procedure menuUpdate(item: TMenuItem);
@ -72,7 +87,7 @@ type
function scedWantNext(out category, identifier: string; out aShortcut: TShortcut): boolean;
procedure scedSendItem(const category, identifier: string; aShortcut: TShortcut);
published
property tools: TCollection read fTools write setTools;
property tools: TCEToolItems read fTools write setTools;
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
@ -97,73 +112,84 @@ const
toolsFname = 'tools.txt';
{$REGION TCEToolItem -----------------------------------------------------------}
function TCEToolItems.findTool(const value: string): TCEToolItem;
var
item: TCollectionItem;
begin
for item in self do
if TCEToolItem(item).toolAlias = value then
exit(TCEToolItem(item));
exit(nil);
end;
constructor TCEToolItem.create(ACollection: TCollection);
begin
inherited;
fToolAlias := format('<tool %d>', [ID]);
fToolItems := TCEToolItems(ACollection);
fToolAlias := format('<tool %d>', [ID]);
fParameters := TStringList.create;
fChainBefore := TStringList.Create;
fChainAfter := TStringList.Create;
end;
destructor TCEToolItem.destroy;
begin
fParameters.Free;
fChainAfter.Free;
fChainBefore.Free;
ce_processes.killProcess(fProcess);
inherited;
end;
procedure TCEToolItem.setChainBefore(value: TStringList);
begin
// kept to reload old setting files. 'xhainBefore' is not saved anymore.
end;
procedure TCEToolItem.setChainAfter(value: TStringList);
begin
// kept to reload old setting files. 'chainAfter' is not saved anymore.
end;
procedure TCEToolItem.assign(Source: TPersistent);
var
tool: TCEToolItem;
begin
// only used to clone a tool: so don't copy everything.
if Source is TCEToolItem then
begin
tool := TCEToolItem(Source);
//
toolAlias := tool.toolAlias;
chainAfter.Assign(tool.chainAfter);
chainBefore.Assign(tool.chainBefore);
queryParameters := tool.queryParameters;
clearMessages := tool.clearMessages;
fOpts := tool.fOpts;
toolAlias := tool.toolAlias;
queryParameters := tool.queryParameters;
clearMessages := tool.clearMessages;
options := tool.options;
executable := tool.executable;
workingDirectory := tool.workingDirectory;
editorToInput := tool.editorToInput;
showWindows := tool.showWindows;
parameters.Assign(tool.parameters);
executable := tool.executable;
workingDirectory := tool.workingDirectory;
end
else inherited;
end;
procedure TCEToolItem.setParameters(aValue: TStringList);
procedure TCEToolItem.setParameters(value: TStringList);
begin
fParameters.Assign(aValue);
fParameters.Assign(value);
end;
procedure TCEToolItem.setChainBefore(aValue: TStringList);
procedure TCEToolItem.setToolAlias(value: string);
var
i: Integer;
i: integer = 0;
begin
fChainBefore.Assign(aValue);
i := fChainBefore.IndexOf(fToolAlias);
if i <> -1 then
fChainBefore.Delete(i);
while fToolItems.findTool(value) <> nil do
begin
value += intToStr(i);
i += 1;
end;
fToolAlias := value;
end;
procedure TCEToolItem.setChainAfter(aValue: TStringList);
var
i: Integer;
begin
fChainAfter.Assign(aValue);
i := fChainAfter.IndexOf(fToolAlias);
if i <> -1 then
fChainAfter.Delete(i);
end;
procedure TCEToolItem.execute;
procedure TCEToolItem.execute(previous: TCEToolItem);
var
prm: string;
inp: string;
begin
ce_processes.killProcess(fProcess);
//
@ -177,33 +203,53 @@ begin
fProcess.Executable := exeFullName(symbolExpander.get(fExecutable));
fProcess.ShowWindow := fShowWin;
fProcess.CurrentDirectory := symbolExpander.get(fWorkingDir);
for prm in fParameters do if not isStringDisabled(prm) then
fProcess.Parameters.AddText(symbolExpander.get(prm));
if fQueryParams then
begin
prm := '';
if InputQuery('Parameters', '', prm) then
if prm <> '' then fProcess.Parameters.DelimitedText := symbolExpander.get(prm);
if prm <> '' then fProcess.Parameters.AddText(symbolExpander.get(prm));
end;
for prm in fParameters do if not isStringDisabled(prm) then
fProcess.Parameters.AddText(symbolExpander.get(prm));
ensureNoPipeIfWait(fProcess);
//
if FileExists(fProcess.Executable) then
begin
fProcess.Execute;
if (previous <> nil) and (previous.outputToNext)
and (poUsePipes in previous.Options) and (poUsePipes in Options) then
begin
setLength(inp, previous.process.OutputStack.Size);
previous.process.OutputStack.Position:=0;
previous.process.OutputStack.Read(inp[1], length(inp));
fProcess.Input.Write(inp[1], length(inp));
fProcess.CloseInput;
end;
end;
end;
procedure TCEToolItem.processOutput(sender: TObject);
var
lst: TStringList;
str: string;
nxt: TCEToolItem;
begin
getMessageDisplay(fMsgs);
lst := TStringList.Create;
try
fProcess.getFullLines(lst);
for str in lst do
fMsgs.message(str, nil, amcMisc, amkAuto);
finally
lst.Free;
if ((not fOutputToNext) or (fNextToolAlias = '')) and (poUsePipes in options) then
begin
getMessageDisplay(fMsgs);
lst := TStringList.Create;
try
fProcess.getFullLines(lst);
for str in lst do
fMsgs.message(str, nil, amcMisc, amkAuto);
finally
lst.Free;
end;
end;
if (not fProcess.Running) and (fNextToolAlias <> '') then
begin
nxt := fToolItems.findTool(fNextToolAlias);
if assigned(nxt) then nxt.execute(self);
end;
end;
{$ENDREGION --------------------------------------------------------------------}
@ -214,7 +260,7 @@ var
fname: string;
begin
inherited;
fTools := TCollection.Create(TCEToolItem);
fTools := TCEToolItems.Create(TCEToolItem);
fname := getCoeditDocPath + toolsFname;
if fileExists(fname) then loadFromFile(fname);
//
@ -336,13 +382,12 @@ begin
if fDoc <> aDoc then exit;
fDoc := nil;
end;
{$ENDREGION}
{$REGION Tools things ----------------------------------------------------------}
procedure TCETools.setTools(const aValue: TCollection);
procedure TCETools.setTools(value: TCEToolItems);
begin
fTools.Assign(aValue);
fTools.Assign(value);
end;
function TCETools.getTool(index: Integer): TCEToolItem;
@ -357,31 +402,18 @@ end;
procedure TCETools.executeTool(aTool: TCEToolItem);
var
nme: string;
txt: string;
chained: TCollectionItem;
begin
if aTool = nil then exit;
//
for nme in aTool.chainBefore do
for chained in fTools do
if TCEToolItem(chained).toolAlias = nme then
if TCEToolItem(chained).toolAlias <> aTool.toolAlias then
TCEToolItem(chained).execute;
//
aTool.execute;
if aTool.editorToInput and assigned(fDoc) and (poUsePipes in aTool.options) then
aTool.execute(nil);
if aTool.editorToInput and assigned(fDoc) and (poUsePipes in aTool.options)
and (aTool.fProcess.Input <> nil) then
begin
txt := fDoc.Text;
aTool.fProcess.Input.Write(txt[1], length(txt));
aTool.fProcess.CloseInput;
end;
//
for nme in aTool.chainAfter do
for chained in fTools do
if TCEToolItem(chained).toolAlias = nme then
if TCEToolItem(chained).toolAlias <> aTool.toolAlias then
TCEToolItem(chained).execute;
end;
procedure TCETools.executeTool(aToolIndex: Integer);

View File

@ -11,7 +11,6 @@ uses
type
{ TCEToolsEditorWidget }
TCEToolsEditorWidget = class(TCEWidget)
BtnAddTool: TBitBtn;
btnMoveDown: TBitBtn;

View File

@ -32,7 +32,7 @@
Welcome to Coedit Wiki, the documentation source for the small Windows & Linux IDE for the D programming language.
A summary of the content is accessible in the right side-bar.
*Note that this document is based on Coedit 2 alpha 2 and it does not represent yet the changes made to the development version*
*Note that this document is based on Coedit 2 development version and it does not represent anymore the latest official stable release*
![](https://raw.githubusercontent.com/BBasile/CoeditWikiData/master/coedit.win7.33.png) ![](https://raw.githubusercontent.com/BBasile/CoeditWikiData/master/coedit.linux.kde.33.png)
@ -106,7 +106,7 @@ libc.so.6
Download ans setup the tools:
* [Download](http://lazarus.freepascal.org/index.php?page=downloads) and setup the latest Lazarus (1.4.2) version and FPC / FPC sources (2.6.4) for your platform.
* [Download](http://lazarus.freepascal.org/index.php?page=downloads) and setup the latest Lazarus (1.4.4) version and FPC / FPC sources (2.6.4) for your platform.
* Windows: the three packages are bundled in an installer. Even on Windows 64 bit, the 32 version must be setup.
* Linux: the three packages must be downloaded and setup individually. Take care to the version number because the official rpm/deb source of a Linux distribution does not always propose the latest version !
@ -145,7 +145,7 @@ See the products documentation for more information.
Any Pascal or Delphi programmer who has interest to the D language can contribute.
The process is based on _git_ and _Github_, using what's often called the _fork push pull_ model:
- _fork_ the _Coedit_ repository in your _Github_ account.
- fork the _Coedit_ repository in your _Github_ account.
- clone this fork to your computer.
- using Lazarus and FPC, develop, fix, optimize, do whatever could improve Coedit.
- _push_ your changes to your online fork.
@ -314,12 +314,12 @@ _DCD_ also has a native configuration system. Refer to the official [_Readme_](h
### Usage
- <kbd>CTRL</kbd> + <kbd>SPACE</kbd>: invokes the completion.
- <kbd>CTRL</kbd> + <kbd>SPACE</kbd>: Calls the completion menu or auto-completes if possible. The default shortcut can be modified in the [shortcut editor][lnk_widg_opts].
- <kbd>.</kbd> invokes the completion if the editor option _autoDotDelay_ is greater than 0.
- <kbd>CTRL</kbd> + <kbd>SHIFT</kbd> + <kbd>UP</kbd>: quick jump to the declaration of the symbol located at the cursor position.
- <kbd>CTRL</kbd> + <kbd>SHIFT</kbd> + <kbd>UP</kbd>: Jumps to the declaration of the symbol located at the cursor. The default shortcut can be modified.
- <kbd>CTRL</kbd> + <kbd>LEFT MOUSE BUTTON</kbd>: ditto.
- <kbd>(</kbd>: gets the function call tips.
- <kbd>)</kbd>: closes the call tips window.
- <kbd>(</kbd>: Gets the function call tips.
- <kbd>)</kbd>: Closes the call tips window.
- <kbd>ESC</kbd>: ditto.
Documentation comments associated to a symbol are displayed when hovering the symbol with the mouse.
@ -407,12 +407,12 @@ The _source editor widget_ is a standard code editor, specialized for highlighti
It's based on the [**Synedit**](http://wiki.freepascal.org/SynEdit) suite, a powerful set of Pascal components and classes,
which can be described as a _"Scintilla for Pascal"_. It features:
- folding (curly brackets blocks, multi-line strings, block comments).
- folding (curly brackets blocks, multi-line strings, block comments, nested block comments, DDoc comments blocks).
- colorization of the following categories: keywords, numbers, symbols, comments, ASM operands and identifiers, DDoc comments.
- colorization of the current identifier in the whole view.
- standard keyboard navigation shortcuts <kbd>CTRL</kbd> + (<kbd>SHIFT</kbd> +) <kbd>LEFT</kbd>/<kbd>RIGHT</kbd>, <kbd>CTRL</kbd> + <kbd>HOME</kbd>, <kbd>CTRL</kbd> + <kbd>END</kbd> etc.
- macro recording and playback using <kbd>CTRL</kbd>+<kbd>SHIFT</kbd>+<kbd>R</kbd> (start/stop recording) or <kbd>CTRL</kbd>+<kbd>SHIFT</kbd>+<kbd>P</kbd> (play).
- synchro-edit (activated when clicking the pen icon located in the gutter).
- synchro-edit (activated when clicking the pen icon located in the gutter, or with the shortcut <kbd>CTRL</kbd>+<kbd>E</kbd> and <kbd>CTRL</kbd>+<kbd>SHIFT</kbd>+<kbd>E</kbd>).
- zoom: (<kbd>CTRL</kbd>+<kbd>WHEEL</kbd>, <kbd>CTRL</kbd>+<kbd>MIDDLE MB</kbd>, <kbd>CTRL</kbd>+<kbd>+</kbd>, <kbd>CTRL</kbd>+<kbd>-</kbd>, <kbd>CTRL</kbd>+<kbd>.</kbd>).
- display cache: for each document, the zoom ratio, the folds and the caret position are saved between two sessions. A cache file has a fixed life-time of three months from its last modification.
- drag drop editing.
@ -455,12 +455,12 @@ The editor shortcuts are listed there:
![](https://raw.githubusercontent.com/BBasile/CoeditWikiData/master/optshortcut.png)
Note that you can edit text files in Coedit too (as well as any other file type suc as _*.dd_ D documentation files)
Note that you can edit text files in Coedit too (as well as any other file type such as _*.dd_ D documentation files)
A simple highlighter is automatically set for this purpose:
![](https://raw.githubusercontent.com/BBasile/CoeditWikiData/master/sourceditor2.png)
It's also customizable in the option editor but the colorizer only recognizes identifiers and symbols.
It's also customizable in the option editor but the highlighter only recognizes identifiers and symbols.
## Find & replace widget
@ -694,7 +694,7 @@ Unfiltered options, sub categories can be expanded or collapsed. The field ***na
## DUB project editor
The DUB project editor is widget is devided in two panels:
The DUB project editor is widget is divided in two panels:
### Inspector
@ -751,13 +751,15 @@ This is a recommended setting because if a run-time error happens, it will be im
## Custom tools widget
This widget allows to define a set of third party applications that can be launched from Coedit.
Thanks to the [symbolic strings][lnk_sym] it's possible for a tool to be aware of the document location or even to get the list of the sources used by a project.
The tools are not just applications that are launched from the software. Since they support [symbolic strings][lnk_sym] they can directly perform some actions on the current source file, in its directory, on all the sources of a project, etc. The tools can even be chained and the output stream of an item redirected to the input stream of the next.
A few typical examples:
- launch a console with its working directory set to the project file directory.
- analyze the current document in _Dscanner_. (see the tutorials).
- generate the documentation for all the project D sources.
- use a custom build tool (_make_, _DUB_).
- format the current document with _dfmt_.
- generate the documentation for all the project sources. (see the tutorials).
- launch a custom build tool (_make_, _DUB_).
- launch a script that will zip and upload the latest project build.
![](https://raw.githubusercontent.com/BBasile/CoeditWikiData/master/toolseditor1.png)
@ -768,21 +770,22 @@ Toolbar:
- ![](https://raw.githubusercontent.com/BBasile/Coedit/master/icons/window/application_flash.png): executes selected tool, according to the options it's associated to. This also works by double-clicking a tool alias.
- ![](https://raw.githubusercontent.com/BBasile/Coedit/master/icons/window/application_double.png): clones selected tool.
A tool can be selected from the left side of the widget. If selected, a property inspector displays the options that can be defined:
- chainBefore: allow to define a list of tool to execute before the item. A list item has to match one of the *toolAlias* already defined. By default a tool is executed asynchronously. If it's desirable that a tool must finish before the next starts then **poWaitOnExit** must be set in the options.
- chainAfter. Idem but the tools defined in the list are executed after the item.
- clearMessages: if the tool standard output is redirected to the [messages widget][lnk_widg_msg] then the previous messages are cleared before the execution.
A tool can be selected from the left side of the widget. If selected, a property inspector displays the options that can be edited:
- clearMessages: if the tool standard output is redirected to the [messages widget][lnk_widg_msg] then the previous messages are cleared before the execution. The output is redirected to the messages when **popUsePipes** is set and if the **nextToolALias** is empty.
- editorToInput: when set, the content of the current editor is streamed to the tool standard input.
- executable: the tool file name. If the system cannot find its path in the environment variables then it must be included. The field can include a [symbolic string][lnk_sym].
- nextToolAlias: defines the alias of another tool that will be launched after this one returns.
- options: various options for the process to create. If you set **popUsePipes** and **poStdErrToOutput** to true, then the standard output will be redirected to the message widget, category Misc.
- outputToNext: if **popUsePipes** is set in the options and if the next tool is defined then the next tool will see its input stream filled with the output stream.
- parameters: allows to define the parameters, switches and options passed to the process. As usual, one item per line, no quotes. The items can include a [symbolic string][lnk_sym].
- queryParameters: if set to true then a small input query dialog will be shown before executing the tool. It can be filled with more _--para --meters_.
- shortcut: allow to define the keystroke to launch the tool. The shortcut can also be edited in the [options editor][lnk_widg_opts].
- showWindow: allow to define how the tool window is displayed. Set to swoHIDE if the tool std out is redirected.
- shortcut: allow to define the keystroke used to launch the tool. The shortcut can also be edited in the [options editor][lnk_widg_opts].
- showWindow: allow to define how the tool window is displayed. Set to *swoHIDE* if the tool std out is redirected.
- toolAlias: the friendly name associated to the tool.
- workingDirectory: directory in which starts the tool. Not to mismatch with its path. The field can include a [symbolic string][lnk_sym].
- workingDirectory: the directory in which the tool starts. Not to mismatch with its path. The field can include a [symbolic string][lnk_sym].
The tools configuration is saved between each cession, in the same folder as the application [options][lnk_widg_opts].
The configuration is saved between each session, in the same folder as the application [options][lnk_widg_opts].
## Todo list