HippoEDIT forum

General Category => Scripting, Scripts and Macros => Topic started by: alex on July 26, 2011, 04:33:24 AM

Title: 1.50: scripting first test
Post by: alex on July 26, 2011, 04:33:24 AM
Hi,

here I will publish first examples for scripting in HippoEDIT. First no documentation, only examples.
So, interested can check what will come and try it a little bit. But I do not promise that API ill not change until final release of 1.50.

To get brief overview of API function you can use this raw help file (chm file) (http://www.hippoedit.com/download/heapi.chm).
To execute scripts you need latest version of 1.50 alpha.
There are two ways to call script currently:
- open script file and use Tools->Execute "Current file" command
- Create a tool, taking script path into command window. It should work as normal tool, and called tool script.
- In next version will be introduced also so called service scripts. They will work based on events registration and can run resident in parallel.

HippoEDIT supports any installed active scripting engine. By default supported  JavaScript and VBScript. If you start any VBS or JS file inside of HippoEDIT with Execute command or as tool, HE will assume that it is HE script and will try to execute passing scripting objects. So it can work with any *.js or *.vbs file. But for convenience there are also dedicated schemes inherited from JS ans  VBS syntaxes and associated with *.hejs and *.hevbs extensions correspondingly. Dedicated schemes extended by HE specific syntax. Till now only HEJS schema is up to date. HEVBS will be updated later.

Script files support includes (see usage of include.js for example). Usage of include files from other supporting scripting language is also supported (you can include JS includes in VBS scripts for example).
Title: Re: 1.50: scripting first test
Post by: alex on July 26, 2011, 04:34:17 AM
more scripts
Title: Re: 1.50: scripting first test
Post by: alex on July 26, 2011, 04:45:27 AM
small VBS example
Title: Re: 1.50: scripting first test
Post by: Stefan on July 31, 2011, 08:43:02 PM
Thank you for your great work Alex!

This looks rather like an complicated syntax. I was more thinking about an simple 'one-line' syntax.
But as every time: if you do it you do it well.  Taking an closer lock the syntax seams as easy as HTML code.


I think with this HE scripting all will be possible.
I mean, other editors have scripting features too, but without an handy UI like you build for HE they are
limited to simple actions mostly and tricky to use for more feature-rich needs. We all know this simple InputBox questions,
most three or four in an row to prompt the user for his options only to script an simple text modification. With HippoEDIT
scripting GUI features the user can build very professional locking (and working) tools for his own needs without HE itself
will become an 'all-features-in-one-app-monster'.

Let's see how long it needs till THIS feature will seen in other editors too like so many in the past.

I can see the power of the programming language style syntax and have to play around to get used to it.

Here are some impressions for those who are not so familiar with scripting or don't want to download and test an alpha build,
 (but don't be afraid, since the scripts are already wrote, your part only is to execute them)
Title: Re: 1.50: scripting first test
Post by: Stefan on August 01, 2011, 11:40:21 AM
My first own dialog (well just copy and paste and a little modified.
[attach=1]


(Note: the alert() at the end of the code  is just non-working dummy code)
Title: Re: 1.50: scripting first test
Post by: alex on August 02, 2011, 04:13:20 AM
Hi Stefan,

if you only want to provide support for input fields and combos, yes it possible to go with "one-line" syntax. But if you want to provide similar level of flexibility as have plugins, it is impossible. Hippoedit provides a lot of controls with a lot of properties with layout possibilities, try to imagine syntax you need to invent for such "one-line" representation. And it should be well formed, with escaping and robust to accept some level of errors. And at the end you need to teach a user of how to use it.
Using XML is standard (for HE), well formed, and fast because already optimized in HE. So it was an  obvious and right choice. I have evaluated it for a long time beforehand.
Example from NotePad it is cryptic nightmare :)

I will try to publish syntax description for XML dialogs, with explanations for all properties.
And I have updated the initial post with raw chm with interface description.

About your examples:
- you (because I know your preferences) can also use VBS for scripting (forgot, the schema is not done for it, but it will work, even then not syntax highlighted). I just have more experience with JS.
- id property for dialog, used for persistence of size and dialog position, that is maybe why layout of your dialog is strange (buttons are not at the bottom)
- you can play with required fields, if they do not filled, "positive" buttons will be disabled. Yon need to use predefined "ok" "apply" as returnvals to make it working.
- you can also mark paragraph as required, than it will have red asterisk.
- for getting results from dialog, you can use as SettingsStorage object (CreateStorage), as automatic way, in which HE reads variables from script by id and updates them on "positive" dialog end.
- if you create a xml dialog, try to use special syntax ('@ - @'), which will enable specialized parser for it.

I will update dialog_actions.hejs with an example.

BR, Alex.
P.S: and thank a lot for a feedback :)
Title: Re: 1.50: scripting first test
Post by: Stefan on August 02, 2011, 11:34:46 AM
Alex>About your examples:
Alex>- you (because I know your preferences) can also use VBS for scripting
I try to use (learn) JS too.


Alex>- id property for dialog, used for persistence of size and dialog position,
I do not see any mistake i have done. What should i change?

Alex>- you can play with required fields, if they do not filled, "positive" buttons will be disabled.
Alex>- you can also mark paragraph as required, than it will have red asterisk.
Alex>- if you create a xml dialog, try to use special syntax ('@ - @'), which will enable specialized parser for it.
Yes, already seen.

Alex>Yon need to use predefined "ok" "apply" as returnvals to make it working.
"My" returnvals are "Ok" and "Cancel" as copied from your script. Only i changed the button labels (title).
What do you mean? Have i make it wrong?

Alex>- for getting results from dialog, you can use as SettingsStorage object (CreateStorage), as automatic way,
Alex> in which HE reads variables from script by id and updates them on "positive" dialog end.
How? How can i get the value of ID "itb" ?

Code: Javascript
  1. var myDialog = '@<dialog title="Insert text" id="test"> \
  2. <paragraph text="Enter the text to be inserted before and/or after each selected line"/><spacer/> \
  3.   <group><paragraph text="Before:" minwidth="6" align="left"/><edit id="itb" minwidth="35"/></group> \
  4.   <group><paragraph text="After:" minwidth="6" align="left"/><edit id="ita" minwidth="35" /></group> \
  5.   <group uniform="true" align="right|bottom"> \
  6.            <button title="&amp;Lets go" returnval="ok" default="true"/> \
  7.            <button title="&amp;No thanks" returnval="cancel"/> \
  8.   </group> \
  9. </dialog>@';
  10.  
  11. // write something to standard output:
  12. var HEOutput = Application.Output();
  13. HEOutput.writeln("HippoEDIT version: " + Application.Version);
  14.  
  15. // get the user input into "varMyOutputStorage " and write to output "HEOutput":
  16. var varMyOutputStorage = CreateStorage();
  17. HEOutput.writeln("My dialog returns: " + dialog(myDialog, varMyOutputStorage));
  18.  

My output:
Code: Text
  1. HippoEDIT version: 1.50.721
  2. My dialog returns: 1
  3.  
Title: Re: 1.50: scripting first test
Post by: JJK on August 02, 2011, 11:20:25 PM
Hi all
I downloaded HeApi.chm but I can't read it under Windows 7.
I had installed Windows6.1-KB917607-x86.msu from Microsoft which is designed to read .hlp files under Windows 7, but it does not work.

Any idea ?
TIA
Title: Re: 1.50: scripting first test
Post by: Stefan on August 03, 2011, 12:04:05 AM
I downloaded HeApi.chm but I can't read it
1. Right click on the file, and click on Properties.
2. Under the General tab,
click on the Unblock button beside the message, "This file came from another computer and might blocked to help protect  this computer."
and click on OK.
Title: Re: 1.50: scripting first test
Post by: alex on August 03, 2011, 04:38:36 AM
Hi Stefan,

id="test" - I noticed that your dialog is bigger than content and buttons are not aligned to bottom, this is or a bug, or you have used same id for a dialog with bigger size, and size was stored ans used for all dialogs with same id. And because dialog was not marked as resizable, there is no way to make it smaller (this is maybe a bug, I will check).

Quote
"My" returnvals are "Ok" and "Cancel" as copied from your script. Only i changed the button labels (title).
What do you mean? Have i make it wrong?
Now I see, they are fine. Generally you can use as hard-coded enumerations, as any integer number there. Values from -1 till 9 are mapped to enumerations. Some enumerations are positive (as I mentioned "ok", "yes"), and there are some built-in extras for them, as auto-disable by missing required fields and auto apply of script variables on finish of the dialog using them.

Quote
How? How can i get the value of ID "itb" ?
There are two ways: implicit and explicit.
 - implicit:
add this code before calling of the dialog (line 17).
Code: Javascript
  1. var itb="/*";
  2. var ita="*/";
you do not need to assign values, they are optional and just read before and used as defaults.
With such code after start of your dialog you will have fields filled with "/*" and "*/" and if you will select "ok" button, modified values will be copied back.
There is one important point about such implicit way - it works ONLY for GLOBAL variables. For vars from withing functions, for example, it will not work.

- explicit:
Works always, and requires usage of settings storage object, the same way as you do if you want to save script values between sessions or share them between scripts.
Add this code before calling of the dialog:
Code: Javascript
  1. var varMyOutputStorage = CreateStorage();
  2. varMyOutputStorage.write("itb", "/*");
  3. varMyOutputStorage.write("ita", "*/");
  4.  
and this after calling of the dialog. Variables will be updated in any case, independent from return code. This is your job to check return code and read or not read variables back:
Code: Javascript
  1. var varMyOutputStorage = CreateStorage();
  2. var itb = varMyOutputStorage.read("itb");
  3. var ita = varMyOutputStorage.read("ita");
  4.  

if you do not want to initialize variables before, you can skip first part, and only read variables from storage later. They will be created automatically in the map, based on id properties in dialog definition.

P.S: I have updated your message with syntax highlighting for you code snippet. I thought you have already seen this - check toolbar. Also now in-line images are supported.

Title: Re: 1.50: scripting first test
Post by: Stefan on August 03, 2011, 11:21:09 AM
Alex> id="test" - I noticed that your dialog is bigger
That was the only dialog and the only ID "test" in that script.
But today the dialog looks normal, as expected.
HE has waited for me over night with that script open, and i didn't modified the dialog,..
only the output code as your reply shows, started the script and... the buttons are at the bottom now.

[attach=1]


- - -

Thanks for your explanation, i got it working:

- implicit

Code: Javascript
  1. // initialize the output vars, and set default values if wanted:
  2. var ID_itb="not used by user";
  3. var ID_ita="";
  4.  
  5. // build up your dialog and store it in var vMyDialog:
  6. var vMyDialog = '@<dialog title="Insert text" id="test"> \
  7. <paragraph text="Enter the text to be inserted before and/or after each selected line"/><spacer/> \
  8.   <group><paragraph text="Before:" minwidth="6" align="left"/><edit id="ID_itb" minwidth="35"/></group> \
  9.   <group><paragraph text="After:" minwidth="6" align="left"/><edit id="ID_ita" minwidth="35" /></group> \
  10.   <group uniform="true" align="right|bottom"> \
  11.            <button title="&amp;OK" returnval="ok" default="true"/> \
  12.            <button title="&amp;Cancel" returnval="cancel"/> \
  13.   </group> \
  14. </dialog>@';
  15.  
  16. // execute the dialog:
  17. var vErrorcode = dialog(vMyDialog);
  18.  
  19. // if [OK] is clicked...
  20. if (vErrorcode==1){
  21.         // write to HEs standard output:
  22.         var vHEOutput = Application.Output();
  23.         vHEOutput.clear();
  24.         vHEOutput.writeln("HippoEDIT version: " + Application.Version);
  25.         vHEOutput.writeln("Returned error code: " + vErrorcode);
  26.         vHEOutput.writeln("Text to be inserted before: " + ID_itb);
  27.         vHEOutput.writeln("Text to be inserted after: " + ID_ita);
  28. }
  29.  

Execute this script and just pressing [OK] results into:
Code: [Select]
HippoEDIT version: 1.50.721
Returned error code: 1
Text to be inserted before: not used by user
Text to be inserted after:




- explicit

Code: Javascript
  1. // build up your dialog and store it in var vMyDialog:
  2. var vMyDialog = '@<dialog title="Insert text" id="test"> \
  3. <paragraph text="Enter the text to be inserted before and/or after each selected line"/><spacer/> \
  4.   <group><paragraph text="Before:" minwidth="6" align="left"/><edit id="ID_itb" minwidth="35"/></group> \
  5.   <group><paragraph text="After:" minwidth="6" align="left"/><edit id="ID_ita" minwidth="35" /></group> \
  6.   <group uniform="true" align="right|bottom"> \
  7.            <button title="&amp;OK" returnval="ok" default="true"/> \
  8.            <button title="&amp;Cancel" returnval="cancel"/> \
  9.   </group> \
  10. </dialog>@';
  11.  
  12. // create new instance of an settings storage object:
  13. var vMyOutputStorage = CreateStorage();
  14. // set default values (if wanted):
  15. vMyOutputStorage.write("ID_itb", "default value for \"before\"");
  16. //vMyOutputStorage.write("ID_ita", "default value for \"after\"");
  17.  
  18. // execute the dialog and use OutputStorage to store the user input:
  19. var vErrorcode = dialog(vMyDialog, vMyOutputStorage);
  20.  
  21. // if [OK] is clicked...
  22. if (vErrorcode==1){
  23.         // get the user input:
  24.         var vITB = vMyOutputStorage.read("ID_itb");      if (vITB==""){vITB="'Before' is not used by user";}
  25.         var vITA = vMyOutputStorage.read("ID_ita");      if (vITA==""){vITA="'After' is not used by user";}
  26.  
  27.         // write to HEs standard output:
  28.         var vHEOutput = Application.Output();
  29.         vHEOutput.clear();
  30.         vHEOutput.writeln("HippoEDIT version: " + Application.Version);
  31.         vHEOutput.writeln("Returned error code: " + vErrorcode);
  32.         vHEOutput.writeln("Text to be inserted before: " + vITB);
  33.         vHEOutput.writeln("Text to be inserted after: " + vITA);
  34. }
  35.  


Execute this script and just pressing [OK] results into:
Code: [Select]
HippoEDIT version: 1.50.721
Returned error code: 1
Text to be inserted before: default value for "before"
Text to be inserted after: 'After' is not used by user

Where is the thump-up smiley?  ;D
Title: Re: 1.50: scripting first test
Post by: JJK on August 03, 2011, 06:41:11 PM
1. Right click on the file, and click on Properties.
2. Under the General tab,
click on the Unblock button beside the message, "This file came from another computer and might blocked to help protect  this computer."
and click on OK.
Many thanks. It works well now.
I didn't know that feature :( but now I know it :) 
Title: Re: 1.50: scripting first test
Post by: Ramon on August 04, 2011, 02:14:11 AM
I just playin with this new feature.

When I use csript with script like bellow I do not see CMD window. But if I use adapted script for HE and run "Tools->Execute Test.js", CMD window has appear. What I need to do to hide CMD window.

Script for cscript:
Code: Javascript
  1. var WshShell = new ActiveXObject("WScript.Shell");
  2. var WshExec = WshShell.Exec("cmd /c dir c:\\");
  3.  
  4. while (!WshExec.StdOut.AtEndOfStream)
  5.         WScript.Echo( WshExec.StdOut.ReadLine() );
  6.  

Script for HE:
Code: Javascript
  1. var Output = Application.Output();
  2. var WshShell = new ActiveXObject("WScript.Shell");
  3. var WshExec = WshShell.Exec("cmd /c dir c:\\");
  4.  
  5. Output.clear();
  6.  
  7. while (!WshExec.StdOut.AtEndOfStream)
  8.         Output.writeln( WshExec.StdOut.ReadLine() );
  9.  
Title: Re: 1.50: scripting first test
Post by: alex on August 04, 2011, 03:20:20 AM
Hi Ramon,

It does not work with first example, because HE does not know what to do with  WScript.Echo :) You send output to WScript and where it sends it further I have no clue :) But OK, maybe in this case I also need to catch standard output. The only problem, is it can conflict with usage of unnamed Output (same pane) from withing the script. But maybe that is fine. I will check.

