Script to autocomplete language-specific templates

Script to autocomplete language-specific templates

3

    Apr 29, 2008#1

    One of the few areas where UE is sub-par (IMHO) is the lack of automatic language-specific templates. This has already been discussed somewhere else (see http://www.ultraedit.com/forums/viewtopic.php?t=1412), so there's no need to go into that.

    Anyway, given UE's scripting capabilities I should be able to DIY this. I have duly written a small script that expands stuff nicely (though it's more a proof of concept). I have put this on the space key as hotkey which means it's called every time I press space. The script itself is fast enough not to make a nuisance of itself but of course now this annoying box to cancel the script flashes up all the time. Does anyone know of a way how to disable this box? (I know I can do that for macros so it seems not too far-fetched an idea to have this for scripts as well.)

    I am having a second, more fundamental problem with that script. The template to be expanded is written with UltraEdit.activeDocument.write(). Unfortunately, this function, if handed a multi-line string, will not perform any auto-indenting. Any hints how to achieve this?

    Here's my attempt (pared-down to the bare minimum) so far. (The spaces written in various places are there because I have put the script on the space key as hotkey, so whenever no template is expanded a space is written instead.)

    I am not a JavaScript guy, so general hints as to how to make this better/faster are welcome as well.

    Code: Select all

    var d=UltraEdit.activeDocument,
    exp_C={
    	'if':'if (!!) {\n}\nelse {\n}',
    	'for':'for (!!;;) {\n}'
    };
    
    function writeExp(exp,l,c) {
    	if (typeof(exp)==='undefined') { // no template, write space
    		d.gotoLine(l,c);
    		d.write(' ');
    	}
    	else { // template, write it
    		d.write(exp);
    		d.gotoLine(l,c);
    		d.findReplace.find("!!");
    	}
    }
    
    function getWordLeft() {
    	d.startSelect();
    	d.key('CTRL+LEFT ARROW');
    	d.endSelect();
    	return d.selection;
    }
    
    function isCFile() {
    	return d.isExt('c')||d.isExt('cpp')||d.isExt('h');
    }
    
    var l=d.currentLineNum,c=d.currentColumnNum;
    if (typeof(UltraEdit.activeDocumentIdx) == "undefined") c++;
    if (d.isSel()||c===1||d.isChar(' ')) d.write(' '); // can't be a template
    else if (isCFile()) writeExp(exp_C[getWordLeft()],l,c);
    //else if (isPerlFile()) writeExp(exp_Perl[getWordLeft()],l,c)
    else d.write(' '); // no source file, no template

    6,683585
    Grand MasterGrand Master
    6,683585

      May 01, 2008#2

      The box to cancel the execution of a script can be currently not disabled. There is not setting or command for it.

      A possible method to keep indentation when inserting a multi-line string would be to use the commands to get the current line and column number into variables.

      Then move the cursor in the current line to start of this line and check if it starts with a space or a tab. If this is the case, use UltraEdit.activeDocument.selectWord(); to select it and save the selection into a variable (works only for ASCII/ANSI files) or copy it to a user clipboard (works for all files). Well, it is possible that the cursor is on script execution at end of the file or it is already at start of a blank line. In this case you need to go 1 line up (if possible - line number greater than 1) and get or copy the white-space characters at start of that line if there are white-space characters at start of this line.

      Now go back to the initial position saved first into the 2 variables and insert here your multi-line template string. But for every \n in the multi-line string you have to insert or paste the white-spaces you get or copied before. Another method would be to first simply insert the multi-line template string and then reselect the just inserted string by using for example UltraEdit.activeDocument.gotoLineSelect(InitialLineNumber, InitialColumnNumber); and run a regular expression replace to insert at start of every selected line the white-spaces string you get or copied before.
      Best regards from an UC/UE/UES for Windows user from Austria

      3

        May 02, 2008#3

        The box to cancel the execution of a script can be currently not disabled. There is not setting or command for it.
        Well, this seems to be one of quite a few inconsistencies in UE. Another such inconsistency I just stumbled across is that opening a file from the list of recently opened files doesn't execute an autoload macro whereas opening the same file normally does. Sigh.
        A possible method to keep indentation when inserting a multi-line string would be ...
        Yeah, I had already thought of something along these lines but I was hoping there's a less "kludgy" way.

        I can't for the life of me understand why this rigmarole to auto-expand language-specific templates should be necessary in the first place, given that UE is otherwise a pretty complete editor. Probably not enough people need (or want) this feature.

          May 07, 2008#4

          I've reworked the script and it works well enough now -- the most annoying problem now being that silly cancel dialog box which pops up whenever the script's run (which in my case is on every space key pressing). Well, a future version of UE might get rid of this.

          Comments or hints so as to make it faster?

          Code: Select all

          var d=UltraEdit.activeDocument,
          exp_C={
          	'do':'do {#\t^#} while ();',  // ^ insertion point; # newline+indent
          	'if':'if (^) {#}#else {#}',
          	'for':'for (^;;) {#}',
          	'switch':'switch (^) {#case :#\tbreak;#default:#\tbreak;#}',
          	'while':'while (^) {#}',
          },
          lbrk='\n';  // I use UNIX-style line breaks; change accordingly
          
          function writeExp(exp) {
          	if (typeof(exp)=='undefined') {  // no expansion found, write space
          		d.key('CTRL+RIGHT ARROW');
          		d.write(' ');
          	}
          	else {
          		var ind=lbrk,c=d.currentColumnNum,l=d.currentLineNum;
                                 if (typeof(UltraEdit.activeDocumentIdx) == "undefined") c++;
          		d.deleteText();
          		d.gotoLine(0,1);
          		if (d.isChar('\t')||d.isChar(' ')) {  // grab indent, if any
          			d.startSelect();
          			d.key('CTRL+RIGHT ARROW');
          			d.endSelect();
          			ind+=d.selection;
          		}
          		d.gotoLine(0,c);
          		d.write(exp.replace(/#/g,ind));  // replace # with newline+indent and insert
          		d.gotoLine(l,c);
          		d.findReplace.find('^');  // finally jump to target pos
          	}
          }
          
          function getWordLeft() {  // works better than .selectWord()
          	d.startSelect();
          	d.key('CTRL+LEFT ARROW');
          	d.endSelect();
          	return d.selection;
          }
          
          function isCFile() {  // true if extension suggests C file, change accordingly
          	return d.isExt('c')||d.isExt('cpp')||d.isExt('h');
          }
          
          // expansion is triggered only on end of line or end of file
          if (!d.isSel()&&(d.isChar('\r')||d.isChar('\n')||d.isEof())) {
          	if (isCFile()) writeExp(exp_C[getWordLeft()]);
          	//else if (isPerlFile()) writeExp(exp_Perl[getWordLeft()])
          	else d.write(' ');
          }
          else d.write(' ');