home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 16 / 16.iso / w / w055 / 4.ddi / SOURCES.LIF / ELECTRIC.PEL < prev    next >
Encoding:
Text File  |  1990-09-27  |  34.9 KB  |  1,112 lines

  1. # $Header:   P:/source/ppee/macros/electric.pev   1.65   24 Sep 1990 17:35:08   skipr  $
  2.  
  3. ##############################################################################
  4. #
  5. #           Sage Software - POLYTRON Division
  6. #             1700 NW 167th Place
  7. #               Beaverton, OR 97006
  8. #
  9. #   Copyright 1990, Sage Software, Inc.
  10. #
  11. #   Permission is hereby granted for licensed users of Sage Professional
  12. #   Editor and PolyAwk to copy and modify this source code for their own
  13. #   personal use.  These derivative works may be distributed only to other
  14. #   licensed Sage Professional Editor and PolyAwk users.  All other usage
  15. #   is prohibited without express written permission from Sage Software.
  16. #
  17. ##############################################################################
  18.  
  19. #### $Workfile:   electric.pel  $: helper routines for entering C code
  20. #
  21. #    There are three principal facilities in this package:
  22. #    1. Insertion of code templates
  23. #        (see "function initialized_template()" in this module
  24. #         on how to add new templates)
  25. #    2. Bracket matching (several flavors)
  26. #    3. Auto-indentation
  27. #
  28.  
  29. #
  30. #    Clipper Support and general improvements made to this module
  31. #    have be provided by P. Polakoff III, 3P Software, Inc.
  32. #
  33.  
  34. ### "electric" templates program-entry features.
  35. #
  36. #    The template entry facility works differently than some other
  37. #    products' in that templates are inserted only upon demand, and
  38. #    not automatically upon recognition of an abbreviation.
  39. #
  40. #    Templates are auto-indented independently of the autoindent mode.
  41. #
  42. #    Template insertion is activated manually by a keypress.  The 
  43. #    definition of ESCAPE may be freely changed from the ESC key to 
  44. #    SPACE or any other key. 
  45. #
  46. #    The mode may be turned on and off by calls to ec() or 
  47. #    toggle_electric(). It additionally is enabled or disabled depending 
  48. #    on whether the extension on the current buffer's name matches one of 
  49. #    the patterns in the expand template list.
  50. #
  51. #    Internally the mode is turned on, so it is sufficient for keymaps
  52. #    merely to bind the associated functions to keys.
  53. #
  54. #    Multiple-character abbreviation sequences are allowed.
  55. #
  56. #    Bug: mark_matching() highlights only the first char of the 
  57. #    destination of multi-char brackets.  It should highlight the entire
  58. #    keyword (or optionally only the enclosed text).
  59. #
  60. #    This eventually needs to be generalized so that different extensions
  61. #    cause different templates to be enabled.
  62. #
  63. #    We probably should default electric and auto-indent modes to ON.
  64. #
  65.  
  66. global    language_template     # the map of abbreviations onto expanded strings
  67. global    electric_extensions = "" # current language template entensions
  68. global    file_extensions
  69. global    extensions_initialized = 0;
  70.  
  71. global    D_DIALECT = "clipper87"    # dBASE dialect (used by errorfix.pel also)
  72. global    ELEC_LANG = "text"    # current electric language
  73.  
  74. global    electric_mode = 0    # 0 = disabled, 1 = enabled
  75. local    initialized_file_ext;    # specifies the last extension used when 
  76.                 # initialized_template() was called.
  77. local    newEditFileId;
  78.  
  79.  
  80. #
  81. # Addition of new templates:
  82. #  --------------------------
  83. # Add a new element to the file_extensions[] array and initialize it
  84. # with the associated extensions as demonstrated below.  Then add
  85. # the new electric array as defined in initialize_template() below.
  86. #
  87.  
  88. # Possible file extents for each language.  Each is a regular expression
  89. # to match the buffer's filename extension.
  90. #
  91. # "electric_extensions" takes on one of these values initialized in
  92. # initialize_extensions().
  93. #
  94.  
  95. function initialize_extensions() {
  96.   delete(file_extensions)
  97.   file_extensions["text"]="\\.txt$|\\.doc$"
  98.   file_extensions["c"] = "\\.c$|\\.h$|\\.awk$|\\.cpp$|\\.pel$"
  99.   file_extensions["dbase"]= "\\.prg$|\\.gen$|\\.cod$|\\.gtl$|\\.tlb$|\\.tem$"
  100.   file_extensions["clipper87"]="\\.prg$|\\.pre$|\\.gen$|\\.cod$|\\.gtl$|\\.tlb$|\\.tem$"
  101.   file_extensions["clipper50"]="\\.prg$|\\.ch$|\\.ppo$|\\.gen$|\\.cod$|\\.gtl$|\\.tlb$|\\.tem$"
  102.   file_extensions["force"]="\\.prg$|\\.hdr$"
  103.   file_extensions["pascal"]= "\\.pas$"
  104.   file_extensions["basic"]= "\\.bas$"
  105.   file_extensions["asm"]= "\\.asm$|\\.mac$|\\.inc$"
  106.   extensions_initialized = 1;
  107. }
  108.  
  109.  
  110.  
  111. ## ec()
  112. #
  113. #  enable/display template generation ( 0 = disable, 1 = enable );
  114. #
  115. function ec( mode ){
  116.     if (argcount())
  117.         toggle_electric( mode );
  118.     else
  119.         toggle_electric()
  120. }
  121.  
  122. ## toggle_electric()
  123. #
  124. #  enable/display template generation ( 0 = disable, 1 = enable );
  125. #
  126. function toggle_electric( selection ){
  127.     local verbose = 0
  128.  
  129.     if( argcount() < 1 ){
  130.         selection = !electric_mode
  131.         verbose = 1
  132.     }
  133.  
  134.     electric_mode = selection
  135.  
  136.  
  137.     if (electric_mode) {
  138.         if (!newEditFileId) {
  139.             newEditFileId = function_id( "electric_edit_file" );
  140.             attach_event_handler( EVENT_NEW_EDIT_FILE, newEditFileId );
  141.         }
  142.         electric_edit_file();
  143.     } else {
  144.         if (newEditFileId) {
  145.             delete_event( EVENT_NEW_EDIT_FILE, newEditFileId );
  146.             newEditFileId = 0;
  147.         }
  148.     }
  149.  
  150.  
  151.     if( verbose )
  152.         message( electric_mode                 \
  153.                 ? "Electric-C enabled"         \
  154.                 : "Electric-C disabled" )
  155. }
  156.  
  157. ## initialize_template()
  158. #
  159. #  Initialize the correct template for the language being used.
  160. #  The language is determined by the extension of the current buffer's
  161. #  name.  If the template has already been initialized, it is ignored.
  162. #
  163. #  Addition of new templates:
  164. #  --------------------------
  165. #  To add a new template, create a new element in the file_extensions
  166. #  array defined in initialize_extensions() above.
  167. #
  168. #  Next, duplicate one of the if-else statements below and change the
  169. #  language_template[] settings appropriately.  Also, be sure the comparison
  170. #  with "_extensions" (your new variable name) is updated as well.
  171. #
  172. local function initialize_template(){
  173.  
  174.  
  175.     if ( path_ext(buffer_name) == initialized_file_ext )
  176.         return;
  177.     else
  178.         initialized_file_ext = path_ext( buffer_name );
  179.  
  180.     if ( !extensions_initialized )
  181.         initialize_extensions();
  182.  
  183.     if ( buffer_name ~ file_extensions["c"] ){
  184.         ## Microsoft C5.1 compatible templates
  185.  
  186.         if ( electric_extensions == file_extensions["c"] )
  187.             return;
  188.  
  189.         delete( language_template );    # delete last template and start over
  190.         electric_extensions = file_extensions["c"]
  191.  
  192.  
  193.         language_template[ "{" ] = "{\n\t@\n}"        # }
  194.         language_template[ "(" ] = "( @ )"
  195.         language_template[ "[" ] = "[ @ ]"
  196.         language_template[ "/" ] = "/* @ */"
  197.         language_template[ "*" ] = "/*\n** @\n*/"
  198.         language_template[ "#i" ] = "#include <@>"
  199.         language_template[ "#d" ] = "#define @"
  200.         language_template[ "#p" ] = "#pragma @"
  201.         language_template[ "#u" ] = "#undef @"
  202.         language_template[ "ac" ] = "access(\"@\",);"
  203.         language_template[ "ca" ] = "case @: "
  204.         language_template[ "cl" ] = "close(@);"
  205.         language_template[ "do" ] = "do {\n\t@\n} while();"
  206.         language_template[ "if" ] = "if(@){\n\t\n}"
  207.         language_template[ "ie" ] = "if(@){\n\t\n} else {\n\t\n}"
  208.         language_template[ "el" ] = "else {\n\t@\n}"
  209.         language_template[ "fo" ] = "for(@;;){\n\t\n}"
  210.         language_template[ "fs" ] = "fscanf(@,\"\");"
  211.         language_template[ "fp" ] = "fprintf(@,\"\",);"
  212.         language_template[ "fr" ] = "fread(@,,);"
  213.         language_template[ "ft" ] = "ftell(@);"
  214.         language_template[ "fw" ] = "fwrite(@,,);"
  215.         language_template[ "gc" ] = "getc(@);"
  216.         language_template[ "gh" ] = "getchar();"
  217.         language_template[ "gs" ] = "gets(@);"
  218.         language_template[ "gw" ] = "getw(@);"
  219.         language_template[ "wh" ] = "while(@){\n\t\n}"
  220.         language_template[ "sw" ] = "switch(@){\n\tcase : \ndefault: \n\b}"
  221.         language_template[ "ts" ] = "typedef struct @ {\n  \n}"
  222.         language_template[ "ty" ] = "typedef @"
  223.         language_template[ "pc" ] = "putc(@,);"
  224.         language_template[ "ph" ] = "putchar(@);"
  225.         language_template[ "pr" ] = "printf(\"@\",);"
  226.         language_template[ "ps" ] = "puts(\"@\");"
  227.         language_template[ "pw" ] = "putw(@,);"
  228.         language_template[ "sc" ] = "scanf(@,\"\",);"
  229.         language_template[ "ss" ] = "sscanf(@,\"\",);"
  230.         language_template[ "sp" ] = "sprintf(@,\"\",);"
  231.         language_template[ "fu" ] = "function @ (){\n  \n}"
  232.         language_template[ "vf" ] = "vfprintf(@,\"\",);"
  233.         language_template[ "vp" ] = "vprintf(\"@\",);"
  234.         language_template[ "vs" ] = "vsprintf(@,\"\",);"
  235.         language_template[ "op" ] = "open(\"@\",,);"
  236.         language_template[ "re" ] = "read(@,,);"
  237.         language_template[ "rn" ] = "rename(\"@\",\"\");"
  238.         language_template[ "wr" ] = "write(@,,);"
  239.         language_template[ "ls" ] = "lseek(@,,SEEK_);"
  240.         language_template[ "_s" ] = "_splitpath(@,,,,);"
  241.         language_template[ "_m" ] = "_makepath(@,,,,);"
  242.         language_template[ "un" ] = "unlink(\"@\");"
  243.         language_template[ "ma" ] = "malloc(@);"
  244.         language_template[ "fe" ] = "free(@);"
  245.         language_template[ "st" ] = "static @;"
  246.  
  247.     } else if ( (buffer_name ~ file_extensions["dbase"])        \
  248.          || (buffer_name ~ file_extensions["clipper87"])    \
  249.          || (buffer_name ~ file_extensions["clipper50"])    \
  250.          || (buffer_name ~ file_extensions["force"]) ){
  251.  
  252.         if( (electric_extensions == file_extensions["dbase"])        \
  253.          || (electric_extensions == file_extensions["clipper87"])    \
  254.          || (electric_extensions == file_extensions["clipper50"])    \
  255.          || (electric_extensions == file_extensions["force"]) )
  256.             return;
  257.  
  258.         delete(language_template);    # delete last template and start over
  259.         dBaseDialect()
  260.         electric_extensions = file_extensions[ELEC_LANG]
  261.         if ( ELEC_LANG == "clipper87" ) {
  262.           language_template[ "(" ] = "(@)"
  263.           language_template[ "[" ] = "[@]"
  264.           language_template[ "*" ] = "***\n*** @\n***"
  265.           language_template[ "&" ] = "\t\t&& @"
  266.           language_template[ "#i" ] = "#include @"
  267.           language_template[ "#d" ] = "#define @"
  268.           language_template[ "ii" ] = "iif((@),,)"
  269.           language_template[ "if" ] = "if(@)\n\t\nendif"
  270.           language_template[ "ie" ] = "if(@)\n\t\nelse\n\t\nendif"
  271.           language_template[ "fo" ] = "for @\n\t\nnext"
  272.           language_template[ "ca" ] = "do case\n\tcase @\n\t\notherwise\n\t\n\b\bendcase"
  273.           language_template[ "el" ] = "else\n\t@"
  274.           language_template[ "ef" ] = "elseif(@)\n\t"
  275.           language_template[ "en" ] = "endif"
  276.           language_template[ "wh" ] = "do while (@)\n\t\nenddo"
  277.           language_template[ "do" ] = "do @ with "
  278.           language_template[ "be" ] = "begin sequence\n\t@\nend"
  279.           language_template[ "pr" ] = "procedure @\nparameters\n\t\nreturn"
  280.           language_template[ "fu" ] = "function @\nparameters\n\t\nreturn('')"
  281.           language_template[ "le" ] = "len(@)"
  282.           language_template[ "tr" ] = "trim(@)"
  283.           language_template[ "us" ] = "use @ "
  284.           language_template[ "in" ] = "index @"
  285.           language_template[ "al" ] = "alias @"
  286.           language_template[ "cl" ] = "clear @"
  287.           language_template[ "co" ] = "copy to @ fields  for  while "
  288.           language_template[ "pv" ] = "private @"
  289.           language_template[ "gt" ] = "go top"
  290.           language_template[ "gb" ] = "go bottom"
  291.           language_template[ "pu" ] = "public @"
  292.           language_template[ "de" ] = "delete @ for  while "
  293.           language_template[ "se" ] = "select @"
  294.           language_template[ "as" ] = "asc(@)"
  295.           language_template[ "ch" ] = "chr(@)"
  296.           language_template[ "at" ] = "at(@,)"
  297.           language_template[ "ct" ] = "ctod(@)"
  298.           language_template[ "dc" ] = "dtoc(@)"
  299.           language_template[ "cm" ] = "cmonth(@)"
  300.           language_template[ "dt" ] = "date()"
  301.           language_template[ "da" ] = "day(@)"
  302.           language_template[ "bf" ] = "bof()"
  303.           language_template[ "ef" ] = "eof()"
  304.           language_template[ "ds" ] = "dtos(@)"
  305.           language_template[ "lo" ] = "lower(@)"
  306.           language_template[ "up" ] = "upper(@)"
  307.           language_template[ "mi" ] = "min(@,)"
  308.           language_template[ "ma" ] = "max(@,)"
  309.           language_template[ "mo" ] = "month(@)"
  310.           language_template[ "yr" ] = "year(@)"
  311.           language_template[ "pc" ] = "pcount() = @"
  312.           language_template[ "ra" ] = "rat(@,)"
  313.           language_template[ "ss" ] = "save screen to @"
  314.           language_template[ "rs" ] = "restore screen from @"
  315.           language_template[ "tf" ] = "transform(@,)"
  316.           language_template[ "su" ] = "substr(@,,)"
  317.           language_template[ "sp" ] = "space(@)"
  318.           language_template[ "re" ] = "replicate(@,)"
  319.           language_template[ "rp" ] = "replace @"
  320.           language_template[ "va" ] = "val(@)"
  321.           language_template[ "pi" ] = "picture @"
  322.           language_template[ "vl" ] = "valid(@)"
  323.         } else if ( ELEC_LANG == "clipper50" ) {
  324.           language_template[ "{" ] = "{@}"
  325.           language_template[ "(" ] = "(@)"
  326.           language_template[ "[" ] = "[@]"
  327.           language_template[ "*" ] = "/*\n** @\n*/"
  328.           language_template[ "/" ] = "// @"
  329.           language_template[ "&" ] = "\t\t// @"
  330.           language_template[ "@" ] = "DevPos(@,)"
  331.           language_template[ "?" ] = "QOut(@)"
  332.           language_template[ "??" ] = "QQOut(@)"
  333.           language_template[ "#i" ] = "#include \"@\""
  334.           language_template[ "#d" ] = "#define @"
  335.           language_template[ "#c" ] = "#command @\t=>\t"
  336.           language_template[ "#t" ] = "#translate @\t=>\t"
  337.           language_template[ "ar" ] = "Array(@)"
  338.           language_template[ "ii" ] = "iif((@),,)"
  339.           language_template[ "if" ] = "if(@)\n\t\nend"
  340.           language_template[ "ie" ] = "if(@)\n\t\nelse\n\t\nend"
  341.           language_template[ "fo" ] = "for @:= to \n\t\nnext"
  342.           language_template[ "ca" ] = "do case\n\tcase @\n\t\notherwise\n\t\n\b\bend"
  343.           language_template[ "el" ] = "else\n\t@"
  344.           language_template[ "ef" ] = "elseif(@)\n\t"
  345.           language_template[ "en" ] = "end"
  346.           language_template[ "wh" ] = "while(@)\n\t\nend"
  347.           language_template[ "be" ] = "begin sequence\n\t@\nend"
  348.           language_template[ "pr" ] = "procedure @\nparameters\n\t\nreturn"
  349.           language_template[ "fu" ] = "function @( )\n\t\nreturn(NIL)"
  350.           language_template[ "le" ] = "len(@)"
  351.           language_template[ "tr" ] = "trim(@)"
  352.           language_template[ "us" ] = "use @ "
  353.           language_template[ "in" ] = "index @"
  354.           language_template[ "al" ] = "alias()"
  355. #############################################################################
  356. # Special Note: The following macro expansions are supplied in two forms.
  357. # The first form is the form preferred by Nantucket for use with Clipper 5.0
  358. # The second form is the translation form as performed by the Clipper 5.0
  359. # preprocessor. It is to the programmer's discretion to choose which of
  360. # these macro sets to utilize, however it should be noted that the use of
  361. # the internal form may not be supported in future Clipper releases.
  362. #############################################################################
  363.           ## Nantucket preferred form
  364.           #language_template[ "cl" ] = "clear"
  365.           #language_template[ "gt" ] = "go top"
  366.           #language_template[ "gb" ] = "go bottom"
  367.           #language_template[ "se" ] = "select @"
  368.           #language_template[ "us" ] = "use @"
  369.           ## Internal form
  370.           language_template[ "cl" ] = "__Clear()"
  371.           language_template[ "gt" ] = "__dbGoTop()"
  372.           language_template[ "gb" ] = "__dbGoBottom()"
  373.           language_template[ "se" ] = "__dbSelect(@)"
  374.           language_template[ "us" ] = "__dbUse(0,NIL,@,,.T.,.F.)"
  375. #############################################################################
  376.           language_template[ "pv" ] = "private @"
  377.           language_template[ "pu" ] = "public @"
  378.           language_template[ "lc" ] = "local @"
  379.           language_template[ "st" ] = "static @"
  380.           language_template[ "as" ] = "asc(@)"
  381.           language_template[ "ch" ] = "chr(@)"
  382.           language_template[ "at" ] = "at(@,)"
  383.           language_template[ "ct" ] = "ctod(@)"
  384.           language_template[ "dc" ] = "dtoc(@)"
  385.           language_template[ "cm" ] = "cmonth(@)"
  386.           language_template[ "dt" ] = "date()"
  387.           language_template[ "da" ] = "day(@)"
  388.           language_template[ "bf" ] = "bof()"
  389.           language_template[ "ef" ] = "eof()"
  390.           language_template[ "ds" ] = "dtos(@)"
  391.           language_template[ "lo" ] = "lower(@)"
  392.           language_template[ "up" ] = "upper(@)"
  393.           language_template[ "mi" ] = "min(@,)"
  394.           language_template[ "ma" ] = "max(@,)"
  395.           language_template[ "mo" ] = "month(@)"
  396.           language_template[ "yr" ] = "year(@)"
  397.           language_template[ "pc" ] = "pcount()==@"
  398.           language_template[ "ra" ] = "rat(@,)"
  399.           language_template[ "ss" ] = "@:=savescreen(0,0,maxrow(),maxcol())"
  400.           language_template[ "rs" ] = "restscreen(0,0,maxrow(),maxcol(),@)"
  401.           language_template[ "tf" ] = "transform(@,)"
  402.           language_template[ "su" ] = "substr(@,,)"
  403.           language_template[ "sp" ] = "space(@)"
  404.           language_template[ "re" ] = "replicate(@,)"
  405.           language_template[ "rp" ] = "FIELD->@:="
  406.           language_template[ "va" ] = "val(@)"
  407.           language_template[ "vt" ] = "valtype(@)"
  408.         } else if ( ELEC_LANG == "force" ) {
  409.           language_template[ "#i" ] = "#include @"
  410.           language_template[ "#d" ] = "#define @"
  411.           language_template[ "*" ]  = "**\n**\t@\n**"
  412.           language_template[ "dd" ] = "DBFDEF @\n\t\nENDDEF"
  413.           language_template[ "vd" ] = "VARDEF\n\t@\nENDDEF"
  414.           language_template[ "id" ] = "INDEXDEF\n\t@\nENDDEF"
  415.           language_template[ "rd" ] = "REPORTDEF @\n\t\nENDDEF"
  416.           language_template[ "ld" ] = "LABELDEF @\n\t\nENDDEF"
  417.           language_template[ "gd" ] = "GROUPDEF\n\t\nENDDEF"
  418.           language_template[ "sg" ] = "SUBGROUPDEF\n\t\nENDDEF"
  419.           language_template[ "cd" ] = "COLUMNDEF\n\t\nENDDEF"
  420.           language_template[ "if" ] = "IF(@)\n\t\nENDIF"
  421.           language_template[ "ie" ] = "IF(@)\n\t\nELSE\n\t\nENDIF"
  422.           language_template[ "ca" ] = "DO CASE\n\tCASE @\n\t\nOTHERWISE\n\t\n\b\bENDCASE"
  423.           language_template[ "el" ] = "ELSE\n\t@"
  424.           language_template[ "en" ] = "ENDIF"
  425.           language_template[ "wh" ] = "DO WHILE (@)\n\t\nENDDO"
  426.           language_template[ "do" ] = "DO @ WITH "
  427.           language_template[ "fu" ] = "FUNCTION @\nPARAMETERS\n\t\nENDPRO"
  428.           language_template[ "pr" ] = "PROCEDURE @\nPARAMETERS\n\t\nENDPRO"
  429.           language_template[ "fm" ] = "FORMAT @\n\tENDPRO"
  430.           language_template[ "ru" ] = "REPEAT\n\t@\nUNTIL"
  431.           language_template[ "le" ] = "len(@)"
  432.           language_template[ "lo" ] = "locate @"
  433.           language_template[ "tr" ] = "trim(@)"
  434.           language_template[ "us" ] = "USE @ "
  435.           language_template[ "in" ] = "INDEX @"
  436.           language_template[ "cl" ] = "CLEAR @"
  437.           language_template[ "co" ] = "COPY TO @"
  438.           language_template[ "gt" ] = "GOTO TOP"
  439.           language_template[ "gb" ] = "GOTO BOTTOM"
  440.           language_template[ "de" ] = "DELETE @"
  441.           language_template[ "se" ] = "SET @"
  442.           language_template[ "as" ] = "asc(@)"
  443.           language_template[ "ch" ] = "chr(@)"
  444.           language_template[ "at" ] = "at(@,)"
  445.           language_template[ "ct" ] = "ctod(@)"
  446.           language_template[ "dc" ] = "dtoc(@)"
  447.           language_template[ "cm" ] = "cmonth(@)"
  448.           language_template[ "da" ] = "day(@)"
  449.           language_template[ "bf" ] = "bof()"
  450.           language_template[ "ef" ] = "eof()"
  451.           language_template[ "lo" ] = "lower(@)"
  452.           language_template[ "up" ] = "upper(@)"
  453.           language_template[ "mo" ] = "month(@)"
  454.           language_template[ "yr" ] = "year(@)"
  455.           language_template[ "ra" ] = "rat(@,)"
  456.           language_template[ "ss" ] = "savescrn(@,,,)"
  457.           language_template[ "rs" ] = "restorescrn(@)"
  458.           language_template[ "su" ] = "substr(@,,)"
  459.           language_template[ "st" ] = "stuff(@)"
  460.           language_template[ "re" ] = "replicate(@,)"
  461.           language_template[ "rp" ] = "replace @"
  462.           language_template[ "va" ] = "val(@)"
  463.           language_template[ "pi" ] = "picture @"
  464.         } else {
  465.           language_template[ "(" ] = "(@)"
  466.           language_template[ "[" ] = "[@]"
  467.           language_template[ "*" ] = "**\n**\t@\n**"
  468.           language_template[ "&" ] = "\t\t&& @"
  469.           language_template[ "ii" ] = "IIF((@),,)"
  470.           language_template[ "if" ] = "IF(@)\n\t\nENDIF"
  471.           language_template[ "ie" ] = "IF(@)\n\t\nELSE\n\t\nENDIF"
  472.           language_template[ "ca" ] = "DO CASE\n\tCASE @\n\t\nOTHERWISE\n  \n\b\bENDCASE"
  473.           language_template[ "el" ] = "ELSE\n\t@"
  474.           language_template[ "en" ] = "ENDIF"
  475.           language_template[ "wh" ] = "DO WHILE (@)\n\t\nENDDO"
  476.           language_template[ "do" ] = "DO @ WITH "
  477.           language_template[ "pr" ] = "PROCEDURE @\nPARAMETERS\n\t\nRETURN"
  478.           language_template[ "fu" ] = "FUNCTION @\nPARAMETERS\n\t\nRETURN( )"
  479.           language_template[ "le" ] = "LEN(@)"
  480.           language_template[ "lo" ] = "LOCATE @"
  481.           language_template[ "tr" ] = "TRIM(@)"
  482.           language_template[ "us" ] = "USE @ "
  483.           language_template[ "in" ] = "INDEX @"
  484.           language_template[ "al" ] = "ALIAS @"
  485.           language_template[ "cl" ] = "CLEAR @"
  486.           language_template[ "co" ] = "COPY TO @"
  487.           language_template[ "pv" ] = "PRIVATE @"
  488.           language_template[ "gt" ] = "GO TOP"
  489.           language_template[ "gb" ] = "GO BOTTOM"
  490.           language_template[ "pu" ] = "PUBLIC @"
  491.           language_template[ "de" ] = "DELETE @"
  492.           language_template[ "se" ] = "SELECT @"
  493.           language_template[ "as" ] = "ASC(@)"
  494.           language_template[ "ch" ] = "CHR(@)"
  495.           language_template[ "at" ] = "AT(@,)"
  496.           language_template[ "ct" ] = "CTOD(@)"
  497.           language_template[ "dc" ] = "DTOC(@)"
  498.           language_template[ "cm" ] = "CMONTH(@)"
  499.           language_template[ "dt" ] = "DATE()"
  500.           language_template[ "da" ] = "DAY(@)"
  501.           language_template[ "bf" ] = "BOF()"
  502.           language_template[ "ef" ] = "EOF()"
  503.           language_template[ "ds" ] = "DTOS(@)"
  504.           language_template[ "lo" ] = "LOWER(@)"
  505.           language_template[ "up" ] = "UPPER(@)"
  506.           language_template[ "mi" ] = "MIN(@,)"
  507.           language_template[ "ma" ] = "MAX(@,)"
  508.           language_template[ "mo" ] = "MONTH(@)"
  509.           language_template[ "yr" ] = "YEAR(@)"
  510.           language_template[ "pc" ] = "PCOUNT() = @"
  511.           language_template[ "ra" ] = "RAT(@,)"
  512.           language_template[ "ss" ] = "SAVE SCREEN TO @"
  513.           language_template[ "rs" ] = "RESTORE SCREEN FROM @"
  514.           language_template[ "tf" ] = "TRANSFORM(@,)"
  515.           language_template[ "su" ] = "SUBSTR(@,,)"
  516.           language_template[ "sp" ] = "SPACE(@)"
  517.           language_template[ "re" ] = "REPLICATE(@,)"
  518.           language_template[ "rp" ] = "REPLACE @"
  519.           language_template[ "va" ] = "VAL(@)"
  520.           language_template[ "pi" ] = "PICTURE @"
  521.           language_template[ "vl" ] = "VALID(@)"
  522.         }
  523.     } else if(buffer_name ~ file_extensions["pascal"]) {
  524.         ### Turbo 5.5 / Quick Pascal 1.x compatible templates
  525.  
  526.         if (electric_extensions == file_extensions["pascal"])
  527.             return;
  528.  
  529.         delete( language_template );    # delete last template and start over
  530.         electric_extensions=file_extensions["pascal"]
  531.  
  532.         language_template[ "{" ] = "{@}"        # }
  533.         language_template[ "(" ] = "(@)"
  534.         language_template[ "[" ] = "[@]"
  535.         language_template[ "*" ] = "(***\n*** @\n***)"
  536.         language_template[ "if" ] = "IF (@) THEN  "
  537.         language_template[ "ie" ] = "IF (@) THEN  \n\tELSE  "
  538.         language_template[ "fo" ] = "FOR @ :=   TO   DO\nBEGIN\n\t\nEND;"
  539.         language_template[ "ca" ] = "CASE @ OF \n\t\nEND;"
  540.         language_template[ "el" ] = "ELSE @"
  541.         language_template[ "en" ] = "END;"
  542.         language_template[ "re" ] = "REPEAT\n\t\nUNTIL (@);"
  543.         language_template[ "wh" ] = "WHILE (@) DO\nBEGIN\n\t\nEND;"
  544.         language_template[ "be" ] = "BEGIN\n\t@\nEND;"
  545.         language_template[ "pr" ] = "PROCEDURE @();\nBEGIN\n\t\nEND;"
  546.         language_template[ "fu" ] = "FUNCTION @(): ;\nBEGIN\n\t\nEND;"
  547.     } else if ( buffer_name ~ file_extensions["basic"]) {
  548.         ### here if they are needed by anyone
  549.  
  550.         if(electric_extensions == file_extensions["basic"])
  551.             return;
  552.  
  553.         delete( language_template );    # delete last template and start over
  554.         ELEC_LANG = "basic"
  555.         electric_extensions=file_extensions[ELEC_LANG]
  556.  
  557.         language_template[ "null" ] = "\0"
  558.     } else if ( buffer_name ~ file_extensions["asm"] ){
  559.         ### if you need ASM macros
  560.         if(electric_extensions==file_extensions["asm"])
  561.             return;
  562.         delete(language_template);
  563.         ELEC_LANG = "asm"
  564.         electric_extensions=file_extensions[ ELEC_LANG ]
  565.         language_template["null"]="\0"
  566.     } else {
  567.         electric_extensions=file_extensions["text"]
  568.         language_template[ "null" ] = "\0"
  569.     }
  570. }
  571.  
  572.  
  573. global function dBaseDialect( dialect ){
  574.     if ( argcount() < 1 ) {
  575.         dialect = tolower( prompt_history(
  576.                 "DB_DIALECT",
  577.                 "dBase Dialect: ",
  578.                 D_DIALECT,
  579.                 1 ))
  580.     } else {
  581.         dialect = tolower(dialect)
  582.     }
  583.     if ( dialect == "clipper50"    \
  584.       || dialect == "clipper87"    \
  585.       || dialect == "force"        \
  586.       || dialect == "dbase" ) {
  587.         D_DIALECT = dialect
  588.     } else {
  589.         D_DIALECT = "dbase"
  590.         warning("Valid choices are 'clipper87' 'clipper50' 'force' 'dbase'(default)")
  591.     }
  592.     ELEC_LANG = D_DIALECT
  593. }
  594.  
  595.  
  596. ## template_add()
  597. #
  598. #  Provides ability to add templates on the fly
  599. #  It is also possible to change a current template with this function
  600. #
  601. function template_add( tstr, expstr ) {
  602.     if (argcount() < 1)
  603.         tstr=prompt("Template characters: ","")
  604.     if (tstr && argcount() < 2)
  605.         expstr=prompt("Template expansion: ","")
  606.     if(tstr){
  607.         gsub("\\\\\\\\","\\",expstr)
  608.         language_template[tstr]=expstr
  609.         message("Template \""tstr"\" created.")
  610.     }
  611. }
  612.  
  613.  
  614. function extension_add(extstr) {
  615.     if ( argcount() < 1 )
  616.         extstr = prompt_history(
  617.                 "EXT_L",
  618.                 toupper( ELEC_LANG ) " File Extensions: ",
  619.                 file_extensions[ ELEC_LANG],
  620.                 1 )
  621.     if ( extstr ){
  622.         gsub("\\\\\\\\","\\",extstr)
  623.         file_extensions[ ELEC_LANG ] = extstr
  624.         message( toupper(ELEC_LANG) " file extensions updated." )
  625.     }
  626. }
  627.  
  628.  
  629.  
  630.  
  631. ## expand_template()
  632. #
  633. #  Expand a template if one can be located at or near the cursor.
  634. #
  635. function expand_template(){
  636.     local l, s, t
  637.  
  638.     initialize_template()
  639.  
  640.     if ( electric_mode && buffer_name ~ electric_extensions ){
  641.         for( t in language_template ){        # [ l ]
  642.             l = length( t )         #
  643.             s = readn( l )
  644.  
  645.             if( t == s ){
  646.                 current_column -= l
  647.                 delete_chars( l )
  648.                 insert_template( language_template[ t ])
  649.                 return
  650.             }
  651.         }
  652.     }
  653.     beep()
  654. }
  655.  
  656.  
  657.  
  658. ## insert_template()
  659. #
  660. #  insert a particular template
  661. #
  662. #    The following characters are treated specially:
  663. #
  664. #    1. "@" => place the cursor here after the template has been inserted
  665. #    2. "\n" => insert a newline and auto-indent.
  666. #    3. "\r" => insert a newline
  667. #    4. "\t" => indent an extra level (not actually treated specially)
  668. #    5. "\b" => unindent one level
  669. #    
  670. #    eg.: "{\n\t\n\b}" follows K&R
  671.  
  672. local function insert_template( t ){
  673.     local i, c
  674.     local col = current_column
  675.     local row = current_line
  676.     local rs = and(buffer_flags,BUFFER_REAL_SPACE_ONLY);
  677.  
  678.     buffer_flags = and( buffer_flags, not(BUFFER_REAL_SPACE_ONLY) );
  679.     
  680.     while( t && ( i = match( t, "[@\\n\\b]" ))){
  681.  
  682.         if( i > 1 )
  683.             insert_string( substr( t, 1, i - 1 ))
  684.         c = substr( t, i, 1 )
  685.         t = substr( t, i + 1 )
  686.  
  687.         if( c == "\n" ){
  688.             insert_auto_indent()
  689.  
  690.         } else if( c == "\r" ){
  691.             insert_newline_ai()
  692.  
  693.         } else if( c == "\b" ){
  694.             backspace();
  695.  
  696.         } else if( c == "@" ){
  697.             col = current_column
  698.             row = current_line
  699.         }
  700.     }
  701.     
  702.     insert_string( t )
  703.  
  704.     buffer_flags = or( buffer_flags, rs );
  705.  
  706.     goto_pos( row, col )
  707. }
  708.  
  709.  
  710. ### support for matching constructs
  711. #
  712.  
  713. local matching_pairs = "{ } [ ] ( ) /* */"    # string of matching pairs
  714.  
  715. ## record the particular matching constructs
  716. #    
  717. #    argument is a whitespace-separated sequence of opening, closing pairs
  718. #    a null string causes the defaults to be selected
  719.  
  720. function init_goto_match( pairs ){
  721.     matching_pairs = pairs
  722. }
  723.  
  724.  
  725. ## form an inclusive selection around a matching pair
  726. #
  727. #    If a selection has already been made, merely swap_marks().
  728. #    It is an error if no half of a matching pair can be found.
  729.  
  730. function mark_matching(){
  731.     if( region_type() ){
  732.         swap_marks()
  733.     } else {
  734.         save_position()
  735.         if( goto_matching()){
  736.             drop_anchor( INCLUSIVE_SELECTION )
  737.         }
  738.         restore_position( 1 )
  739.     }
  740. }
  741.  
  742. function  normalize_block(i){}
  743.  
  744. ## normalize_block
  745. #  Moves cursor to beginning or end of block, if it's not already there.
  746.  
  747. local function normalize_block(move_to_end)
  748. {
  749.     if ((mark_line() > mark_line(0)) ||
  750.             ((mark_line() == mark_line(0)) && (mark_column() > mark_column(0))))
  751.         if (move_to_end)
  752.             swap_marks();
  753. }
  754.  
  755.  
  756. ## form an inclusive selection around a NESTED matching pair
  757. #
  758. function mark_matching_next()
  759. {
  760.     local s_flag = 0x04 + 0x10;
  761.     if (region_type() != 0){
  762.         normalize_block(0);        # move cursor to beginning of block
  763.         raise_anchor();
  764.         next_char();
  765.     }
  766.     if (search("([\\({\\[])|(/\\*)", s_flag) == 0)            # "}"
  767.         message("No opening pairs found.");
  768.     else
  769.         mark_matching();
  770. }
  771.  
  772.  
  773.  
  774. ## goto the matching construct corresponding to the one under the cursor
  775. #
  776. #    The cursor may be on a matching construct and be valid.
  777. #    The cursor is restored to its original position if no match is found.
  778.  
  779. function goto_matching(){
  780.     local forward        # odd => forward; even => backward
  781.     local base, open, close
  782.     local l, i, p
  783.     local matching_pair    # the array identifying matching pairs
  784.     local matching_count    # number of elements in matching_pair
  785.  
  786.     if( matching_pairs ){
  787.  
  788.         matching_count = split( matching_pairs, matching_pair )
  789.  
  790.         for( i=1; i<= matching_count; i++ ){    
  791.             p = matching_pair[ i ]
  792.             l = length( p )
  793.             if( p == readn1( l )){         # || p == readn( l )
  794.                 forward = and( i, 1 )
  795.                 base = and( i + 1, 0xFFFFFFFE )
  796.                 open = matching_pair[ base - 1 ]
  797.                 close = matching_pair[ base ]
  798.                 return scan_for_matching( forward, open, close )
  799.             }
  800.         }
  801.     
  802.         warning( "cursor not positioned on matching construct" )
  803.     }
  804.  
  805.     beep()
  806.  
  807.     return 0
  808. }
  809.  
  810. ## move the cursor to a matching construct, 
  811. #
  812. #    given a direction, and the opening and closing constructs.
  813. #    The cursor is restored to its original position if no match is found.
  814.  
  815.  
  816. local function scan_for_matching( forward, open, close ){
  817.     local olen = length( open )
  818.     local clen = length( close )
  819.     local pattern = quote_regex( open ) "|" quote_regex( close )
  820.     local flags = SEARCH_REGEX             \
  821.             + SEARCH_IGNORE_CASE        \
  822.             + SEARCH_MAXIMAL_MATCH        \
  823.             + SEARCH_ADVANCE        \
  824.             + SEARCH_FORWARD * forward
  825.     local level = forward * 2 - 1    # forward => +1; backward => -1
  826.     local s
  827.     
  828.     save_position()
  829.  
  830.     while( level != 0 ){
  831.         if( search( pattern, flags )){
  832.             s = readn1( olen ) 
  833.             if( s == open )        # == was opening symbol
  834.                 level += 1
  835.             if( olen != clen )
  836.                 s = readn1( clen )
  837.             if( s == close )    # == was closing symbol
  838.                 level -= 1
  839.         } else  {
  840.             restore_position( 1 )    # restore saved pos
  841.             warning( "unbalanced nesting pair" )
  842.             beep()
  843.             return 0
  844.         }
  845.     }
  846.  
  847.     restore_position( 0 )    # discard saved pos
  848.  
  849.     return 1
  850. }
  851.  
  852.  
  853. ##
  854. # braces -- report on unmatched opening and closing braces
  855. #
  856. function braces(){
  857.     local prevWin = current_window
  858.     local level = 0
  859.     local matched
  860.     local opening = "{"
  861.     local closing = "}"
  862.     local pattern = quote_regex( opening ) "|" quote_regex( closing )
  863.     local flags = SEARCH_FWD_REGEX_MAX_IG
  864.  
  865.     if( dialog_window )
  866.         current_window = dialog_window
  867.  
  868.     save_position()
  869.     goto_buffer_top()
  870.  
  871.     while( search( pattern, flags )){
  872.         matched = read_buffer( search_string_length )
  873.         if( matched == opening ){
  874.             save_position()
  875.             level++
  876.         } else if( matched == closing ){
  877.             if( level-- ){
  878.                 restore_position( 0 )
  879.             } else {
  880.                 save_position()
  881.                 break
  882.             }
  883.         }
  884.         message( "nesting level == " substr( "{{{{{{{{{{...", 1, level ))    # }}}}}}}}}}
  885.         next_char()
  886.     }
  887.  
  888.     if( prevWin )
  889.         current_window = prevWin
  890.  
  891.  
  892.     restore_position( 1 )
  893.     if( level > 0 ){
  894.         while( level-- ) {
  895.             restore_position( 0 )
  896.         }
  897.         warning( "unmatched " opening )
  898.     } else if( level < 0 ){
  899.         restore_position( 0 )
  900.         warning( "unmatched " closing )
  901.     } else {
  902.         message( "all braces match" )
  903.     }
  904. }
  905.  
  906. # read n characters before the cursor
  907.  
  908. local function readn( n ){
  909.     return ( n <= current_line_offset )                \
  910.         ? read_buffer( -n )                    \
  911.         : ""
  912. }
  913.  
  914. # read n characters following and including the cursor
  915.  
  916. local function readn1( n ){
  917.     return ( n + current_line_offset <= current_line_length )    \
  918.         ? read_buffer( n )                    \
  919.         : ""
  920. }
  921.  
  922.  
  923. # quote all regex characters in a string
  924.  
  925. function quote_regex( s ){                    #PUBLIC #STR
  926.     local r = s
  927.  
  928.     gsub( "[\\\\.*{}()^$|\\[\\]]", "\\\\&", r )
  929.     return r
  930. }
  931.  
  932.  
  933. ### auto indent mode: automatically indent newly-entered lines to match
  934. #    the leading whitespace on the previous non-blank line.
  935. #
  936. #    One key, normally Enter, causes auto-indent to occur.
  937. #    Another key, normally Control-Enter causes auto-indent to
  938. #    occur after a line is "opened".
  939. #    
  940. #    The automatically-indented line is initially composed of virtual
  941. #    space.  This means that consecutive lines that are indented but
  942. #    also left blank do not contain any superfluous characters.
  943.  
  944.  
  945. global auto_indent_mode = 0
  946.  
  947. function ai( on ){                    #PUBLIC #VOID
  948.     if (argcount())
  949.         toggle_auto_indent( on )
  950.     else
  951.         toggle_auto_indent()
  952. }
  953.  
  954. ## toggle auto-indent mode
  955. #    when enabled auto_indent_cr does auto-indenting;
  956. #    when disabled auto_indent_cr merely inserts a "\n".
  957. #
  958. # if selection is present it causes the mode to be set to its value
  959. #    rather than toggled
  960.  
  961. function toggle_auto_indent( selection ){        #PUBLIC #VOID
  962.     local verbose = 0
  963.  
  964.     if( argcount() < 1 ){
  965.         selection = !auto_indent_mode
  966.         verbose = 1
  967.     }
  968.  
  969.     auto_indent_mode = selection
  970.  
  971.     if( verbose )
  972.         message( selection                 \
  973.             ? "auto-indent enabled"            \
  974.             : "auto-indent disabled" )
  975. }
  976.  
  977.  
  978. # open line and auto-indent
  979.  
  980. function auto_indent_nl(){
  981.     goto_eol()
  982.     if( auto_indent_mode )
  983.         insert_auto_indent()    # prev_command == function_id( "auto_indent_nl" ))
  984.     else
  985.         insert_newline_ai()
  986. }
  987.  
  988.  
  989. # insert a new line and auto-indent
  990.  
  991. function auto_indent_cr(){
  992.     if( auto_indent_mode )
  993.         insert_auto_indent()    # prev_command == function_id( "auto_indent_cr" ))
  994.     else
  995.         insert_newline_ai()
  996. }
  997.  
  998. local function insert_newline_ai(){
  999.     local overtypemode = and( buffer_flags, BUFFER_OVERTYPE_MODE );
  1000.  
  1001.     buffer_flags = and( buffer_flags, not(BUFFER_OVERTYPE_MODE) );
  1002.     insert_newline();
  1003.     buffer_flags = or( buffer_flags, overtypemode );
  1004. }
  1005.  
  1006.  
  1007.  
  1008. # # insert and auto-indent a newline before the current line
  1009. # function auto_indent_before(){
  1010. #     if( current_line == 1 ){ 
  1011. #          goto_bol()
  1012. #         insert_newline_ai()
  1013. #         up()
  1014. #     } else {
  1015. #         up()
  1016. #         auto_indent_nl()
  1017. #     }
  1018. # }
  1019.     
  1020. function insert_auto_indent( repeat ){
  1021.     local line, col, follow
  1022.  
  1023.     follow = read_buffer( 100 )
  1024.     delete_to_eol()
  1025.     insert_newline_ai()
  1026.  
  1027.     line = current_line
  1028.     do {
  1029.         prev_line()
  1030.     } while( current_line > 1 && !read_buffer( 1 ))
  1031.  
  1032.     col = current_column
  1033.     goto_pos( line, col )
  1034.     insert_string( follow )
  1035.     goto_pos( line, col )
  1036. }
  1037.  
  1038.  
  1039. ###
  1040. #
  1041. # electric_edit_file()
  1042. #
  1043. # Whenever a new edit file is created, the extension is stripped from
  1044. # the file name and a function with that extension (preceded by "__")
  1045. # is invoked. If the function does not exist, "_default()" is called.
  1046. #
  1047. global function electric_edit_file() {
  1048.     local    ext = path_ext( buffer_filename );
  1049.     local    lev = message_level;
  1050.     local    def_name = "_default"
  1051.     local    id
  1052.  
  1053.     message_level = 3;
  1054.  
  1055.     if (ext) {
  1056.         if (substr( ext, 1, 1 ) == "." ) {
  1057.             ext = "__" substr( ext, 2 );
  1058.             id = function_id( ext );
  1059.             if ( id ) {
  1060.                 message_level = lev;
  1061.                 execute_function( ext );
  1062.                 return;
  1063.             }
  1064.         }
  1065.     }
  1066.  
  1067.     id = function_id( def_name );
  1068.     message_level = lev;
  1069.     if ( id )
  1070.         execute_function( def_name );
  1071. }
  1072.  
  1073.  
  1074. #
  1075. # Language-specific macros.  The following ("__") macros are called in turn 
  1076. # whenever a file with the corresponding (".") extension is edited and
  1077. # electric is enabled.  
  1078. #
  1079.  
  1080. function __c(){
  1081.         buffer_tabs = "5 9"    # equidistant 4
  1082. }
  1083.  
  1084. function __pel(){
  1085.         buffer_tabs = "9 17"    # equidistant 8
  1086. }
  1087.  
  1088. function __awk(){
  1089.         buffer_tabs = "9 17"    # equidistant 8
  1090. }
  1091.  
  1092. function __cbl(){
  1093.         buffer_tabs = "8 12"    # 8 followed by equidistant 4
  1094. }
  1095.  
  1096. function __cob(){
  1097.         buffer_tabs = "8 12"    # 8 followed by equidistant 4
  1098. }
  1099.  
  1100. function __sal(){
  1101.         buffer_tabs = "9 17"    # equidistant 8
  1102. }
  1103.  
  1104. function __asm(){
  1105.         buffer_tabs = "9 17"    # equidistant 8
  1106. }
  1107.  
  1108. function __prg() {
  1109.         buffer_tabs = "5 9"    # equidistant 4
  1110. }
  1111.