About second example. I think this is too complicated :) Check scripting.hejs for example:
Code: Javascript
  1. // capture cmd.exe and execute a command
  2. var output_cmd = Application.Output("CMD");
  3. output_cmd.Capture("cmd.exe", "", "exit");
  4. Application.sleep(1000);
  5. output_cmd.AddCommand("dir");
  6. Application.ClosePane("", output_cmd);

There is also a way to just run tool in background and capture the standard output in string variable:
Code: Javascript
  1. var sResult = CaptureOutput("test.bat");
See attached heapi.chm for parameters.

If you close standard pane, it is just hidden. If you close custom pane (named output fex), it is really closed.
For now to way to just hide it. Maybe I need to add this, but not yet done.

BR, Alex
Title: Re: 1.50: scripting first test
Post by: Stefan on August 04, 2011, 11:11:25 AM
Alex, the first script from Ramon was an example only, tested outside of HE by involving script.exe.

Common info:
WScript is an object of the Windows Scripting Host, meaning only available by using cScript.exe or wScript.exe
Since HippoEDIT is it own scripting host, the WScript object is not involved at all.


An other idea for
var WshExec = WshShell.Exec("cmd /c dir c:\\");

maybe
var WshExec = WshShell.RUN( strCommand, intWindowStyle, bWaitOnReturn);
where intWindowStyle could be '0' (Hides the window)

