📄 smartindent.c
字号:
# $1 to a maximum of $2.\n\# if $3 is non-zero, newlines are considered blank space as well. Return -1\n\# if the maximum position ($2) is hit mid-comment or mid-directive\n\#\n\define cSkipBlankSpace {\n\ \n\ for (i=$1; i<$2; i++) {\n\ c = get_character(i)\n\ if (c == \"/\") {\n\ if (i+1 >= $2)\n\ return i\n\ if (get_character(i+1) == \"*\") {\n\ for (i=i+1; ; i++) {\n\ if (i+1 >= $2)\n\ return -1\n\ if (get_character(i) == \"*\" && get_character(i+1) == \"/\") {\n\ i++\n\ break\n\ }\n\ }\n\ } else if (get_character(i+1) == \"/\") {\n\ for (i=i+1; i<$2; i++) {\n\ if (get_character(i) == \"\\n\") {\n\ if (!$3)\n\ return i\n\ break\n\ }\n\ }\n\ }\n\ } else if (c == \"#\" && $3) {\n\ for (i=i+1; ; i++) {\n\ if (i >= $2) {\n\ if (get_character(i-1) == \"\\\\\")\n\ return -1\n\ else\n\ break\n\ }\n\ if (get_character(i) == \"\\n\" && get_character(i-1) != \"\\\\\")\n\ break\n\ }\n\ } else if (!(c == \" \" || c == \"\\t\" || ($3 && c==\"\\n\")))\n\ return i\n\ }\n\ return $2\n\}\n\\n\#\n\# Search backward for an anchor point: a line ending brace, or semicolon\n\# or case statement, followed (ignoring blank lines and comments) by what we\n\# assume is a properly indented line, a brace on a line by itself, or a case\n\# statement. Returns the position of the first non-white, non comment\n\# character on the line. returns -1 if an anchor position can't be found\n\# before $cMaxSearchBackLines.\n\#\n\define cFindIndentAnchorPoint {\n\\n\ nLines = 0\n\ anchorPos = $1\n\ for (i=$1-1; i>0; i--) {\n\ c = get_character(i)\n\ if (c == \";\" || c == \"{\" || c == \"}\" || c == \":\") {\n\\n\ # Verify that it's line ending\n\ lineEnd = cSkipBlankSpace(i+1, $1, 0)\n\ if (lineEnd == -1 || \\\n\ (lineEnd != $text_length && get_character(lineEnd) != \"\\n\"))\n\ continue\n\\n\ # if it's a colon, it's only meaningful if \"case\" begins the line\n\ if (c == \":\") {\n\ lineStart = startOfLine(i)\n\ caseStart = cSkipBlankSpace(lineStart, lineEnd, 0)\n\ if (get_range(caseStart, caseStart+4) != \"case\")\n\ continue\n\ delim = get_character(caseStart+4)\n\ if (delim!=\" \" && delim!=\"\\t\" && delim!=\"(\" && delim!=\":\")\n\ continue\n\ isCase = 1\n\ } else\n\ isCase = 0\n\\n\ # Move forward past blank lines and comment lines to find\n\ # non-blank, non-comment line-start\n\ anchorPos = cSkipBlankSpace(lineEnd, $1, 1)\n\\n\ # Accept if it's before the requested position, otherwise\n\ # continue further back in the file and try again\n\ if (anchorPos != -1 && anchorPos < $1)\n\ break\n\\n\ # A case statement by itself is an acceptable anchor\n\ if (isCase)\n\ return caseStart\n\\n\ # A brace on a line by itself is an acceptable anchor, even\n\ # if it doesn't follow a semicolon or another brace\n\ if (c == \"{\" || c == \"}\") {\n\ for (j = i-1; ; j--) {\n\ if (j == 0)\n\ return i\n\ ch = get_character(j)\n\ if (ch == \"\\n\")\n\ return i\n\ if (ch != \"\\t\" && ch != \" \")\n\ break\n\ }\n\ }\n\\n\ } else if (c == \"\\n\")\n\ if (++nLines > $cMaxSearchBackLines)\n\ return -1\n\ }\n\ if (i <= 0)\n\ return -1\n\ return anchorPos\n\}\n\\n\#\n\# adjust the indent on a line about to recive either a right or left brace\n\# or pound (#) character ($2) following position $1\n\#\n\define cBraceOrPound {\n\\n\ # Find start of the line, and make sure there's nothing but white-space\n\ # before the character. If there's anything before it, do nothing\n\ for (i=$1-1; ; i--) {\n\ if (i < 0) {\n\ lineStart = 0\n\ break\n\ }\n\ c = get_character(i)\n\ if (c == \"\\n\") {\n\ lineStart = i + 1\n\ break\n\ }\n\ if (c != \" \" && c != \"\\t\")\n\ return\n\ }\n\\n\ # If the character was a pound, drag it all the way to the left margin\n\ if ($2 == \"#\") {\n\ replace_range(lineStart, $1, \"\")\n\ return\n\ }\n\\n\ # Find the position on which to base the indent\n\ indent = cFindSmartIndentDist($1 - 1, \"noContinue\")\n\ if (indent == -1)\n\ return\n\ \n\ # Adjust the indent if it's a right brace (left needs no adjustment)\n\ if ($2 == \"}\") {\n\ indent -= defaultIndent($cIndentDist)\n\ if (indent < 0)\n\ indent = 0\n\ }\n\\n\ # Replace the current indent with the new indent string\n\ insertStr = makeIndentString(indent)\n\ replace_range(lineStart, $1, insertStr)\n\}\n\\n\#\n\# Find Smart Indent Distance for a newline character inserted at $1,\n\# or return -1 to give up. Adding the optional argument \"noContinue\"\n\# will stop the routine from inserting line continuation indents\n\#\n\define cFindSmartIndentDist {\n\\n\ # Find a known good indent to base the new indent upon\n\ anchorPos = cFindIndentAnchorPoint($1)\n\ if (anchorPos == -1)\n\ return -1\n\\n\ # Find the indentation of that line\n\ anchorIndent = measureIndent(anchorPos)\n\\n\ # Look for special keywords which affect indent (for, if, else while, do)\n\ # and modify the continuation indent distance to the normal indent\n\ # distance when a completed statement of this type occupies the line.\n\ if ($n_args >= 2 && $2 == \"noContinue\") {\n\ continueIndent = 0\n\ $allowSemi = 0\n\ } else\n\ continueIndent = cCalcContinueIndent(anchorPos, $1)\n\\n\ # Move forward from anchor point, ignoring comments and blank lines,\n\ # remembering the last non-white, non-comment character. If $1 is\n\ # in the middle of a comment, give up\n\ lastChar = get_character(anchorPos)\n\ if (anchorPos < $1) {\n\ for (i=anchorPos;;) {\n\ i = cSkipBlankSpace(i, $1, 1)\n\ if (i == -1)\n\ return -1\n\ if (i >= $1)\n\ break\n\ lastChar = get_character(i++)\n\ }\n\ }\n\\n\ # Return the new indent based on the type of the last character.\n\ # In a for stmt, however, last character may be a semicolon and not\n\ # signal the end of the statement\n\ if (lastChar == \"{\")\n\ return anchorIndent + defaultIndent($cIndentDist)\n\ else if (lastChar == \"}\")\n\ return anchorIndent\n\ else if (lastChar == \";\") {\n\ if ($allowSemi)\n\ return anchorIndent + continueIndent\n\ else\n\ return anchorIndent\n\ } else if (lastChar == \":\" && get_range(anchorPos, anchorPos+4) == \"case\")\n\ return anchorIndent + defaultIndent($cIndentDist)\n\ return anchorIndent + continueIndent\n\}\n\\n\#\n\# Calculate the continuation indent distance for statements not ending in\n\# semicolons or braces. This is not necessarily $continueIndent. It may\n\# be adjusted if the statement contains if, while, for, or else.\n\#\n\# As a side effect, also return $allowSemi to help distinguish statements\n\# which might contain an embedded semicolon, which should not be interpreted\n\# as an end of statement character.\n\#\n\define cCalcContinueIndent {\n\\n\ anchorPos = $1\n\ maxPos = $2\n\\n\ # Figure out if the anchor is on a keyword which changes indent. A special\n\ # case is made for elses nested in after braces\n\ anchorIsFor = 0\n\ $allowSemi = 0\n\ if (get_character(anchorPos) == \"}\") {\n\ for (i=anchorPos+1; i<maxPos; i++) {\n\ c = get_character(i)\n\ if (c != \" \" && c != \"\\t\")\n\ break\n\ }\n\ if (get_range(i, i+4) == \"else\") {\n\ keywordEnd = i + 4\n\ needsBalancedParens = 0\n\ } else\n\ return defaultContIndent($cContinuationIndent)\n\ } else if (get_range(anchorPos, anchorPos + 4) == \"else\") {\n\ keywordEnd = anchorPos + 4\n\ needsBalancedParens = 0\n\ } else if (get_range(anchorPos, anchorPos + 2) == \"do\") {\n\ keywordEnd = anchorPos + 2\n\ needsBalancedParens = 0\n\ } else if (get_range(anchorPos, anchorPos + 3) == \"for\") {\n\ keywordEnd = anchorPos + 3\n\ anchorIsFor = 1\n\ needsBalancedParens = 1\n\ } else if (get_range(anchorPos, anchorPos + 2) == \"if\") {\n\ keywordEnd = anchorPos + 2\n\ needsBalancedParens = 1\n\ } else if (get_range(anchorPos, anchorPos + 5) == \"while\") {\n\ keywordEnd = anchorPos + 5\n\ needsBalancedParens = 1\n\ } else\n\ return defaultContIndent($cContinuationIndent)\n\\n\ # If the keyword must be followed balanced parenthesis, find the end of\n\ # the statement by following balanced parens. If the parens aren't\n\ # balanced by maxPos, continue the condition. In the special case of\n\ # the for keyword, a semicolon can end the line and the caller should be\n\ # signaled to allow that\n\ if (needsBalancedParens) {\n\ stmtEnd = findBalancingParen(keywordEnd, maxPos)\n\ if (stmtEnd == -1) {\n\ $allowSemi = anchorIsFor\n\ return defaultContIndent($cContinuationIndent)\n\ }\n\ } else\n\ stmtEnd = keywordEnd\n\\n\ # check if the statement ends the line\n\ lineEnd = cSkipBlankSpace(stmtEnd, maxPos, 0)\n\ if (lineEnd == -1) # ends in comment or preproc\n\ return -1\n\ if (lineEnd == maxPos) # maxPos happens at stmt end\n\ return defaultIndent($cIndentDist)\n\ c = get_character(lineEnd)\n\ if (c != \"\\n\") # something past last paren on line,\n\ return defaultIndent($cIndentDist) # probably quoted or extra braces\n\\n\ # stmt contintinues beyond matching paren && newline, we're in\n\ # the conditional part, calculate the continue indent distance\n\ # recursively, based on the anchor point of the new line\n\ newAnchor = cSkipBlankSpace(lineEnd+1, maxPos, 1)\n\ if (newAnchor == -1)\n\ return -1\n\ if (newAnchor == maxPos)\n\ return defaultIndent($cIndentDist)\n\ return cCalcContinueIndent(newAnchor, maxPos) + defaultIndent($cIndentDist)\n\}\n\";/*** Turn on smart-indent (well almost). Unfortunately, this doesn't do** everything. It requires that the smart indent callback (SmartIndentCB)** is already attached to all of the text widgets in the window, and that the** smartIndent resource must be turned on in the widget. These are done** separately, because they are required per-text widget, and therefore must** be repeated whenever a new text widget is created within this window** (a split-window command).*/void BeginSmartIndent(WindowInfo *window, int warn){ windowSmartIndentData *winData; smartIndentRec *indentMacros; char *modeName, *stoppedAt, *errMsg; static int initialized; /* Find the window's language mode. If none is set, warn the user */ modeName = LanguageModeName(window->languageMode); if (modeName == NULL) { if (warn) { DialogF(DF_WARN, window->shell, 1, "Smart Indent", "No language-specific mode has been set for this file.\n\n" "To use smart indent in this window, please select a\n" "language from the Preferences -> Language Modes menu.", "Dismiss"); } return; } /* Look up the appropriate smart-indent macros for the language */ indentMacros = findIndentSpec(modeName); if (indentMacros == NULL) { if (warn) { DialogF(DF_WARN, window->shell, 1, "Smart Indent", "Smart indent is not available in languagemode\n%s.\n\n" "You can create new smart indent macros in the\n" "Preferences -> Default Settings -> Smart Indent\n" "dialog, or choose a different language mode from:\n" "Preferences -> Language Mode.", "Dismiss", modeName); } return; } /* Make sure that the initial macro file is loaded before we execute any of the smart-indent macros. Smart-indent macros may reference routines defined in that file. */ ReadMacroInitFile(window); /* Compile and run the common and language-specific initialization macros (Note that when these return, the immediate commands in the file have not necessarily been executed yet. They are only SCHEDULED for execution) */ if (!initialized) { if (!ReadMacroString(window, CommonMacros, "smart indent common initialization macros")) return; initialized = True; } if (indentMacros->initMacro != NULL) { if (!ReadMacroString(window, indentMacros->initMacro, "smart indent initialization macro")) return; } /* Compile the newline and modify macros and attach them to the window */ winData = (windowSmartIndentData *)XtMalloc(sizeof(windowSmartIndentData)); winData->inNewLineMacro = 0; winData->inModMacro = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -