// // btm_mode // // v 1.2.0 // 2006-09-08 // // Timothy Byrd // timbyrd@pobox.com // // (Please contact me with comments/corrections.) // // This is an updated batch mode to work better with the JP Software // products 4NT and TakeCommand. By default it is set to work with // version 8 of these products, but that can be changed using the // btm_major_version variable below. // // History: // // 2006-09-08 - v1.2.0 - Update for version 8.0 of the JP products. // Added btm_option and btm_unknown color classes. // Now highlight configuration options. // // 2005-12-20 - v1.1.0 - Update for version 7.0 of the JP products. // Also highlight the "Control Variables" (e.g. RecycleExclude) // when they immediately follow the SET keyword. // // 2005-04-06 - Added btm_delete_trailing_spaces variable // // 2005-04-05 - Smart indenting (shift-tab to unindent) // Alias coloring (get list from alias file or running shell) // // 2005-03-24 - Initial version: I've updated the keywords for // version 6.01 of the JP products, and distingish between // built-in commands and common externals (e.g. FORMAT). // // // See the user variables below for info on how the behavior of // btm-mode can be customized. // // // I also color the names of variable functions (distinguishing between // built-in and user defined). I suggest setting btm_function and // btm_userfunction to different colors so it's easy to tell when you // mis-type the name of a built-in function. For example: // // color_class btm_alias 0x8080ff on black; // color_class btm_backquote red on grey; // color_class btm_bat_param red on black; // color_class btm_comment grey on black; // color_class btm_external 0xC4DF02 on black; // color_class btm_function 0x41C0FE on black; // color_class btm_keyword 0xff8000 on black; // color_class btm_label red on black; // color_class btm_option 0x00e0b0 on black; // color_class btm_punctuation cyan on black; // color_class btm_unknown red on cyan; // color_class btm_userfunction red on black; // color_class btm_uservariable 0x00e0b0 on black; // color_class btm_variable 0x40C0F7 on black; // #if 0 // Add these lines to colclass.txt to get descriptions in set-color btm-alias An aliased command in a batch file. btm-backquote A back-quote character (`) in a batch file. btm-bat-param A batch file parameter, e.g., %1, %$, %2$, %#. btm-comment A comment in a batch file (rem or ::). btm-external A commonly used external for a batch file, e.g., FORMAT. btm-function An internal variable function in a batch file e.g., %@makedate[]. btm-keyword An internal keyword in a batch file, e.g., COPY. btm-label A label line in a batch file ( :label ). btm-option A configuration option. btm-punctuation Punctuation in a batch file. btm-unknown Something unknown - likely an error. btm-userfunction A user-defined variable function in a batch file e.g., %@myfunc[]. btm-uservariable A user-defined variable in a batch file e.g., %myvar. btm-variable An internal variable in a batch file, e.g., %_TIME. #endif #include "eel.h" #include "proc.h" #include "colcode.h" #include "misclang.h" // This variable gets a list of words to color as aliases, of the form: // "|alias1|alias2|alias3|" // Set this variable to an empty string to cause it to be refreshed. // Or if your aliases do not change, save the value in your state file // or einit.ecm. // If you have a lot of aliases, you may need to make this larger. // user char btm_alias_list[1024] = ""; // If you use an alias file, set this variable to read the list of // aliases from the file. // If no path is specified, will look in epsilon\bin and epsilon dirs. // //user char btm_alias_file[FNAMELEN] = "aliases.txt"; user char btm_alias_file[FNAMELEN] = ""; // If you don't use an alias list, set this variable so we can fire up // a copy of the shell to list out the aliases. // The value of btm_alias_command is the full command line to get the // alias list. // It should include '/c alias' but may include other options like a // directive to specify the .ini file. // //user char btm_alias_command[128] // = "%JP_EXE_DIR%\\4nt\\4nt.exe /@c:\\jp\\4nt.ini /L /c alias"; user char btm_alias_command[128] = ""; // Alter this variable if you use a command separator other than the // default ampersand '&' // user char btm_command_sep = '&'; // Alter this variable if you use an escape character other than the // default caret '^' // user char btm_escape_char = '^'; // Alter this variable if you use an parameter character other than the // default caret '$' // user char btm_bat_param_char = '$'; // indent by this amt; 0 means use tab size // user buffer short btm_indent = 4; // Since CHCP is internal to 4NT and external to TakeCommand // user char btm_chcp_is_internal = 0; // Since different versions have different keywords.. // // Currently support 6, 7 & 8. // user int btm_major_version = 8; user int reindent_after_btm_yank = 20000; user char btm_reindent_previous_line = 1; user char btm_delete_trailing_spaces = 1; buffer char in_shell_buffer; ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// color_class perl_comment; color_class perl_function; color_class perl_string; color_class perl_variable; color_class perl_keyword; color_class btm_alias = color_class perl_function; color_class btm_backquote = color_class perl_string; color_class btm_bat_param = color_class perl_string; color_class btm_comment = color_class perl_comment; color_class btm_external = color_class perl_function; color_class btm_function = color_class perl_function; color_class btm_keyword = color_class perl_keyword; color_class btm_label = color_class perl_variable; color_class btm_punctuation = color_class perl_string; color_class btm_userfunction = color_class perl_function; color_class btm_uservariable = color_class perl_variable; color_class btm_variable = color_class perl_variable; color_class btm_option = color_class perl_keyword; color_class btm_unknown = color_class perl_string; char _btm_mode_name[] = "btm"; keytable btm_tab; // Get the user's alias list // btm_get_aliases() { int aliasBuf; #if 0 aliasBuf = create("my_aliases"); // a named buf we can examine #else aliasBuf = tmp_buf(); // read help text for classes into buf on_exit buf_delete(aliasBuf); #endif save_var bufnum = aliasBuf; // Try to grab an alias file into the temp buffer // if (btm_alias_file && *btm_alias_file) { char* new; if (new = lookpath(btm_alias_file)) file_read(new, FILETYPE_AUTO); else say("Could not open alias file '%s'", btm_alias_file); } // Try run btm_alias_command to get text into temp buffer. // if (size() == 0 && btm_alias_command && *btm_alias_command) { int retval = buf_pipe_text(0, aliasBuf, btm_alias_command, // char *cmdline, "", PIPE_SYNCH|PIPE_NOREFRESH|PIPE_SKIP_SHELL); if (!retval) say("Could not run alias command '%s'", btm_alias_file); } strcpy(btm_alias_list, "|"); char abuf[100]; int start, stop, aliasesOK = 1; point = 0; for (;;) { if (!re_search(1, "^[ \t]*([^= \t\f\n\r]+)=")) { break; } start = find_group(1, 1); stop = find_group(1, 0); grab(start, MIN(stop, start + ptrlen(abuf) - 1), abuf); to_end_line(); // Skip keystroke macros // if ('@' == abuf[0]) { continue; } char* cp = strchr(abuf, '*'); if (!cp) { aliasesOK = aliasesOK && btm_append_alias(abuf); } else { // This expands partial alias names to all possibilities. // e.g.: WHER*EIS => WHER, WHERE, WHEREI and WHEREIS // while (*cp) { *cp = 0; aliasesOK = aliasesOK && btm_append_alias(abuf); *cp = *(cp + 1); ++cp; } } } if (!aliasesOK) { say("Alias list truncated - make btm_alias_list larger!"); } } int btm_append_alias(char* abuf) { if (strlen(btm_alias_list) + strlen(abuf) + 3 > ptrlen(btm_alias_list)) { return 0; } strcat(btm_alias_list, abuf); strcat(btm_alias_list, "|"); return 1; } // Return code for word from here to point (something with alpha or // digits). // // Return values: // // 0 if unknown // 1 for command // 2 for comment // 3 for system function // 4 for user function (any %@ not in the list) // 5 for internal variable // 6 for batch file parameter // 7 for known external // 8 for an aliased command // 9 for punctuation // 10 for user variable // 11 for a known option // 12 for an unknown option // is_btm_keyword(int from) { char buf[200], *s; save_var case_fold = 1; if (point - from > sizeof(buf) / sizeof(char) - 10) save_var point = from + sizeof(buf) / sizeof(char) - 10; buf[0] = '|'; // get identifier, between | chars grab(from, point, buf + 1); // Does it start a command? // (first thing on the line or following a '%+') // // Substitute in the btm_command_sep value for the ampersand // 012345678v char* start_pattern = "(^|%%%+|[&])([ \t]*%*)?[ \t]*[^ ]"; start_pattern[9] = btm_command_sep; int starts_command = matches_at(from+1, -1, start_pattern); // If it's the first thing on the line, remove text after dot (file // extension) to match things like 'format.exe'. // if (starts_command && buf[1] != '.' && (s = strchr(buf + 1, '.'))) *s = 0; strcat(buf, "|"); // Check for aliases // (an astrisk disables an alias) // if (starts_command && !matches_at(from, -1, "%*[ \t]*")) { // Load aliases if necessary // if (!btm_alias_list || strlen(btm_alias_list) == 0) { btm_get_aliases(); } if (btm_alias_list && strstr(btm_alias_list, buf)) return 8; } if (strstr("|rem|", buf) && !matches_at(from, -1, "[^ \n\t@][@ \t]*")) return 2; if (buf[1] == '%' && buf[2] == '@') { if (strstr( "|%@abs|%@agedate|%@alias|%@altname|%@ascii|%@attrib" "|%@caps|%@cdrom|%@ceiling|%@char|%@clip|%@clipw|%@color" "|%@comma|%@console|%@convert|%@crc32|%@cwd|%@cwds|%@date" "|%@day|%@dec|%@decimal|%@descript|%@device|%@digits" "|%@dirstack|%@diskfree|%@disktotal|%@diskused|%@domain" "|%@dow|%@dowf|%@dowi|%@doy|%@enumservers|%@enumshares" "|%@errtext|%@eval|%@exec|%@execstr|%@exetype|%@expand" "|%@ext|%@field|%@fields|%@fileage|%@fileclose|%@filedate" "|%@filename|%@fileopen|%@fileread|%@files|%@fileseek" "|%@fileseekl|%@filesize|%@filetime|%@filewrite" "|%@filewriteb|%@findclose|%@findfirst|%@findnext|%@floor" "|%@format|%@formatn|%@fstype|%@full|%@function|%@getdir" "|%@getfile|%@getfolder|%@history|%@idow|%@idowf|%@if" "|%@inc|%@index|%@iniread|%@iniwrite|%@insert|%@instr" "|%@int|%@ipaddress|%@ipname|%@isalnum|%@isalpha|%@isascii" "|%@iscntrl|%@isdigit|%@isprint|%@ispunct|%@isspace" "|%@isxdigit|%@label|%@left|%@len|%@lfn|%@line|%@lines" "|%@lower|%@ltrim|%@makeage|%@makedate|%@maketime|%@max" "|%@md5|%@min|%@month|%@name|%@numeric|%@option|%@path" "|%@ping|%@random|%@readscr|%@ready|%@regcreate" "|%@regdelkey|%@regexist|%@regquery|%@regset|%@regsetenv" "|%@remote|%@removable|%@repeat|%@replace|%@rexx|%@right" "|%@rtrim|%@search|%@select|%@sfn|%@strip|%@subst|%@substr" "|%@time|%@timer|%@trim|%@truename|%@truncate|%@unc" "|%@unicode|%@unique|%@upper|%@verinfo|%@wattrib|%@wild" "|%@winclass|%@winexename|%@wininfo|%@winmemory" "|%@winmetrics|%@winstate|%@winsystem|%@word|%@words" "|%@workgroup|%@year" "|", buf)) return 3; if (btm_major_version >= 7 && strstr( "|%@afscell|%@afsmount|%@afspath|%@afssymlink|%@afsvolid" "|%@afsvolname|%@assoc|%@average|%@compare|%@count|%@drivetype" "|%@ftype|%@group|%@inode|%@junction|%@lcs|%@links|%@perl" "|%@quote|%@regex|%@regexindex|%@regexsub|%@reverse|%@ruby" "|%@sha1|%@sha256|%@sha384|%@sha512|%@similar|%@snapshot" "|%@summary|%@unquote|%@winapi" "|", buf)) return 3; if (btm_major_version >= 8 && strstr( "|%@capi|%@drivetypeex|%@owner|%@script|%@unquotes|%@winpos" "|%@wmi|%@xmlpath" "|", buf)) return 3; return 4; } if (buf[1] == '%') { char* b = buf; char* bp; // Change variables of the form %[foo] to %foo // if (buf[2] == '[') { ++b; buf[1] = '|'; buf[2] = '%'; bp = strchr(b, ']'); if (bp) { bp[0] = '|'; bp[1] = '\0'; } } // Remove trailing percent if not bracketed // else if (bp = strchr(b+2, '%')) { bp[0] = '|'; bp[1] = '\0'; } if (strstr( "|%+|%=|%?||%_4ver|%_?||%_acstatus|%_alt|%_ansi|%_batch" "|%_batchline|%_batchname|%_batchtype|%_battery" "|%_batterylife|%_batterypercent|%_bdebugger|%_bg|%_boot" "|%_build|%_capslock|%_childpid|%_ci|%_cmdline|%_cmdproc" "|%_cmdspec|%_co|%_codepage|%_column|%_columns|%_country" "|%_cpu|%_cpuusage|%_ctrl|%_cwd|%_cwds|%_cwp|%_cwps" "|%_date|%_datetime|%_day|%_detachpid|%_disk|%_dname" "|%_dos|%_dosver|%_dow|%_dowf|%_dowi|%_doy|%_echo|%_fg" "|%_ftperror|%_hlogfile|%_host|%_hour|%_hwprofile|%_idow" "|%_idowf|%_imonth|%_imonthf|%_ininame|%_ip|%_isodate" "|%_kbhit|%_lalt|%_lastdisk|%_lctrl|%_logfile|%_lshift" "|%_minute|%_month|%_monthf|%_numlock|%_pid|%_pipe|%_ppid" "|%_ralt|%_rctrl|%_row|%_rows|%_rshift|%_scrolllock" "|%_second|%_selected|%_shell|%_shift|%_shralias" "|%_startpath|%_startpid|%_syserr|%_time|%_transient" "|%_unicode|%_windir|%_winfgwindow|%_winname|%_winsysdir" "|%_winticks|%_wintitle|%_winuser|%_winver|%_xpixels" "|%_year|%_ypixels|%cdpath|%cmdline|%colordir|%comspec" "|%date|%errorlevel|%filecompletion|%historyexclusion" "|%path|%pathext|%prompt|%recycleexclude|%temp|%time" "|%titleprompt|%tmp|%treeexclude" "|", b)) return 5; if (btm_major_version >= 7 && strstr( "|%!|%_afswcell|%_drives|%_dst|%_exit|%_idleticks|%_iftp|%_iftps" "|%_openafs|%_osbuild|%_stderr|%_stdin|%_stdout|%_stzn|%_stzo" "|%_tzn|%_tzo|%debugvariableexclude|%variableexclude" "|", b)) return 5; if (btm_major_version >= 8 && strstr( "|%_cdroms|%_dvds|%_editmode|%_execstr|%_expansion|%_hdrives" "|%_ready|%_registered|%_shells|%_virtualpc|%_vmware|%_wow64" "|", b)) return 5; // If this string gets edited, edit the assignments below to // replace the correct positions for the dollar signs. // char* bat_param_re; if (btm_major_version >= 8) { bat_param_re = "%%[0-9]+|%%%[[0-9]+]|%%-?[0-9]*%$|%%%[[0-9]*%$]|%%#|%%%[#]"; // 01234567890123456789012345678901^345678901234^ // 1 2 3 4 bat_param_re[32] = bat_param_re[45] = btm_bat_param_char; } else { bat_param_re = "%%[0-9]+|%%%[[0-9]+]|%%[0-9]*%$|%%%[[0-9]*%$]|%%#|%%%[#]"; // 012345678901234567890123456789^123456789012^45 // 1 2 3 4 bat_param_re[30] = bat_param_re[43] = btm_bat_param_char; } // check for a batch file parameter // if (matches_at(from, 1, bat_param_re)) { point = matchend; return 6; } // Check for just a percent sign // if (!buf[3]) return 9; return 10; // unknown variable } // Does it immediately follow the word SET? // char* set_pattern = "set[ \t]+[^ ]"; int set_command = matches_at(from+1, -1, set_pattern); if (set_command) { if (strstr( "|cdpath|cmdline|colordir|comspec|date|errorlevel|filecompletion" "|historyexclusion|path|pathext|prompt|recycleexclude|temp|time" "|titleprompt|tmp|treeexclude" "|", buf)) return 5; if (btm_major_version >= 7 && strstr( "|debugvariableexclude|variableexclude" "|", buf)) return 5; } // // Is it an option? For example: // // option 4StartPath // option //4StartPath=c:\jp // echo %@option[4StartPath] // char* option_pattern = "(option[ \t]*(//[ \t]*)?[a-z0-9])|(%%@option[ \t]*%[[ \t]*[a-z0-9])"; int option_command = matches_at(from+1, -1, option_pattern); if (option_command) { char* slash_pattern = "(//[ \t]*[^ ])"; int slashes = matches_at_length(from+1, -1, slash_pattern); if (slashes) { set_character_color(from-slashes+1, from, color_class btm_option); } if (strstr( "|4startpath|addfile|aliasexpand|ampm|ansi|appendtodir" "|backspace|batchecho|beepfreq|beeplength|beginline" "|cddwincolors|cddwinheight|cddwinleft|cddwintop|cddwinwidth" "|clearkeymap|colordir|commandescape|commandsep|completehidden" "|consolecolumns|consolerows|copy|copyprompt|cua|cursorins" "|cursorover|debug|decimalchar|del|delglobalquery|delhistory" "|deltobeginning|deltoend|delwordleft|delwordright" "|descriptionmax|descriptionname|descriptions|dirhistory" "|dirwinopen|down|duplicatebugs|editmode|editor|endhistory" "|endline|eraseline|escapechar|evalmax|evalmin|execline" "|execwait|filecompletion|firewallhost|firewallpassword" "|firewalltype|firewalluser|ftpcfg|fuzzycd|help|helpword" "|hideconsole|histcopy|histdups|histlogname|histlogon|histmin" "|histmove|history|histwinopen|histwrap|ibeamcursor|include" "|iniquery|inputcolors|ins|left|lfntoggle|linetoend" "|listboxbarcolors|listcolors|listexit|listfind" "|listfindreverse|listhex|listhighbit|listinfo|listnext" "|listopen|listprevious|listprint|listrowstart" "|liststatbarcolors|listunicode|listwrap|localaliases" "|localdirhistory|localfunctions|localhistory|logerrors" "|logname|logon|mailaddress|mailpassword|mailport|mailserver" "|mailuser|nextfile|nexthistory|nextinifile|noclobber" "|normaleditkey|normalkey|normallistkey|normalpopupkey" "|parameterchar|passiveftp|paste|pathext|pauseonerror|popfile" "|popupwinbegin|popupwincolors|popupwindel|popupwinedit" "|popupwinend|popupwinexec|popupwinheight|popupwinleft" "|popupwintop|popupwinwidth|prevfile|prevhistory|proxy" "|proxypassword|proxyport|proxyuser|recyclebin|repeatfile|rexx" "|right|savedircase|savehistory|screenbufsize|screencolumns" "|screenrows|scrolldown|scrollpgdn|scrollpgup|scrollup" "|selectcolors|selectstatbarcolors|servercompletion|sslport" "|sslprovider|sslstartmode|statusbaron|statusbartext|stdcolors" "|swapscrollkeys|tabstops|tcstartpath|thousandschar|timeserver" "|toolbaron|toolbartext|treepath|unicodeoutput|unixpaths|up" "|updatetitle|win32sfnsearch|windowheight|windowstate" "|windowwidth|windowx|windowy|wordleft|wordright" "|", buf)) return 11; if (btm_major_version >= 7 && strstr( "|cmdextensions|completepaths|debuggertransparency" "|delayedexpansion|exitfile|ftptimeout|histfile|httptimeout" "|jabberserver|jabberuser|jabberpassword|lasthistory|listback" "|listcontinue|listfindregex|listfindregexreverse" "|ntfsdescriptions|perl|regularexpressions|rlocalhost" "|rlocalport|rlocaluser|ruby|settingchange|shchangenotify" "|startupfile|switchchar|tftptimeout|transparency" "|variableexpand|wow64fsredirection|zoneid" "|", buf)) return 11; if (btm_major_version >= 8 && strstr( "|autocancel|autorun|bgcolorrgb|fgcolorrgb|inactivetransparency" "|listinversecolors|logall" "|", buf)) return 11; return 12; } if (strstr( "|.and.|.or.|.xor.|activate|alias|assoc|attrib|batcomp|bdebugger" "|beep|break|call|cancel|case|cd|cdd|chdir|cls|color|copy|date" "|ddeexec|default|defined|del|delay|describe|detach|dir|direxist" "|dirhistory|dirs|do|drawbox|drawhline|drawvline|echo|echoerr|echos" "|echoserr|else|elseiff|enddo|endiff|endlocal|endswitch|endtext|eq" "|eqc|eql|eqlequ|equ|erase|errorlevel|eset|eventlog|except|exist" "|exit|ffind|for|forever|free|ftype|function|ge|geq|global|gosub" "|goto|gt|gtr|head|help|history|if|iff|iftp|in|inkey|input|isalias" "|isapp|isdir|isfile|isfunction|isinternal|islabel|iswindow|iterate" "|keybd|keys|keystack|le|leave|leq|list|loadbtm|log|lss|lt|md" "|memory|mkdir|mklnk|move|msgbox|ne|neq|not|on|option|path|pause" "|pdir|playavi|playsound|popd|print|prompt|pushd|querybox|quit|rd" "|reboot|recycle|ren|rename|return|rmdir|screen|scrput|select" "|sendmail|set|setdos|setlocal|shift|shortcut|shralias|smpp|snpp" "|start|switch|tail|taskend|tasklist|tctoolbar|tee|text|then|time" "|timer|title|touch|tree|truename|type|unalias|unfunction|unset" "|until|ver|verify|vol|vscrput|which|window|y" "|", buf)) return 1; if (btm_major_version >= 7 && strstr( "|abortretryignore|breakpoint|canceltrycontinue|continueabort" "|debugstring|ejectmedia|isplugin|jabber|plugin|postmsg" "|retrycancel|rexec|rshell|transient" "|", buf)) return 1; if (btm_major_version >= 8 && strstr( "|osd|priority|script|snmp|sync|wmiquery" "|", buf)) return 1; if (btm_chcp_is_internal && strstr("|chcp|", buf)) return 1; // Common externals // if (strstr( "|at|cacls|chcp|chkdsk|chkntfs|cmd|cmdextversion|command|comp" "|compact|convert|diskcomp|diskcopy|doskey|fc|find|findstr" "|format|graftabl|label|mode|more|recover|replace|sort|subst" "|xcopy" "|", buf)) return 7; if (strstr( "|unknown_cmd" "|", buf)) return 8; if (btm_major_version >= 8 && strstr( "|post_exec|pre_exec|pre_input" "|", buf)) return 8; // Special case - make sure no spaces before left square bracket of // function, e.g. "%@perl[]" is good, but "%@perl []" is not. // Return 12 for unknown in this case. // if (1 == point - from && strchr("[", character(from))) { char* func_space_pattern = "%%@?[-a-z0-9_.$]+[ \t]+%["; int func_space = matches_at(from+1, -1, func_space_pattern); if (func_space) return 12; } // Check for punctuation in here // if (1 == point - from && strchr("]-[<>|&/\\()+*?:.", character(from))) return 9; return 0; } color_btm_range(from, to) { int t = -1; if (from >= to) return to; save_var point, matchstart, matchend, case_fold = 1; point = to; // Color entire lines. nl_forward(); to = point; save_var narrow_end = size() - to; set_character_color(from, to, -1); point = from; while (point < to) { if (!re_search(1, "(%%@)?[-a-z0-9_.$]+|%%[-a-z0-9_.$]+(%%)?|%%%%" "|%%%[[^]%]+%]|%%[+=?#!]|%%_%?|[]-[<>|&/\\()+*?:`%]")) { t = size(); break; } t = matchstart; // colon at beginning of line. // if (character(t) == ':' && matches_at(t+1, -1, "^[ \t]*:")) { // :: is a comment if (character(t+1) == ':') { nl_forward(); set_character_color(t, point, color_class btm_comment); } // a label else if (matches_at(t+1, 1, "[ \t]*[a-z0-9_.&]+")) { point = matchend; set_character_color(t, point, color_class btm_label); } else { point = t + 1; set_character_color(t, point, color_class btm_punctuation); } continue; } else if (character(point - 1) == '`') { set_character_color(t, point, color_class btm_backquote); continue; } switch (is_btm_keyword(t)) { case 1: set_character_color(t, point, color_class btm_keyword); break; case 2: nl_forward(); set_character_color(t, point, color_class btm_comment); break; case 3: set_character_color(t, point, color_class btm_function); break; case 4: set_character_color(t, point, color_class btm_userfunction); break; case 5: set_character_color(t, point, color_class btm_variable); break; case 6: set_character_color(t, point, color_class btm_bat_param); break; case 7: set_character_color(t, point, color_class btm_external); break; case 8: set_character_color(t, point, color_class btm_alias); break; case 9: set_character_color(t, point, color_class btm_punctuation); break; case 10: set_character_color(t, point, color_class btm_uservariable); break; case 11: set_character_color(t, point, color_class btm_option); break; case 12: set_character_color(t, point, color_class btm_unknown); break; default: set_character_color(t, point, -1); break; } } if (to < t) set_character_color(to, t, -1); return point; } // Indent the following line more? // // True for lines following one of: // // iff | else | elseiff | do | switch | case | default // // // iff exist regina.dll then // echo Already have a regina.dll here. // elseiff exist "%[JP_EXE_DIR]\regina.dll" then // echo Linking "%[JP_EXE_DIR]\regina.dll" to regina.dll. // mklnk "%[JP_EXE_DIR]\regina.dll" regina.dll // else // echo Cannot link to regina.dll. // endiff // // // do loop_control // commands // iterate // commands // leave // commands // enddo // // // switch %key // case A // echo It's an A // case B .or. C // echo It's either B or C // default // echo It's none of A, B, or C // endswitch // // int btm_indent_more() { if (parse_string(1, "[*@ \t]*(" "iff|else|elseiff|do|switch|case|default" ")")) { return 1; } return 0; } // Indent *this* line less? // // True for lines starting with one of: // // else | elseiff | endiff | enddo | case | default | endswitch // int btm_indent_less() { return parse_string(1, "[*@ \t]*(" "else|elseiff|endiff|enddo|case|default|endswitch" ")") != 0 ? 1 : 0; } // Is this a continuation line? // btm_is_continuation() { save_var point; to_begin_line(); // Substitute in the btm_escape_char value for the caret // 012345v char* continuation_pattern = "(%%=|%^)\n"; continuation_pattern[6] = btm_escape_char; return parse_string(RE_REVERSE, continuation_pattern); } // If this is a continuation line, move back to the actual start. // btm_before_continuation() { while (btm_is_continuation()) nl_reverse(); to_begin_line(); } btm_step() { return (btm_indent > 0) ? btm_indent : tab_size; } // Indent line at orig based on this one. // btm_indent_continuation(orig) { int ind; btm_before_continuation(); ind = get_indentation(point); point = orig; indent_to_column(ind + 2 * btm_step()); } do_btm_indent() on btm_tab['\t'] { if (maybe_indent_rigidly(0)) return; if (this_cmd != CMD_INDENT_REG) this_cmd = C_INDENT; if (current_column() > get_indentation(point) || prev_cmd == C_INDENT) { indent_like_tab(); return; } btm_indenter(); } btm_indenter() { int orig = point, ind; // Put labels and 'rem' comments at column 0. // ('::' comments indent normally) // char* cmnt_or_lbl = "^[ \t]*(:[^:]|[*@]*rem)"; if (matches_at(give_begin_line(), 1, cmnt_or_lbl) || point <= narrow_start) { indent_to_column(0); return; } if (btm_is_continuation()) { btm_indent_continuation(orig); return; } do { to_begin_line(); if (!re_search(-1, "[^ \t\n]")) /* Find previous non-blank line */ break; to_indentation(); } while (parse_string(1, cmnt_or_lbl)); // that's not a comment or label btm_before_continuation(); ind = get_indentation(point); ind += btm_step() * btm_indent_more(); point = orig; if (btm_indent_less()) ind -= btm_step(); to_indentation(); /* go to current line's indent */ indent_to_column(ind); } // recompute this line's indentation without moving point // fix_btm_indentation() { if (in_shell_buffer) return; save_spot point; to_indentation(); btm_indenter(); } // move back to nearest tab stop // unindent if in the initial whitespace of the line // command btm_unindent() on btm_tab[NUMSHIFT(GREYTAB)] { int tab = get_soft_tab_size(), old, old_point; if (maybe_indent_rigidly(1)) return; old = current_column(); old_point = point; to_indentation(); if (point >= old_point) { old_point = point; move_to_column(((current_column() - 1) / tab) * tab); delete(old_point, point); return; } else { point = old_point; } move_to_column(((current_column() - 1) / tab) * tab); if (old && old == current_column()) point--; } command btm_mode() { mode_default_settings(); major_mode = _btm_mode_name; mode_keys = btm_tab; /* Use these keys. */ strcpy(comment_start, "(::|rem)[ \t]*"); strcpy(comment_pattern, "(::|rem).*$"); strcpy(comment_begin, ":: "); strcpy(comment_end, ""); comment_column = 0; recolor_range = color_btm_range; // set up coloring rules recolor_from_here = recolor_by_lines; idle_coloring_size = 10000; if (want_code_coloring) // maybe turn on coloring when_setting_want_code_coloring(); buffer_maybe_break_line = generic_maybe_break_line; fill_mode = misc_language_fill_mode; // indent_with_tabs = btm_indent_with_tabs; indenter = btm_indenter; auto_indent = 1; try_calling("btm-mode-hook"); make_mode(); } when_loading() { btm_tab[ALT('q')] = (short) fill_comment; } suffix_btm() { btm_mode(); } // Comment out the following if you don't want to use this mode on .bat // and .cmd files. // suffix_bat() { btm_mode(); } suffix_cmd() { btm_mode(); }