See
http://msdn.microsoft.com/en-us/library/d5fk67ky%28v=vs.85%29.aspx
Title: Re: 1.50: scripting first test
Post by: alex on August 04, 2011, 12:46:25 PM
Hi Stefan,

thank for help here.

I think Ramons first example was correct. This should work correct (also used in my scripting.hejs):
Code: Javascript
  1. var WshShell = new ActiveXObject("WScript.Shell");
and you do not need to start cScript or wScript.exe. What xScript.exe are doing, is just starting as scripting host and initialize WshShell by internal objects, which are COM objects from some registered type library. The same does new ActiveXObject. So, this is a way how to execute/adopt scripts for WSH inside of HE.

But the problem is that WScript.Echo( WshExec.StdOut.ReadLine() ); uses standard output (console output), from WSH and normally I know how to catch it if it executes in other process (as done for tools), but currently for me is not sure how this should work, if it called in HE scripting host and where goes this Echo command. I will try to clarify this, because this can help to make easier scripts adoption....

BR, Alex
Title: Re: 1.50: scripting first test
Post by: Stefan on August 04, 2011, 02:21:55 PM
I don't know if i can make myself clear with all that 'host' and 'object'.


What i mean was:

"WScript.Shell" is not the same as the "WScript .dot" object in an script.


