/* pAssist: - Assist: Cursor jumps to the matching string, OK. - Assist: MLCs don't match. - MatchData mode currently switched off, same compile ifs as assist-6-OK-compile-if.e. */ /****************************** Module Header ******************************* * * Module Name: assist.e * * Copyright (c) Netlabs EPM Distribution Project 2002 * * $Id$ * * =========================================================================== * * This file is part of the Netlabs EPM Distribution package and is free * software. You can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * Netlabs EPM Distribution. This library is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * ****************************************************************************/ /*****************************************************************************/ /* Assist interface for E3 Ralph Yozzo, Larry Margolis */ /* */ /* This macro is intended for use with programming language */ /* which have tokens which must be balanced to compile correctly. */ /* We shall call these tokens "balanceable tokens" or BalTok for */ /* short. */ /* */ /* The functions provided include moving from an opening token */ /* (e.g., (, {, [ ) to a closing token (e.g., ), }, ] ) and vice versa. */ /* */ /* KEYS: */ /* Ctrl-[, Ctrl-], Ctrl-8 -- move to corresponding BalTok) */ /* */ /* CONSTANTS: */ /* gold -BalTok tokens are defined in the const gold and additional */ /* tokens may be added. */ /* */ compile if 0 -- Used here a compile if instead of a comment to enable matching: Example: if ((c=getch())=='c' &&(d=complicatedisntit(e))){ lookforbracket(); } compile endif /* In the above program segment if one places the cursor on an opening */ /* parenthesis and presses Ctrl-[ the cursor will move to the corresponding */ /* closing parenthesis if one exists. Pressing Ctrl-[ again will reverse */ /* the process. */ /* */ /* Modified by Larry Margolis to use the GREP option of Locate to search */ /* for either the opening or closing token, rather than checking a line at */ /* a time. I also changed the key from Ctrl-A to Ctrl-[ or -], which are */ /* newly allowed as definable keys, and deleted the matching of /* and */. */ /* (The GREP search is much faster than the way Ralph did it, but doesn't */ /* let you match either of 2 strings.) Finally, the user's previous search */ /* arguments are saved and restored, so Ctrl-F (repeatfind) will not be */ /* affected by this routine. */ /* */ /* Updated by LAM to use EGREP to also handle #if, #endif, etc. and COMPILE */ /* IF, COMPILE ENDIF, etc. */ /* */ /* 1995/02/21 Updated by LAM to also handle SCRIPT list tags and /* */. */ /* 1995/02/22 Updated by LAM to also handle SGML tags. */ /* */ /* 1999/03/15 Updated by Petr Mikulik, http://www.sci.muni.cz/~mikulik/, to */ /* also handle TeX tokens: \if... \else \fi; \begin... \end...; */ /* \if... \else \fi; \begin{ \end{; \left \right */ /* This patch is part of the "pmCSTeX for EPM" package, see */ /* http://www.sci.muni.cz/~mikulik/os2/pmCSTeX.html */ /*****************************************************************************/ ; 2006 changes: JBS ; A major rework of the code: ; o Bugs were fixed. ; o More tokens are balanced, including the start and end points of ; multi-line comments. ; o More modes supported (PASCAL, FORTRAN77, JAVA, WARPIN). ; o Added initial stages of support for ADA, CSS, PERL, PHP. ; o Code was added to ensure tokens found within comments or literals were ; not matched. ; o Better variable names and code documentation. ; o Contains procs that return if a position is within a multi-line commemt, ; single-line comment or literal. ; o Added a multi-line comment (MLC) array to speed up searching and for ; making MLC matching for modes with nested MLCs reliable. ; After that: aschn ; o Commented out debug messages (minor speed improvement). ; o Replaced searching in the MLC array (big speed improvement). ; o Renamed procs and vars. ; o Added more procs for use from outside. ; o Added optional line and col parameters for querying another than ; current position. ; o Use the comment and literal procs now by tags and syntax expansion. ; 2020 changes: ; o Building the multi-line comment (MLC) array takes much time for longer ; files. For MatchFindOnMove (matching brackets while moving the cursor), ; a simple method is used instead to keep cursor movement fluently. For ; modes that support nested MLCs (E and REXX), the MLC array has to be ; built to determine the within-comment state. ; o That simple method just checks if the previous found MLC string is a ; start or end string. From that, the in-MLC state is determined. ; o If a valid MLC array exists, that one is always used with precedence. ; o The MLC array method is also used for other cases than MatchFindOnMove. ; By the way: For larger files and e.g. TagScan, the array method is ; multiple (something like ten) times faster. ; 2022 changes: ; o Moved all Match procs from KEYS.E. ; o Replaced match limitation consts with config keys. ; o Allow for words instead of chars only to match. ; o MatchData extension: Search for every pair passed within MatchData. ; Avoid to determine opening and closing strings again. ; Ideas: ; o Use attributes for marking MLCs and scan only that region that has ; changed. ; o Use attributes for tags and scan only that region that has changed. compile if not defined( SMALL) -- If compiled separately EA_comment 'Linkable bracket-matching routines.' define INCLUDING_FILE = 'ASSIST.E' include 'stdconst.e' const tryinclude 'mycnf.e' const compile if not defined( NLS_LANGUAGE) NLS_LANGUAGE = 'ENGLISH' compile endif include NLS_LANGUAGE'.e' defmain 'Assist' compile endif -- not defined( SMALL) ; --------------------------------------------------------------------------- const -- NOTE: The logic below relies on GOLD being defined with the left -- "brackets" in the odd positions and the right "brackets" in -- the even positions. GOLD = '(){}[]<>' -- Parens, braces, brackets & angle brackets ASSIST_RC_MLC_MATCHED = -1 ASSIST_RC_NO_ERROR = 0 ASSIST_RC_IN_ONELINE_COMMENT = 1 ASSIST_RC_IN_MULTILINE_COMMENT = 2 ASSIST_RC_IN_LITERAL = 3 ASSIST_RC_NOT_ON_A_TOKEN = 4 ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN = 5 ASSIST_RC_BAD_FORTRAN77_CURSOR = 6 ASSIST_RC_MODE_NOT_SUPPORTED = 7 ASSIST_RC_TOO_MANY_LINES = 8 ASSIST_RC_TOO_MANY_LOOPS = 9 -- JBSQ: The following constants 'hard-code' the versions of NMAKE and -- FORTRAN77 for which pAssist works. Perhaps there is a better way -- that would allow this to be selected by the user? compile if not defined( USE_NMAKE32) USE_NMAKE32 = 1 -- 0 means do not accept NMAKE32-specific directives compile endif compile if not defined( USE_FORTRAN90_SLC) USE_FORTRAN90_SLC = 1 -- 0 means disregard FORTRAN90 SLC: '!' compile endif ; --------------------------------------------------------------------------- ; Syntax: Assist [quiet] [[] ] defc Assist universal vepm_pointer parse arg args wp = wordpos( 'QUIET', upcase( args)) fQuiet = (wp > 0) if wp then args = delword( args, wp, 1) endif if fQuiet then VerboseLevel = 0 -- 0 = quiet, no 'Invalid:' etc. messages (0 also disables pointer change) else VerboseLevel = 1 -- 1 = normal endif parse value args with MaxLines MaxLoops MaxLines = strip( MaxLines) MaxLoops = strip( MaxLoops) if VerboseLevel <> 0 then mouse_setpointer WAIT_POINTER endif fHighlight = 1 fUseArray = 1 call pAssist( VerboseLevel, fHighlight, fUseArray, '', MaxLines, MaxLoops) if VerboseLevel <> 0 then mouse_setpointer vepm_pointer endif ; --------------------------------------------------------------------------- ; o After the first search, the string at cursor (CursorStr) is highlighted. ; o A second search, eventually repeated until a match is found, places the ; cursor at the start of the matched string (MatchStr). Literals, comments ; and nested search strings cause a repetition. ; o Usually MatchData is empty and pAssist works in standard Assist mode. ; It finds the hard-coded strings. ; o If MatchData is set, pAssist works in MatchData mode. The strings ; defined in match_strings are searched then. ; Syntax: pAssist( [VerboseLevel [, fHighlight [, fUseArray [, MatchData ; [, MaxLines [, MaxLoops]]]]]]) ; Parameters: ; VerboseLevel = an integer. Supported are 0 = quiet, 1 = verbose. ; 0 is the default value. ; fHighlight = a flag to indicate if found string should be circled ; (highlighted). The default value is 0. ; fUseArray = a flag for to avoid building the MLC array. ; 0 = don't rebuild array (faster for the near ; surrounding, e.g. for cursor move). ; 1 = rebuild the MLC array if necessary (exact, but ; causes a delay if array must be rebuilt). ; '' The default value is 1. ; MatchData = a string consisting of three words: ; OpenStr CloseStr fForward ; A calling process may use this for to avoid determining ; it again. This is used by AssistMatch and ; MatchFindOnMove. ; Meaning of fForward within MatchData: ; 0 = cursor is on closing string, search backward. ; 1 = cursor is on opening string, search forward. ; In assist mode, this is empty. In MatchData mode, this ; is set. ; MaxLines = an integer to limit the number of lines for searching ; a matched string. If the MLC array is used, MaxLines is ; multiplied by 4. ; The default value is configurable as config key: ; \NEPMD\User\SpecialKeys\MatchMaxLines ; MaxLoops = an integer to limit the number of searches until a match ; is found. Repeated searches are made e.g. within ; comments or nested environments. If the MLC array is ; used, MaxLoops is multiplied by 4. ; The default value is configurable as config key: ; \NEPMD\User\SpecialKeys\MatchMaxLoops ; ; Used vars: ; CursorStr = found word under cursor (or beneath the cursor in some ; cases). ; StartCol = the pos of CursorStr start in current line. ; EndCol = the pos of CursorStr end (last char of CursorStr). ; fForward = a flag to indicate which direction to search ; 1 = forward, 0 = backward. ; CheckList = a space-delimited list of substrings to match on. ; Usually this is a single substring. An example of ; multiple substrings in CheckList would be that an "end" ; in REXX mode can match up with either a "do" or a ; "select" statement. If fForward = 1, then these ; substrings should identify the starting token(s) of the ; bracketed code. If fForward = 0, then these substrings ; should identify the ending token(s). SearchList usually ; contains only the beginning of the strings, until matched ; strings are unique. ; CheckLen = the length of a CheckList element. All elements should ; have the same length. ; RegExp = string for locate command, without seps and options, ; egrep will be used. ; CheckOffset = offset from cursor pos after the search to substring to ; match. The cursor pos, specified with \c in the regex, ; marks also the begin of the highlighted string. ; NestLevel = counter for nesting of matched tokens. On NestLevel = 0, ; the matched token was found. ; fIntermediate = set to 1 if CursorStr is an intermediate conditional token ; (e.g. 'else', but not 'if' or 'endif'). ; IHighlightCol = the start pos of the highlighted string for intermediate ; tokens (e.g. else, elseif). The first search is ; suppressed for them, so that no search data exists for ; them. If not specified, the start is determined from the ; CursorStr at the cursor. HighlightCol is set to this if > 0. ; IHighlightLen = the length of the highlighted string for intermediate ; tokens (e.g. else, elseif). The first search is ; suppressed for them, so that no search data exists for ; them. If not specified, the length is determined from ; the CursorStr at the cursor. HighlightLen is set to this if > 0. ; TexEnvStr = a string to submit the searched TEX environment name, ; surrounded by braces and preceded by '\begin' or \'end'. ; fECompile = a flag to indicate if an E condition is preceded by ; 'compile'. ; 0 = not included or not a condition. ; 1 = 'compile' included, ; 'compile if|...' uses 1, 'if|...' uses 0. ; match_strings = universal var with word pairs of matching strings: ; OpenStr1 CloseStr1 OpenStr2 CloseStr2 ... ; MatchStr = the found string that matches CursorStr. defproc pAssist universal match_strings call pSave_Pos( SavedPos) -- Save the cursor location getsearch SavedSearch -- Save user's search command StartLineNum = .line VerboseLevel = arg( 1) fHighlight = arg( 2) -- TODO: fUseArray overridden later? ######################### fUseArray = arg( 3) MatchData = arg( 4) MaxLines = arg( 5) MaxLoops = arg( 6) dprintf( 'pAssist: VerboseLevel = 'VerboseLevel', fHighlight = 'fHighlight', fUseArray = 'fUseArray || ', MatchData = 'MatchData', MaxLines = 'MaxLines', MaxLoops = 'MaxLoops) if VerboseLevel < 1 then VerboseLevel = 0 endif if fHighlight <> 1 then fHighlight = 0 endif if fUseArray <> 0 then fUseArray = 1 endif /* if MatchData = '' then -- Search for match_strings at cursor MatchData = GetMatchData() endif */ if MatchData = '' then OpenStr = '' CloseStr = '' fForward = 1 -- init StartCol = 1 EndCol = 1 else parse value MatchData with OpenStr CloseStr fForward StartCol EndCol endif KeyPath = '\NEPMD\User\SpecialKeys' if MaxLines = '' then MaxLines = QueryConfigKey( KeyPath'\MatchMaxLines') endif if MaxLoops = '' then MaxLoops = QueryConfigKey( KeyPath'\MatchMaxLoops') endif -- The non-array version can not be used for retrieving pos. data or for -- finding the matching MLC string. It should only be used for -- MatchFindOnMove. For repeated use and long texts, the array version -- is much faster. It causes a short delay to scan the entire file and -- leads to non-fluently cursor move. call SetAVar( 'assist.fUseArray', fUseArray) -- Searching within the MLC array is much faster, but it has to be built -- before. The limits can be larger if the array is used. if fUseArray then MaxLines = MaxLines * 4 MaxLoops = MaxLoops * 4 endif SearchLimitData = StartLineNum MaxLines MaxLoops -- Use one arg for AssistSearch to save args CursorStr = '' -- token under cursor RegExp = '' fForward = 1 CheckList = '' CheckLen = 1 CheckOffset = 0 -- cursor offset for CheckList keyword(s) after the search NestLevel = 1 fIntermediate = 0 IHighlightCol = 0 IHighlightLen = 0 TexEnvStr = '' fECompile = 0 assist_rc = 0 -- Init search position data for highlighting HighlightLine = .line HighlightCol = .col HighlightLen = 1 --#dprintf( "pAssist", "------------------------------------------------------------") --#dprintf( "pAssist", "Initial cursor: ".line",".col) Mode = NepmdGetMode() -- These are MLCs in E and just be better used as variables to allow -- using them as MLCs in E, here in this code: (The E compiler doesn't -- handle strings correctly.) SlashStar = '/'||'*' StarSlash = '*'||'/' do once = 1 to 1 fCaseSensitive = QueryModeKey( Mode, 'CaseSensitive') if fCaseSensitive then Case = 'e' else Case = 'c' endif -- TODO: fUseArray a 2nd time? ######################### -- InsideComment2 -> LocateMLC may have changed fUseArray for modes -- that support nested MLCs fUseArray = GetAVar( 'assist.fUseArray') assist_rc = InsideComment2( Mode, CommentData) --#dprintf( "pAssist", "comment return:" assist_rc CommentData) if assist_rc = ASSIST_RC_IN_MULTILINE_COMMENT then parse value CommentData with MlcStartLine MlcStartCol MlcStartLen MlcEndLine MlcEndCol MlcEndLen -- If cursor on start, move to the end if .line = MlcStartLine & .col - MlcStartCol < MlcStartLen then .line = MlcEndLine .col = MlcEndCol HighlightLine = MlcStartLine HighlightCol = MlcStartCol HighlightLen = MlcStartLen assist_rc = ASSIST_RC_MLC_MATCHED -- If cursor on end, move to the start elseif .line = MlcEndLine & .col >= MlcEndCol then .line = MlcStartLine .col = MlcStartCol HighlightLine = MlcEndLine HighlightCol = MlcEndCol HighlightLen = MlcEndLen assist_rc = ASSIST_RC_MLC_MATCHED else assist_rc = ASSIST_RC_IN_MULTILINE_COMMENT leave endif endif if InsideLiteral( Mode) then assist_rc = ASSIST_RC_IN_LITERAL leave endif compile if 0 -- #################################################################################################################### -- This is the problem -- It prevents search. It seems as if it does nothing. -- MatchData is empty, except for pairs found in match_strings. 'if endif' -- are in match_strings. And this is only triggered if the cursor is at -- the start of a MatchStr. Otherwise the normal Assist match is applied. -- It does nothing, because the rest processing for MatchData is missing. -- -> Make MatchStr work if cursor is an any pos. of a MatchStr. -- -> Add the rest for MatchData processing. E.g. nesting is missing. -- ================================================= if MatchData <> '' then if fForward then CursorStr = OpenStr else CursorStr = CloseStr endif CheckList = CursorStr CheckLen = length( CursorStr) RegExp = '('EscapeSearchChars( OpenStr)'|'EscapeSearchChars( CloseStr)')' dprintf( 'pAssist: RegExp = 'RegExp', MatchData = 'MatchData) leave endif compile endif getline LineStr TabWidth = word( .tabs, 1) LineStr = TabExpandStr( LineStr, TabWidth, dummy) -- Determine RegExp and vars for brackets CurChar = substr( LineStr, .col, 1) pBracketChar = pos( CurChar, GOLD) -- '(){}[]<>' -- Braces, '{}', can be matched with BEGIN and END in RC files. -- So they need to be handled separately. if pBracketChar then if pos( CurChar, '{}') & Mode = 'RC' then pBracketChar = 0 endif endif -- If BracketChar, then set RegExp to the corresponding char out of GOLD if pBracketChar then LeftBracket = substr( GOLD, (pBracketChar + 1) % 2 * 2 - 1, 1) RightBracket = substr( GOLD, (pBracketChar + 1) % 2 * 2, 1) -- Escape brackets with '\' RegExp = '[\'LeftBracket'\'RightBracket']' -- New: CursorStr must be set for HighlightLen. ##################################### CursorStr = CurChar CheckList = CursorStr CheckLen = length( CursorStr) fForward = pBracketChar // 2 leave endif -- Build the separator list for find_token if Mode = 'FORTRAN77' then Seps = "+-"SlashStar"=().,':$" else Seps = ' ~`!.%^&*()-+=][{}|\;?<>,''"'\t endif if Mode = 'TEX' then -- Move cursor right if it is on \backslash if substr( LineStr, .col, 1) = '\' then right endif endif -- Get the word under cursor and return StartCol and EndCol -- Stop at separators = arg( 3) -- Stop at double char separators = arg( 4) -- Checking for SlashStar and StarSlash is not required here, because of -- InsideComment2 above. compile if 1 -- This is OK if not Find_Token( StartCol, EndCol, Seps, 'NONE:') then assist_rc = ASSIST_RC_NOT_ON_A_TOKEN leave endif dprintf( 'Find_Token returns StartCol = 'StartCol', EndCol = 'EndCol) compile else -- #################################################################################################################### -- This is the problem -- It prevents to work if the cursor is on the start of CursorStr. It works from -- other pos. -- ================================================= if MatchData = '' then if not Find_Token( StartCol, EndCol, Seps, 'NONE:') then assist_rc = ASSIST_RC_NOT_ON_A_TOKEN leave endif endif compile endif --#dprintf( "pAssist", "Initial token start,end: "StartCol","EndCol) if StartCol > 1 then PrevChar = substr( LineStr, StartCol - 1, 1) if PrevChar = '<' then if wordpos( Mode, 'HTML WARPIN') then -- Add '<' to found word if it is on the left side of it -- this assumes ALL balanceable tokens for HTML and WARPIN -- start with '<' StartCol = StartCol - 1 endif elseif PrevChar = '\' then if Mode = 'TEX' then --//PM TeX macros are preceded by \backslash which is also separator -- Add '\' to found word if it is on the left side of it StartCol = StartCol - 1 endif endif elseif StartCol = 1 then -- if cursor is on the first column of a MAKE directive if leftstr( LineStr, 1) = '!' then -- "shift" the CursorStr to the following token if Mode = 'MAKE' then newstart = verify( LineStr, ' '\t, 'N', 2) -- skip to next non-whitespace if newstart then newend = verify( LineStr' ', ' ', 'M', newstart) if newend then StartCol = newstart EndCol = newend - 1 endif endif endif endif endif -- CursorStr = found word CursorStr = substr( LineStr, StartCol, (EndCol - StartCol) + 1) --#dprintf( "pAssist", "Token after preprocessing : '"CursorStr"' Startcol: "StartCol" Endcol: "EndCol) -- Set/re-init search position data for highlighting HighlightLine = .line HighlightCol = StartCol HighlightLen = EndCol - StartCol + 1 if 0 then -- just a placeholder so the following ELSEIFs can be freely reordered -- Mode(s): E ------------------------------------------------------------------------------- elseif Mode = 'E' then --dprintf( "pAssist", "E Token after : '"CursorStr"'") CursorStr = lowcase( CursorStr) LineStr = lowcase( LineStr) if 0 then -- another placeholder ---- E compiler directives: compile if, compile else, compile elseif, compile endif elseif CursorStr = 'compile' then Temp = substr( LineStr, pos( CursorStr, LineStr)) --#dprintf( "pAssist", "Initial Temp: "Temp) do while (pos( SlashStar, Temp) > 0) & (pos( StarSlash, Temp) > 0) Temp = substr( Temp, pos( StarSlash, Temp)) --#dprintf( "pAssist", "Intermediate Temp: "Temp) enddo --#dprintf( "pAssist", "Final Temp: "Temp) if (words( Temp) = 0) then assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN else CursorStr2 = word( Temp, 2) --#dprintf( "pAssist", "CursorStr2: "CursorStr2) if wordpos( CursorStr2, 'if endif else elseif') then pcompile = pos( 'compile', LineStr) pcondition = pos( CursorStr2, LineStr, pcompile + 8) CheckOffset = pcondition - pcompile IHighlightCol = pcompile IHighlightLen = pcondition + length( CursorStr2) - pcompile -- compile if/... code (when cursor is on compile RegExp = '^[ \t]*\ccompile[ \t]*(/\*.*\'StarSlash')*[ \t]*(end)?if([; \t]|(--)|(/\*)|$)' CheckList = leftstr( CursorStr2, 1) fForward = (CheckList <> 'e') if fForward then -- move to beginning .col = StartCol else -- move to end, so first Locate will hit this instance. endline endif fIntermediate = (substr( CursorStr2, 2, 1) = 'l') else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif endif ---- E conditions: (compile) if, (compile) else, (compile) elseif, (compile) endif elseif wordpos( CursorStr, 'if endif else elseif') then pcompile = pos( 'compile', LineStr) if pcompile & pcompile <= StartCol then -- compile if|endif|else|elseif fECompile = 1 parse value LineStr with part1 'compile' part2 (CursorStr) part3 --#dprintf( 'pAssist', 'E if parse: "'part1'"compile"'part2'"'CursorStr'"'part3'"') part1 = strip( part1) part2 = strip( part2) if (part1 = '' | ((length( part1) >= 4) & (leftstr( part1, 2) = SlashStar) & (rightstr( part1, 2) = StarSlash))) & (part2 = '' | ((length( part2) >= 4) & (leftstr( part2, 2) = SlashStar) & (rightstr( part2, 2) = StarSlash))) then pcompile = pos( 'compile', LineStr) pcondition = pos( CursorStr, LineStr, pcompile + 8) CheckOffset = pcondition - pcompile IHighlightCol = pcompile IHighlightLen = pcondition + length( CursorStr) - pcompile -- compile if/... code (when cursor is on if/... --RegExp = '^[ \t]*compile[ \t]*(/\*.*\'StarSlash')*[ \t]*\c(end)?if([; \t]|(--)|(/\*)|$)' RegExp = '^[ \t]*\ccompile[ \t]*(/\*.*\'StarSlash')*[ \t]*(end)?if([; \t]|(--)|(/\*)|$)' CheckList = leftstr( CursorStr, 1) fForward = (CheckList <> 'e') if fForward then -- move to beginning .col = length( part1) + 1 else -- move to end, so first Locate will hit this instance. endline endif fIntermediate = (substr( CursorStr, 2, 1) = 'l') else -- /* compile */ if/... code RegExp = '(^|[ \t]|(\'StarSlash'))\c(end)?if([; \t]|(--)|(/\*)|$)' CheckList = leftstr( CursorStr, 1) fForward = (CheckList <> 'e') if fForward then -- move to beginning .col = StartCol else -- move to end, so first Locate will hit this instance. .col = EndCol endif fIntermediate = (substr( CursorStr, 2, 1) = 'l') endif else -- if|endif (without compile) -- The found line is checked by a 2nd search for a preceding 'compile', -- otherwise the re would have two many parentheses. --RegExp = '((\'StarSlash':o)|(^:o)|(^:o(~compile:w)))\c(end)?if([; \t]|(--)|(/\*)|$)' --RegExp = '((\'StarSlash':o)|(;:o)|(^:o)|(^:o(~compile:w)))\c(end)?if([; \t]|(--)|(/\*)|$)' RegExp = '(^|[ \t]|(\'StarSlash'))\c(end)?if([; \t]|(--)|(/\*)|$)' CheckList = leftstr( CursorStr, 1) fForward = (CheckList <> 'e') if fForward then -- move to beginning .col = StartCol else -- move to end, so first Locate will hit this instance. .col = EndCol endif fIntermediate = (substr( CursorStr, 2, 1) = 'l') endif ---- E loop keywords 1: loop, endloop elseif wordpos( CursorStr, 'loop endloop') then RegExp = '(^|[ \t]|(\'StarSlash'))\c(end)?loop([; \t]|(--)|(/\*)|$)' CheckList = leftstr( CursorStr, 1) fForward = (CheckList <> 'e') if fForward then -- move to beginning .col = StartCol else -- move to end, so first Locate will hit this instance. .col = EndCol endif ---- E loop keywords 2: for, endfor elseif wordpos( CursorStr, 'for endfor') then RegExp = '(^|[ \t]|(\'StarSlash'))\c(end)?for([; \t]|(--)|(/\*)|$)' CheckList = leftstr( CursorStr, 1) fForward = (CheckList <> 'e') if fForward then -- move to beginning .col = StartCol else -- move to end, so first Locate will hit this instance. .col = EndCol endif ---- E loop keywords 3: do, while, end, enddo, endwhile elseif wordpos( CursorStr, 'do while end enddo endwhile') then if (CursorStr = 'end') then RegExp = '(^|[ \t]|(\'StarSlash'))\c(do|end|enddo)([; \t]|(--)|(/\*)|$)' elseif (CursorStr = 'enddo') then RegExp = '(^|[ \t]|(\'StarSlash'))\c(do|end|enddo)([; \t]|(--)|(/\*)|$)' elseif (CursorStr = 'endwhile') then RegExp = '(^|[ \t]|(\'StarSlash'))\c(end)?while([; \t]|(--)|(/\*)|$)' else -- check for do and/or while LeftLineStr = leftstr( LineStr, StartCol - 1) if (CursorStr = 'do') then -- Check if 'while' comes before 'do' pWhile = lastpos( 'while', LeftLineStr) if pWhile then -- while ... do CursorStr = 'while' RegExp = '(^|[ \t]|(\'StarSlash'))\c(end)?while([; \t]|(--)|(/\*)|$)' StartCol = pWhile else -- do RegExp = '(^|[ \t]|(\'StarSlash'))\c(do|end|enddo)([; \t]|(--)|(/\*)|$)' endif elseif (CursorStr = 'while') then -- Check the if 'do' is the word before 'while' CursorWord0 = strip( lastword( LeftLineStr)) pCursorWord0 = wordindex( LeftLineStr, Max( 1, words( LeftLineStr))) if CursorWord0 = 'do' then -- do while ... CursorStr = 'do' RegExp = '(^|[ \t]|(\'StarSlash'))\c(do|end|enddo)([; \t]|(--)|(/\*)|$)' StartCol = pCursorWord0 else -- while ... RegExp = '(^|[ \t]|(\'StarSlash'))\c(end)?while([; \t]|(--)|(/\*)|$)' endif endif endif --#dprintf( "pAssist", "RegExp: "RegExp) CheckList = leftstr( CursorStr, 1) --#dprintf( "pAssist", "CheckList: "CheckList) fForward = (CheckList <> 'e') if fForward then -- move to beginning .col = StartCol else -- move to end, so first Locate will hit this instance. .col = EndCol endif ---- E loop keywords 4: leave, iterate elseif wordpos( CursorStr, 'leave iterate') then RegExp = '(^|[ \t]|(\'StarSlash'))\c(do|end|enddo|loop|endloop|for|endfor|endwhile)([; \t]|(--)|(/\*)|$)' fForward = 0 CheckList = 'e' CheckLen = 1 .col = EndCol fIntermediate = 1 else -- not a known balanceable E token assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif -- Mode(s): C, JAVA JAVASCRIPT and RC ------------------------------------------------------- elseif wordpos( Mode, 'C JAVA RC JAVASCRIPT') > 0 then -- C allows for spaces between '#' and keyword, JAVA, RC and JAVASCRIPT don't. if Mode = 'C' then if wordpos( CursorStr, 'if ifdef ifndef endif else elif') > 0 then -- Check for "# if", etc. .col = StartCol if NextCodeChar( Mode, .line, .col, '-R') = '#' then CursorStr = '#'CursorStr StartCol = .col endif call pRestore_Pos( SavedPos) endif endif if 0 then --placeholder ---- Directive(s): #if #ifdef #ifndef #endif #else #elif elseif wordpos( CursorStr, '#if #ifdef #ifndef #endif #else #elif') then if Mode <> 'JAVA' & Mode <> 'JAVASCRIPT' then RegExp = '\#[ \t]*\c((if((n?def)?))|endif)([ \t]|$)' if Mode = 'C' then RegExp = '^[ \t]*\c'RegExp elseif StartCol = 1 then -- RC directives must start in column one RegExp = '^'RegExp else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif CheckList = substr( CursorStr, 2, 1) fForward = (CheckList = 'i') if fForward then -- move to beginning .col = StartCol else -- move to end, so first Locate will hit this instance. .col = EndCol endif fIntermediate = (substr( CursorStr, 3, 1) = 'l') else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif ---- Keyword(s): do, try elseif wordpos( CursorStr, 'do try') then -- this code might be expanded to { .... } if Mode <> 'RC' then setsearch 'xcom l /[{;]/xe+F' -- does following a '{' precede a ';'? CheckList = '{ ;' CheckOffset = 0 CheckLen = 1 NestLevel = -1 -- -1 = stop on first 'hit' assist_rc = AssistSearch( Mode, CheckList, Case, CheckOffset, CheckLen, NestLevel, SearchLimitData) if assist_rc then assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN else --#dprintf( "pAssist", "token {} '{;' RegExp found: "substr( textline( .line), .col, 1)) if substr( textline( .line), .col, 1) = '{' then -- found the braces RegExp = '[{}]' fForward = 1 CheckList = '{' else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN -- token without braces endif endif else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif ---- Keyword(s): while elseif CursorStr = 'while' then if Mode <> 'RC' then setsearch 'xcom l /[()]/xe+F' -- find the end of the conditional CheckList = '{' CheckOffset = 0 CheckLen = 1 NestLevel = 0 assist_rc = AssistSearch( Mode, CheckList, Case, CheckOffset, CheckLen, NestLevel, SearchLimitData) if assist_rc then -- no conditional?? assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN else nextchar = NextCodeChar( Mode) if not nextchar then assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN else --#dprintf( "pAssist", "while {; RegExp found: "nextchar) if nextchar = '{' then -- must be while loop (i.e. NOT do/while) with braces RegExp = '[{}]' fForward = 1 CheckList = '{' elseif nextchar = ';' then -- cursor is on the 'while' of a do/while loop --RegExp = '\{|\}|((^|[ \t])\cdo([ \t]|$))' RegExp = '[{}]|((^|[ \t])\cdo([ \t]|$))' fForward = 0 CheckList = '}' NestLevel = 2 else -- cursor is on a one-statement while loop assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN -- no braces follow, so JBSQ: unbalanceable? endif endif endif endif /* JBSQ: The following code should work for break/continue statements within nested do and for loops which have braces. Problems arise if there are DOs or FORs without braces between the break/continue and the enclosing loop. Also problems arise if the enclosing loop is a while loop. The solution, if it is worth it, is to code the entire search here so that these different variations of loops can be handled correctly. ---- Keyword(s): break continue elseif wordpos( CursorStr, 'break continue' then if Mode <> 'RC' then RegExp = '([{}])|((^|[ \t])\c(do|for)([ \t]|$))' fForward = 0 CheckList = '}' fIntermediate = 1 else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif */ elseif Mode = 'RC' then -- All remaining RC tokens here CursorStr = lowcase( CursorStr) if wordpos( CursorStr, '{ } begin end') then RegExp = '[{}]|((^|[ \t])\c(begin|end)([ \t;]|$))' fForward = (wordpos( CursorStr, '{ begin') > 0) if fForward then -- move to beginning begin .col = StartCol CheckList = '{ b' else -- move to end, so first Locate will hit this instance. .col = EndCol CheckList = '} e' endif else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif else -- All remaining C/JAVA/JAVASCRIPT tokens here idlist = 'case default default:' if Mode <> 'C' then idlist = idlist 'finally' endif if wordpos( CursorStr, idlist) then RegExp = '[{}]' fForward = 0 CheckList = '}' fIntermediate = 1 else -- This code seems to handle matching the beginning and end of -- a) functions when the cursor is on a token preceding the -- parameter list -- b) 'if' when the 'if' has following braces -- c) 'for' when the 'for' has following braces -- d) 'switch' statements -- e) anything of the structure: token ( ) { ... } -- e.g. catch ( ) { ... } -- JBSQ: Check for NextCodeChar( Mode) = '(' first? -- (This would force the cursor to actually be on the function -- name. The current code allows the cursor on any nonblank, -- noncomment, nonliteral character preceding the parameter -- list.) setsearch 'xcom l /[()]/xe+F' -- find the ending ')' or ; CheckList = '{' CheckOffset = 0 CheckLen = 1 NestLevel = 0 assist_rc = AssistSearch( Mode, CheckList, Case, CheckOffset, CheckLen, NestLevel, SearchLimitData) --#dprintf( 'pAssist', 'last chance c,... srch_rc line col' assist_rc .line .col) if not assist_rc & substr( textline( .line), .col, 1) = ')' then -- no conditional?? assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN NextChar = NextCodeChar( Mode) if NextChar then --#dprintf( "pAssist", "Generic token () {; RegExp found: "nextchar) if NextChar = '{' then -- structure is: token ( ) { ... } RegExp = '[{}]' fForward = 1 CheckList = '{' assist_rc = ASSIST_RC_NO_ERROR endif endif else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif endif endif -- Mode(s): REXX ---------------------------------------------------------------------------- elseif Mode = 'REXX' then ---- REXX conditions: if, else CursorStr = lowcase(CursorStr) if 0 then -- another placeholder elseif wordpos( CursorStr, 'do end select when otherwise') then RegExp = '(^|[ \t])\c(do|end|select)([; \t]|$)' fForward = (wordpos(CursorStr, 'do select') > 0) if fForward then -- move to beginning CheckList = 'do se' .col = StartCol else -- move to end, so first Locate will hit this instance. CheckList = 'en' .col = EndCol endif CheckLen = 2 fIntermediate = ((CursorStr = 'when') | (CursorStr = 'otherwise')) elseif CursorStr = 'else' then .col = StartCol PrevChar = NextCodeChar( Mode, .line, .col, '-R') --#dprintf( "pAssist", 'Previous char:' pchar) if lowcase( PrevChar) = 'd' then if .col > 2 then .col = .col - 2 PrevWord = lowcase( substr( textline( .line), .col, 3)) if .col > 1 & substr( textline( .line), .col - 1, 1) <> ' ' then -- else --#dprintf( "pAssist", 'Previous word:' PrevWord) if PrevWord = 'end' then display -1 call pAssist( VerboseLevel, fHighlight) display 1 EndCol = .col endif endif endif endif RegExp = '(^|[ \t])\cif([ \t]|$)' CheckList = 'i' fForward = 0 fIntermediate = 1 .col = EndCol NestLevel = -1 compile if 0 elseif wordpos( CursorStr, 'if else') then -- JBSQ: How is this supposed to work? IFs don't always have ELSEs RegExp = '(^|[ \t])(if|else)([ \t]|$)' CheckList = leftstr( CursorStr, 1) fForward = (CheckList <> 'e') if fForward then -- move to beginning .col = StartCol else -- move to end, so first Locate will hit this instance. .col = EndCol endif compile endif else -- not a known balanceable REXX token assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif -- Mode(s): IPF ----------------------------------------------------------------------------- elseif Mode = 'IPF' then -- IPF tags start with ':' and end with '.' -- If CursorStr = '.', then go 1 col left if CursorStr = '.' & .col > 1 then left if Find_Token( StartCol, EndCol) then CursorStr = substr( LineStr, StartCol, (EndCol - StartCol) + 1) endif endif if pos( ':', CursorStr) > 1 then -- :tag, separate the :tag CursorStr = substr( CursorStr, pos( ':', CursorStr)) endif if length( LineStr) > EndCol then if (pos( substr( LineStr, EndCol + 1, 1), '. ')) then IPFBeginTags = ':artlink :caution :cgraphic :ctrldef :fn :hide' IPFBeginTags = IPFBegintags ':hp1 :hp2 :hp3 :hp4 :hp5 :hp6 :hp7 :hp8 :hp9' IPFBeginTags = IPFBegintags ':lines :link :nt :userdoc :warning :xmp' IPFEndTags = ':eartlink :ecaution :ecgraphic :ectrldef :efn :ehide' IPFEndTags = IPFEndTags ':ehp1 :ehp2 :ehp3 :ehp4 :ehp5 :ehp6 :ehp7 :ehp8 :ehp9' IPFEndTags = IPFEndTags ':elines :elink :ent :euserdoc :ewarning :exmp' IPFTags = IPFBeginTags IPFEndTags --#dprintf( "pAssist", "IPF ID wordpos: "wordpos( CursorStr, IPFTags)) --#dprintf( "pAssist", "IPF Tags: "IPFTags) CheckOffset = 1 -- omit the leading ':' in words of CheckList if wordpos( CursorStr, IPFTags) then CheckList = substr( CursorStr, 2, 1) -- Character to check to see if it's an end tag fForward = (CheckList <> 'e') -- fForward = 1 if searching forward; 0 if backwards if fForward then -- move to beginning .col = StartCol CursorStr = substr( CursorStr, 2) else -- move to end, so first Locate will hit this instance. .col = EndCol + 1 CursorStr = substr( CursorStr, 3) endif RegExp = '\:e?'CursorStr'(\.| )' elseif wordpos( CursorStr, ':ol :ul :sl :eol :eul :esl :li :lp') then fIntermediate = (CursorStr = ':li' | CursorStr = ':lp') fForward = (wordpos( CursorStr, ':ol :ul :sl') > 0) -- fForward = 1 if searching forward; 0 if backwards if fForward then -- move to beginning .col = StartCol CursorStr = substr( CursorStr, 2) CheckList = 'ol ul sl' CheckLen = 2 else -- move to end, so first Locate will hit this instance. .col = EndCol + 1 CursorStr = substr( CursorStr, 3) CheckList = 'eol eul esl' CheckLen = 3 endif RegExp = '\:e?(o|u|s)l(\.| )' elseif wordpos( CursorStr, ':table :etable :row :c') then fIntermediate = (CursorStr = ':row' | CursorStr = ':c') fForward = (CursorStr = ':table') -- fForward = 1 if searching forward; 0 if backwards if fForward then -- move to beginning .col = StartCol CheckList = 'table' CheckLen = 5 CursorStr = substr( CursorStr, 2) else -- move to end, so first Locate will hit this instance. .col = EndCol + 1 CheckList = 'etable' CheckLen = 6 CursorStr = substr( CursorStr, 3) endif RegExp = '\:e?table(\.| )' elseif wordpos( CursorStr, ':parml :eparml :pt :pd') then fIntermediate = (CursorStr = ':pt' | CursorStr = ':pd') fForward = (CursorStr = ':parml') -- fForward = 1 if searching forward; 0 if backwards if fForward then -- move to beginning .col = StartCol CursorStr = substr( CursorStr, 2) CheckList = 'parml' CheckLen = 5 else -- move to end, so first Locate will hit this instance. .col = EndCol + 1 CursorStr = substr( CursorStr, 3) CheckList = 'eparml' CheckLen = 6 endif RegExp = '\:e?parml(\.| )' elseif wordpos( CursorStr, ':dl :dthd :ddhd :dt :dd :edl') then fIntermediate = (wordpos( CursorStr, ':dthd :ddhd :dt :dd') > 0) fForward = (CursorStr = ':dl') -- fForward = 1 if searching forward; 0 if backwards if fForward then -- move to beginning .col = StartCol CursorStr = substr( CursorStr, 2) CheckList = 'dl' CheckLen = 2 else -- move to end, so first Locate will hit this instance. .col = EndCol + 1 CursorStr = substr( CursorStr, 3) CheckList = 'edl' CheckLen = 3 endif RegExp = '\:e?dl(\.| )' elseif wordpos( CursorStr, ':fig :efig :figcap') then fIntermediate = (CursorStr = ':figcap') fForward = (CursorStr = ':fig') -- fForward = 1 if searching forward; 0 if backwards if fForward then -- move to beginning .col = StartCol CursorStr = substr( CursorStr, 2) else -- move to end, so first Locate will hit this instance. .col = EndCol + 1 CursorStr = substr( CursorStr, 3) endif RegExp = '\:e?fig(\.| )' else -- not a known balanceable IPF token assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif else -- not a known balanceable IPF token assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif else -- not a known balanceable IPF token assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif -- Mode(s): HTML, WARPIN, XML --------------------------------------------------------------- elseif wordpos( Mode, 'HTML WARPIN XML') then ---- HTML tags: <..., if leftstr( CursorStr, 1) = '<' then CheckList = substr( CursorStr, 2, 1) -- Character to check to see if it's the same or the other fForward = (CheckList <> '/') -- fForward = 1 if searching forward; 0 if backwards if fForward then -- move to beginning CursorStr = substr( CursorStr, 2) -- Strip off the '<' CheckList = CursorStr .col = StartCol else -- move to end, so first Locate will hit this instance. CursorStr = substr( CursorStr, 3) -- Strip off the '' after the tag endif RegExp = '<\c/?'CursorStr'(>| )' -- Use \c to not put cursor on angle bracket. CheckLen = length( CheckList) else -- not a known balanceable HTML token assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif -- Mode(s): MAKE ---------------------------------------------------------------------------- elseif Mode = 'MAKE' then CursorStr = lowcase( CursorStr) -- Currently ALL balanceable MAKE tokens must be on a line with -- '!' in column 1 and if there are any characters between the '!' -- and the token they must be whitespace. if leftstr( LineStr, 1) = '!' then if StartCol > 2 then -- Are there characters between '!' and token? if verify( substr( LineStr, 2, StartCol - 2), ' '\t) then assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN CursorStr = '' -- Disable further processing endif endif if 0 then -- placeholder compile if USE_NMAKE32 elseif wordpos( CursorStr, 'if ifdef ifndef endif else elif elseif') then compile else elseif wordpos( CursorStr, 'if ifdef ifndef endif else') then compile endif RegExp = '^![ \t]*\c(if((n?def)?)|endif)([ \t]|$)' CheckList = leftstr( CursorStr, 1) fForward = (CheckList = 'i') if fForward then -- move to beginning .col = 1 else -- move to end, so first Locate will hit this instance. .col = EndCol endif fIntermediate = (substr( CursorStr, 2, 1) = 'l') compile if USE_NMAKE32 elseif wordpos( CursorStr, 'foreach endfor') then -- NMAKE32 RegExp = '^![ \t]*\c(foreach|endfor)([ \t]|$)' CheckList = leftstr( CursorStr, 1) fForward = (CheckList = 'f') if fForward then -- move to beginning .col = 1 else -- move to end, so first Locate will hit this instance. .col = EndCol endif fIntermediate = (wordpos( CursorStr, 'else elif elseif') > 0) compile endif else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif -- Mode(s): Pascal -------------------------------------------------------------------------- elseif Mode = 'PASCAL' then CursorStr = lowcase( CursorStr) PascalStartBlockTokens = 'begin record try asm case unit object class' -- interface? if wordpos( CursorStr, PascalStartBlockTokens 'end except finally') then RegExp = '(^|[^a-zA_Z0-9_])\c('translate( PascalStartBlockTokens, '|', ' ')'|end)([;. \t]|$)' fForward = (wordpos( CursorStr, PascalStartBlockTokens) > 0) CheckLen = 3 if fForward then .col = StartCol CheckList = '' do i = 1 to words( PascalStartBlockTokens) CheckList = CheckList leftstr( word( PascalStartBlockTokens, i), 3) enddo else .col = EndCol CheckList = 'end' endif fIntermediate = (CursorStr = 'except' | CursorStr = 'finally') elseif wordpos( CursorStr, 'repeat until') then RegExp = '(^|[ \t])\c(repeat|until)([ \t]|$)' fForward = (CursorStr = 'repeat') if fForward then .col = StartCol CheckList = 'r' else .col = EndCol CheckList = 'u' endif elseif wordpos( CursorStr, 'while for') then -- Check for begin before ';' (i.e a block loop instead of a -- single statement loop) setsearch 'xcom l /[ \t]\cdo([ \t]|$)/x'Case'c+F' -- find the end of following 'do' CheckList = 'd' CheckOffset = 0 CheckLen = 1 NestLevel = -1 -- -1 = stop on first 'hit' assist_rc = AssistSearch( Mode, CheckList, Case, CheckOffset, CheckLen, NestLevel, SearchLimitData) do once2 = 1 to 1 if assist_rc then -- no 'do'?? assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN leave endif .col = .col + 2 nextchar = NextCodeChar( Mode) if not nextchar then assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN leave endif do once3 = 1 to 1 --#dprintf( "pAssist", "while/for 'do' RegExp found: "nextchar) assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN -- assume bad if lowcase( nextchar) <> 'b' then leave endif tmpline = textline( .line) tmpline_len = length( tmpline) --#dprintf( "pAssist", "col: ".col "len: "tmpline_len "line: "tmpline) if tmpline_len < .col + 4 then leave endif if lowcase( substr( tmpline, .col, 5)) <> 'begin' then leave endif if (tmpline_len > .col + 4) then nextchar = substr( tmpline, .col + 5, 1) --#dprintf( "pAssist", "charafter: '"nextchar"'") if nextchar = ' ' | nextchar = \9 then assist_rc = ASSIST_RC_NO_ERROR endif else assist_rc = ASSIST_RC_NO_ERROR endif if not assist_rc then RegExp = '(^|[ \t])\cbegin|end([;. \t]|$)' fForward = 1 CheckList = 'b' endif enddo enddo else assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif -- Mode(s): TEX ----------------------------------------------------------------------------- elseif Mode = 'TEX' then -- NOTE: There is some special code for \begin and \end which depends -- on 'CheckList' being set to 'be' or 'en'. If it becomes necessary -- to use these values for 'CheckList' for other TEX tokens, then the -- special code for \begin and \end will break. CheckOffset = 1 -- omit the leading '\' in words of CheckList -- //PM additions: balanceable tokens for (La)TeX ---- TeX conditions: \if, \else, \fi if substr( CursorStr, 1, 3) = '\if' | wordpos( CursorStr, '\else \fi') then --// \if.. \else \fi RegExp = '\\(if|fi)' CheckList = substr( CursorStr, 2, 1) fForward = (CheckList = 'i') -- fForward=1: forward, fForward=0 backward search if fForward then -- move cursor so that the first Locate will hit this instance .col = StartCol -- \if: move to beginning else .col = EndCol -- \else,\fi: move to end endif fIntermediate = (CursorStr = '\else') ---- TeX environment: \begin..., \end... elseif CursorStr = '\begin' | CursorStr = '\end' then --// \begin.. \end.. RegExp = '\\(begin|end)[ \t]*' ---- LaTeX environment: \begin{...}, \end{...} .col = EndCol if NextCodeChar( Mode) == '{' then --#dprintf( 'pAssist', 'TEX: found } at '.line .col) Temp = substr( textline( .line), .col) p = pos( '}', Temp) if p > 0 then TexEnvStr = leftstr( Temp, p) endif endif call pRestore_Pos( SavedPos) CheckList = substr( CursorStr, 2, 2) CheckLen = 2 fForward = (CheckList = 'be') if fForward then .col = StartCol else .col = EndCol endif elseif CursorStr = '\bgroup' | CursorStr = '\egroup' then RegExp = '\\(bgroup|egroup)' CheckList = substr( CursorStr, 2, 1) fForward = (CheckList = 'b') if fForward then .col = StartCol else .col = EndCol endif elseif CursorStr = '\begingroup' | CursorStr = '\endgroup' then RegExp = '\\(begingroup|endgroup)' CheckList = substr( CursorStr, 2, 1) fForward = (CheckList = 'b') if fForward then .col = StartCol else .col = EndCol endif elseif CursorStr = '\makeatletter' | CursorStr = '\makeatother' then RegExp = '\\makeat(letter|other)' CheckList = substr( CursorStr, 8, 1) fForward = (CheckList = 'l') if fForward then .col = StartCol else .col = EndCol endif CheckOffset = 7 elseif CursorStr = '\[' | CursorStr = '\]' then RegExp = '\\(\[|\])' CheckList = substr( CursorStr, 2, 1) fForward = (CheckList = '[') if fForward then .col = StartCol else .col = EndCol endif elseif CursorStr = '\(' | CursorStr = '\)' then RegExp = '\\(\(|\))' CheckList = substr( CursorStr, 2, 1) fForward = (CheckList = '(') if fForward then .col = StartCol else .col = EndCol endif ---- TeX math elseif wordpos( CursorStr, '\left \right') then RegExp = '\\(left|right)' CheckList = substr( CursorStr, 2, 1) fForward = (CheckList = 'l') if fForward then .col = StartCol else .col = EndCol endif ---- TeX environment: \begin{env}, \end{env} when cursor is on {env} else fEnvFound = 0 if NextCodeChar( Mode, .line, EndCol) == '}' & NextCodeChar( Mode, .line, StartCol, '-R') == '{' then -- Find \begin or \end before {env} call NextCodeChar( Mode, '', '', '-R') rcx = Find_Token( beStartCol, beEndCol, seps, 'NONE:') if rcx then beLineStr = ( textline( .line)) if beStartCol > 1 then bePrevChar = substr( beLineStr, beStartCol - 1, 1) if bePrevChar = '\' then beStartCol = beStartCol - 1 RegExp = '\\(begin|end)[ \t]*' TexEnvStr = '{'CursorStr'}' CheckList = substr( beLineStr, beStartCol + 1, 2) CheckLen = 2 fForward = (CheckList = 'be') if fForward then .col = beStartCol - 1 else .col = beEndCol endif fEnvFound = 1 endif endif endif endif if not fEnvFound then -- not a known balanceable 'TEX' token assist_rc = ASSIST_RC_NOT_ON_A_BALANCEABLE_TOKEN endif endif -- Mode(s): FORTRAN77 ----------------------------------------------------------------------- elseif Mode = 'FORTRAN77' then compile if 1 -- This code disregards the "token" and allows the cursor anywhere -- within columns 7 ... 72 if .col > 6 & .col < 73 then Statement = Fortran77ExtractText( .line, Case) do i = .line + 1 to .last Temp = textline( i) if pos( substr( Temp, 6, 1), ' 0') then leave elseif not pos( leftstr( Temp, 1), 'C*') then Statement = Statement''Fortran77ExtractText( i, Case) endif enddo Statement = Fortran77RemoveSpaces( Statement) if leftstr( Statement, 2) = 'DO' then equalpos = pos( '=', Statement, 4) commapos = pos( ',', Statement, 6) if equalpos & commapos then -- DO loop of some kind? fForward = 1 CheckList = 'D' .col = pos( 'D', LineStr, 7) p = verify( Statement, '0123456789', 'N', 3) if p > 3 then -- DO ,... loop label = substr( Statement, 3, p - 3) --#dprintf( 'pAssist', 'label as string: 'label) label = label + 0 --#dprintf( 'pAssist', 'label as number: 'label) Temp = '' do i = length( label) to 4 Temp = Temp'[ 0]?' enddo RegExp = '^('Temp''label'[ 0]?[ ]*\c[^0])' --#dprintf( "pAssist", "DO