"WScript.Shell" is an string only to refer to the "WshShell object" registry entry
HKEY_CLASSES_ROOT\CLSID\{72C24DD5-D70A-438B-8A42-98424B88AFB8}\VersionIndependentProgID
to use this object for your script.



Where as "WScript .dot" as object in your script
is only instanced if you use the WSH as your host (via cscript/wscript)
but HE is its own host (as other text editors, or IE for that matter) and don't have access to this object.
http://msdn.microsoft.com/en-us/library/at5ydy31%28v=vs.85%29.aspx



So the simple use of
WScript.echo,
WScript.Quit,
WScript.BuildVersion, ... will not work inside HE.
http://www.devguru.com/technologies/wsh/quickref/wscript.html


Try 
C:\>cscript test.vbs

test.vbs
Code: Visual Basic
  1. Set WS = WScript.CreateObject("WScript.Shell") '//not need, only to see
  2.  
  3. WScript.echo WScript.Fullname & ", v:" & WScript.BuildVersion
  4. WScript.echo "Hi one"
  5. WScript.Quit
  6. WScript.echo "Hi two"

WScript Dot will only work for (c|w)script in WSH host. Not for other hosts.


I guess that's why (if i understand you right)
var WshShell = new WScript.CreateObject("WScript.Shell");
will not work
and you have created your own 'ActiveXObject' ?
var WshShell = new ActiveXObject("WScript.Shell");


Or, changes are good, you know more about that things under the hood... or i misunderstood the whole topic? Then excuse me.
Title: Re: 1.50: scripting first test
Post by: alex on August 04, 2011, 03:08:11 PM
Hi Stefan,

you are completely right, and I was wrong. I have overlooked, that Ramon has used WScript object directly. And yes, it is not possible to use it inside of HE (the script execution fails, because object is unknown, of course).
WScript is same as Application in HE. 

So, problem solved and no catch output necessary ;) What only can be done, is emulation of WScript object, by implementing same methods and forwarding them to HE specific methods.

BR, Alex
Title: Re: 1.50: scripting first test
Post by: Stefan on August 10, 2011, 08:53:13 PM
WOW the API chm is pretty full loaded with commands. You must have been very busy.

Would you please tell me how i can get and set selected text?
I only see "GetText start, end"

But i think about smtg like
varSel = GetSelectedText
and
SetSelectedText(varString)
to replace an selection.

Is this already there?
Title: Re: 1.50: scripting first test
Post by: alex on August 10, 2011, 09:16:55 PM
Hi Stefan,

Selection does not belong to a Document but to a View (so called presentation). One document can have several Views and only one Active.
So, something like this should work:
Code: Javascript
  1. var ptStart, ptEnd;
  2. ActiveView.GetSelection(ptStart, ptEnd);
  3. ActiveView.Select(ptStart, ptEnd);
  4. ActiveDocument.GetText(ptStart, ptEnd);
  5. ActiveDocument.ReplaceText(ptStart, "New Text", ptEnd, 0);
  6. ActiveDocument.InsertText(ptStart, "Inserted Text", ptEnd, 0);

where point is structure with Line and Pos, but I am afraid that scripting (not a plugins), does not support structures, and I will need to replace this to two integer as line and position for start and end. I will check.

BR, Alex.
Title: Re: 1.50: scripting first test
Post by: alex on August 12, 2011, 04:00:46 AM
Hi Stefan,

I think I will need to replace all usages of POINT_T in API and my implementation by two int values for line and position... I was trying to change this fast, but I think I will not be able to update alpha before my vacation (from 13.08.2011 till 22.08.2011) - too many places should be adopted.
So, please wait with it till then.

BR, Alex.
Title: Re: 1.50: scripting first test
Post by: Stefan on August 12, 2011, 11:47:31 AM
Of course take your time and have an nice vacation. Greetings to your family.


Just my thought:

But i don't understand your syntax:
ActiveView.GetSelection(ptStart, ptEnd);
ActiveDocument.GetText(ptStart, ptEnd);
ActiveDocument.ReplaceText(ptStart, "New Text", ptEnd, 0);

While it is good to know start and end point
sometimes i don't take care of this info
and only want to get or set (replace) the selected text
varSel = ActiveDocument.GetSelectedText
ActiveDocument.SetSelectedText varString
I want to make the syntax more easy to write for the most time, and use the extended syntax only f needed.

And the editor already knows the ptStart and ptEnd of an selection, why should the user execute this GetSelection command again?
F.ex.: In other editors i had to get the start and end point of an selection and calculate the selected lines on my own.
I hope HE will provide such infos just by build-in "variables"?
ActiveDocument.Info.CountLinesDocument
ActiveDocument.Info.CountLinesSelection
ActiveDocument.Info.CountByteDocument
ActiveDocument.Info.CountByteSelection

ActiveDocument.Info.SelectionStartLine
ActiveDocument.Info.SelectionStartColumn
ActiveDocument.Info.SelectionEndLine
ActiveDocument.Info.SelectionEndColumn

Yes, i have browse the heapi.chm, but i got lost somewhere.

As far as i  underst guess,
the last four infos i  should get by using
var ptStart, ptEnd;
ActiveView.GetSelection(ptStart, ptEnd);
???

But according your last post you have to modify it to smtg like:
var LineStart, LineEnd, ColumnStart, ColumnEnd;
ActiveView.GetSelection(LineStart, LineEnd, ColumnStart, ColumnEnd);
???

.
Title: Re: 1.50: scripting first test
Post by: alex on August 12, 2011, 02:32:11 PM
Hi Stefan,

I have only provide you example function you can use.
To get selected text you need something like this:
Code: Javascript
  1. var ptStart, ptEnd;
  2. ActiveView.GetSelection(ptStart, ptEnd);
  3. var text = ActiveDocument.GetText(ptStart, ptEnd);

to replace selection:
Code: Javascript
  1. var ptStart, ptEnd;
  2. ActiveView.GetSelection(ptStart, ptEnd);
  3. ActiveDocument.ReplaceText(ptStart, "New Text", ptEnd, 0);

Quote
var LineStart, LineEnd, ColumnStart, ColumnEnd;
ActiveView.GetSelection(LineStart, LineEnd, ColumnStart, ColumnEnd);
Yes. In all places where before points were used.

HE will not provide all kinds of functions. Because this set will be unlimited and every user will want something different to simplify his life.
HE will only provide low level functions. But the user can create his own helper functions, wrapping HE functions and put them into include, for reuse. This is how it is designed. And the good thing that one can refer to js functions from js include in vb script for example. We can think about some generic include with such helper functions, that HE can pre-install. As example check include.js attached to post and used in scripting.hejs.

Title: Re: 1.50: scripting first test
Post by: Stefan on August 26, 2011, 11:14:35 AM
Hi Alex, if you find some time please take an look:


I have only provide you example function you can use.
To get selected text you need something like this:

Alex> "Create a tool, taking script path into command window. It should work as normal tool, and called tool script."

When i execute this script via an tool at an document, HE jumps to the script and shows the red arrow:
[attach=1]

What did i wrong?
Title: Re: 1.50: scripting first test
Post by: alex on August 26, 2011, 02:25:28 PM
Hi Stefan,

you did everything right. This is exactly the problem I have described before: var ptStart, and ptEnd should be structures of type POINT_T, but the problem is that scripting languages do not understand structures (but for plugins this was not a problem). So I was forced to updated signatures to use or expanded version with 4 variables for all positions (startline, startpos, endline, endpos) instead of two (pointStart, pointEnd), or as it will be to use objects instead of structures there. And this way will be published in new beta soon.

I have removed GetSelection method and instead provided object, that represents range, smt like this:
Code: Javascript
  1. var selection = ActiveView.Selection;
  2. selection.start.line
  3. selection.start.pos
  4. selection.Width
  5. selection.Height
  6. selection.Left
  7.  

There will be two new objects: Range and Position, which will be passed to and read from API. The only disadvantage, you need an extra call, if you like to create such object for passing it to API:
Code: Javascript
  1. var selection = CreateRange(nStartLine, nStartPos, nEndLine, nEndPos);
  2. var position1 = CreatePosition(nLine, nPos);
  3. position1.line = 2;
  4. position1.pos = 0;
  5. var position2 = CreatePosition(nLine2, nPos2);
  6. var range2 = CreateRangeEx(position1, position1);
  7.  

Will try to update alpha on Monday. BTW, the solution now is very similar that you have suggested with info object.
Another new thing which will come also with new update is WScript emulation: it will be possible to start scripts written for WSH inside of HE without any modification, because HE emulates WScript object by itself. Of course will be some limitations, but maybe I will cover them with time. Such approach with emulation will minimize jump-in time for people with experience in WScript.

BR, Alex
Title: Re: 1.50: scripting first test
Post by: Stefan on September 01, 2011, 11:21:14 AM
Hi Alex, thanks for the update!

Are you ready for feedback... or it is to early to report malfunctions?



1.50.721  on XP SP3

1.)
Code: Javascript
  1. edit-2011-08-31.hejs
  2.  
  3. Got the yellow tool tip, but then
  4. "Schwerwiegender Fehler"
  5. ==> ActiveView.Select(sel);
  6.  
  7. or
  8.  
  9. Got the yellow tool tip,
  10. got output in output pane, but then
  11. "HE_ACTION_UNKNOWN is undefined"
  12. ==>ActiveDocument.ReplaceText(sel.start, "New Text", sel.end, HE_ACTION_UNKNOWN);

<EDIT
Alex> but excluding start/end of line
I had read/thought "start/end of FILE", sorry.
Now if i take your advice it works better.
But get still: "HE_ACTION_UNKNOWN is undefined"
</EDIT




2.)
Code: Javascript
  1. dialog_actions-2011-08-31.hejs
  2. "eMessageTypeInfo is undefined"
  3. ==>status("Result code: " + result, eMessageTypeInfo);



3.)
dialog_test-2011-08-31.hejs seams to work fine.


4.)
wscript_test.js
executing ends HE
Title: Re: 1.50: scripting first test
Post by: alex on September 01, 2011, 02:44:22 PM
Hi Stefan,

main problem that you have not installed but only unpack binaries. Now installer also register type library and this step is missing, if you do not run it.
But generally you can achieve the same, if you will run Hippoedit.exe /Register  . This is a reason for "undefined" errors.

Problem with select comes because you call engine with invalid range. Maybe I will add some more meaningful error description in the future.
I have not add any error check in the example script, so if you decrease by one or increase by one selection range and goes out of line size of document size you will get it. For testing, just select some text in between of the line, before execution.

Crash with wscript_test.js I also reproduced.. Something strange, in debug was working. But I will fix it, should not be something serious. Just try the same, but with commented Quit (it cause the crash) to see the idea.
Added: It is very funny, but I am not able to reproduce this any more.. By me works. As release as debug. But probably there is something wrong...


You can also check updated dialog_actions.hejs for color_browser and font_browser.

BR, Alex.
Title: Re: 1.50: scripting first test
Post by: Stefan on September 01, 2011, 03:38:36 PM
Hi Stefan,

main problem that you have not installed but only unpack binaries. Now installer also register type library and this step is missing, if you do not run it.
But generally you can achieve the same, if you will run Hippoedit.exe /Register  . This is a reason for "undefined" errors.

Ah, i see.
I do install 1.50 builds, but i work with limited user rights, of course ;-)
<edit to clarify> i have installed to X:\, where i have write access. (To "C:\Pro Fi" i wouldn't) - But i had still no write access to HKLM. </edit>
Anyway. runas /u:administrator "Hippoedit.exe /Register" did it. Much better now.


Quote
Problem with select comes because you call engine with invalid range. Maybe I will add some more meaningful error description in the future.
I have not add any error check in the example script, so if you decrease by one or increase by one selection range and goes out of line size of document size you will get it. For testing, just select some text in between of the line, before execution.
Yes you are right. Works.

Quote
Crash with wscript_test.js I also reproduced.. Something strange, in debug was working. But I will fix it, should not be something serious. Just try the same, but with commented Quit (it cause the crash) to see the idea.
Added: It is very funny, but I am not able to reproduce this any more.. By me works. As release as debug. But probably there is something wrong...
//WScript.Quit();
But still the same here. (as limited user)
But no matter for me. I have other things to check out.
<edit> Not related to limited user, the same with runas /u:Admin HE </edit>


Quote
You can also check updated dialog_actions.hejs for color_browser and font_browser.
Yes, have seen and used. Now i need to use that choice to do smtg. e.g.  alert me the choice taken...
I also have seen things like "ActiveDocument.BeginUndoGroup();", ... you have did much work for that 1.5 build it seams...


Now I going to see if I can take an selection, modify it and write back,... i think i had seen smtg in your example code to reuse...
Title: Remove Empty Lines
Post by: alex on September 11, 2011, 05:23:33 AM
This is and example of first useful script which deletes empty lines from whole document or selection.
Script can be added as tool (select remove_empty_lines.hejs).


edit_helpers.hejs
Code: Javascript
  1. ////////////////////////////////////////////////////////////////////////
  2. // Helper function to check, if text contains only white space
  3. // characters or empty
  4. // sText - string to be checked
  5. // result - true, if text, contains only white space
  6. function isWhiteText(sText)
  7. {
  8.         var bWhiteSpace = true;
  9.         for (var i = 0; i < sText.length && bWhiteSpace; ++i)
  10.         {
  11.                 var c = sText.charAt(i);
  12.                 bWhiteSpace = c == " " || c == "\t";
  13.         }
  14.         return bWhiteSpace;
  15. }
  16.  
  17. ////////////////////////////////////////////////////////////////////////
  18. // Helper function to check if line contain only white space
  19. // doc    - document object
  20. // nLine  - line index to be checked
  21. // result - true, if line, contains only white space
  22. function isEmptyLine(doc, nLine)
  23. {
  24.         return isWhiteText(doc.GetLine(nLine));
  25. }
  26.  
  27. ////////////////////////////////////////////////////////////////////////
  28. // Often, selection ends up in 0 char of next line,
  29. // when we want to work only with lines above
  30. // but algorithms do not know that, so we help them by
  31. // correcting bottom bound of the range
  32. // doc            - document object
  33. // selRange   - range to be adjusted
  34. function AdjustSelection(doc, selRange)
  35. {
  36.         if ( selRange.Height > 0 && selRange.Right == 0)
  37.                 doc.MovePositionLine(selRange.end, -1);
  38.  
  39.         return selRange;
  40. }
  41.  

remove_empty_lines.hejs
Code: Javascript
  1. #include "edit_helpers.hejs"    // generic he edit helper functions
  2.  
  3. // if there is no active view, exit
  4. if ( ActiveView != null )
  5. {
  6.         // first get current selection
  7.         var sel = ActiveView.Selection;
  8.  
  9.         // if nothing is selected, let us assume, that whole document should be processed
  10.         if ( sel.IsEmpty )
  11.         {
  12.                 sel.Top          = 0;
  13.                 sel.Bottom   = ActiveDocument.LineCount - 1;
  14.         }
  15.         else
  16.         {
  17.                 AdjustSelection(ActiveDocument, sel);
  18.         }
  19.  
  20.         var nUndoActionType = AddUndoActionType("Remove Empty Lines");
  21.  
  22.         // start UndoGroup to be able to Undo all at once
  23.         ActiveDocument.BeginUndoGroup();  
  24.  
  25.         var nDeleted = 0;  
  26.         var nLineStart = sel.Top, nLineEnd = sel.Bottom;  
  27.         for (i = nLineStart; i <= nLineEnd;)
  28.         {
  29.                 if ( isEmptyLine(ActiveDocument, i) )
  30.                 {
  31.                         var rgDelete = CreateRange(i, 0, i + 1, 0);
  32.                         if ( i == ActiveDocument.LineCount - 1 )
  33.                         {
  34.                                 ActiveDocument.MovePositionLine(rgDelete.start, -1);
  35.                                 rgDelete.end = rgDelete.start;
  36.                                 ActiveDocument.MovePositionLine(rgDelete.end, 1);
  37.                         }
  38.  
  39.                         if ( !rgDelete.IsEmpty )
  40.                         {
  41.                                 ActiveDocument.DeleteText(rgDelete, nUndoActionType);
  42.                                 ++nDeleted;
  43.                         }
  44.                         --nLineEnd;
  45.                 }
  46.                 else
  47.                 {
  48.                         ++i;
  49.                 }
  50.         }
  51.  
  52.         ActiveDocument.FlushUndoGroup();
  53.  
  54.         status(nDeleted + " empty lines have been deleted", eMessageTypeInfo);
  55. }
  56. else
  57. {
  58.         status("There is no document selected", eMessageTypeError);
  59. }
  60.