📄 smartindent.c
字号:
static const char CVSID[] = "$Id: smartIndent.c,v 1.27 2003/05/09 17:43:48 edg Exp $";/******************************************************************************** ** smartIndent.c -- Maintain, and allow user to edit, macros for smart indent ** ** Copyright (C) 1999 Mark Edel ** ** This 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; either version 2 of the License, or (at your option) any later ** version. ** ** This software 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. ** ** You should have received a copy of the GNU General Public License along with ** software; if not, write to the Free Software Foundation, Inc., 59 Temple ** Place, Suite 330, Boston, MA 02111-1307 USA ** ** Nirvana Text Editor ** July, 1997 ** ** Written by Mark Edel ** ********************************************************************************/#ifdef HAVE_CONFIG_H#include "../config.h"#endif#include "smartIndent.h"#include "textBuf.h"#include "nedit.h"#include "text.h"#include "preferences.h"#include "interpret.h"#include "macro.h"#include "window.h"#include "parse.h"#include "shift.h"#include "help.h"#include "../util/DialogF.h"#include "../util/misc.h"#include <stdio.h>#include <string.h>#include <limits.h>#include <Xm/Xm.h>#ifdef VMS#include "../util/VMSparam.h"#else#ifndef __MVS__#include <sys/param.h>#endif#endif /*VMS*/#include <Xm/Xm.h>#include <Xm/Form.h>#include <Xm/Text.h>#include <Xm/LabelG.h>#include <Xm/PushB.h>#include <Xm/RowColumn.h>#include <Xm/SeparatoG.h>#include <Xm/PanedW.h>#ifdef HAVE_DEBUG_H#include "../debug.h"#endifstatic char MacroEndBoundary[] = "--End-of-Macro--";typedef struct { char *lmName; char *initMacro; char *newlineMacro; char *modMacro;} smartIndentRec;typedef struct { Program *newlineMacro; int inNewLineMacro; Program *modMacro; int inModMacro;} windowSmartIndentData;/* Smart indent macros dialog information */static struct { Widget shell; Widget lmOptMenu; Widget lmPulldown; Widget initMacro; Widget newlineMacro; Widget modMacro; char *langModeName;} SmartIndentDialog = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};/* Common smart indent macros dialog information */static struct { Widget shell; Widget text;} CommonDialog = {NULL,NULL};static int NSmartIndentSpecs = 0;static smartIndentRec *SmartIndentSpecs[MAX_LANGUAGE_MODES];static char *CommonMacros = NULL;static void executeNewlineMacro(WindowInfo *window,smartIndentCBStruct *cbInfo);static void executeModMacro(WindowInfo *window,smartIndentCBStruct *cbInfo);static void insertShiftedMacro(textBuffer *buf, char *macro);static int isDefaultIndentSpec(smartIndentRec *indentSpec);static smartIndentRec *findIndentSpec(const char *modeName);static char *ensureNewline(char *string);static int loadDefaultIndentSpec(char *lmName);static int siParseError(char *stringStart, char *stoppedAt, char *message);static void destroyCB(Widget w, XtPointer clientData, XtPointer callData);static void langModeCB(Widget w, XtPointer clientData, XtPointer callData);static void commonDialogCB(Widget w, XtPointer clientData, XtPointer callData);static void lmDialogCB(Widget w, XtPointer clientData, XtPointer callData);static void okCB(Widget w, XtPointer clientData, XtPointer callData);static void applyCB(Widget w, XtPointer clientData, XtPointer callData);static void checkCB(Widget w, XtPointer clientData, XtPointer callData);static void restoreCB(Widget w, XtPointer clientData, XtPointer callData);static void deleteCB(Widget w, XtPointer clientData, XtPointer callData);static void dismissCB(Widget w, XtPointer clientData, XtPointer callData);static void helpCB(Widget w, XtPointer clientData, XtPointer callData);static int checkSmartIndentDialogData(void);static smartIndentRec *getSmartIndentDialogData(void);static void setSmartIndentDialogData(smartIndentRec *is);static void comDestroyCB(Widget w, XtPointer clientData, XtPointer callData);static void comOKCB(Widget w, XtPointer clientData, XtPointer callData);static void comApplyCB(Widget w, XtPointer clientData, XtPointer callData);static void comCheckCB(Widget w, XtPointer clientData, XtPointer callData);static void comRestoreCB(Widget w, XtPointer clientData, XtPointer callData);static void comDismissCB(Widget w, XtPointer clientData, XtPointer callData);static int updateSmartIndentCommonData(void);static int checkSmartIndentCommonDialogData(void);static int updateSmartIndentData(void);static char *readSIMacro(char **inPtr);static smartIndentRec *copyIndentSpec(smartIndentRec *is);static void freeIndentSpec(smartIndentRec *is);static int indentSpecsDiffer(smartIndentRec *is1, smartIndentRec *is2);#define N_DEFAULT_INDENT_SPECS 4static smartIndentRec DefaultIndentSpecs[N_DEFAULT_INDENT_SPECS] = {{"C","# C Macros and tuning parameters are shared with C++, and are declared\n\# in the common section. Press Common / Shared Initialization above.\n","return cFindSmartIndentDist($1)\n","if ($2 == \"}\" || $2 == \"{\" || $2 == \"#\")\n\ cBraceOrPound($1, $2)\n"},{"C++","# C++ Macros and tuning parameters are shared with C, and are declared\n\# in the common section. Press Common / Shared Initialization above.\n","return cFindSmartIndentDist($1)\n","if ($2 == \"}\" || $2 == \"{\" || $2 == \"#\")\n\ cBraceOrPound($1, $2)\n"},{"Python","# Number of characters in a normal indent level. May be a number, or the\n\# string \"default\", meaning, guess the value from the current tab settings.\n\$pyIndentDist = \"default\"\n","if (get_range($1-1, $1) != \":\")\n\ return -1\n\return measureIndent($1) + defaultIndent($pyIndentDist)\n", NULL},{"Matlab","# Number of spaces to indent \"case\" statements\n\$caseDepth = 2\n\define matlabNewlineMacro\n\{\n\ if ($em_tab_dist == -1)\n\ tabsize = $tab_dist\n\ else\n\ tabsize = $em_tab_dist\n\ startLine = startOfLine($1)\n\ indentLevel = measureIndent($1)\n\\n\ # If this line is continued on next, return default:\n\ lastLine = get_range(startLine, $1)\n\ if (search_string(lastLine, \"...\", 0) != -1) {\n\ if ($n_args == 2)\n\ return matlabNewlineMacro(startLine - 1, 1)\n\ else {\n\ return -1\n\ }\n\ }\n\\n\ # Correct the indentLevel if this was a continued line.\n\ while (startLine > 1)\n\ {\n\ endLine = startLine - 1\n\ startLine = startOfLine(endLine)\n\ lastLine = get_range(startLine, endLine)\n\ # No \"...\" means we've found the root\n\ if (search_string(lastLine, \"...\", 0) == -1) {\n\ startLine = endLine + 1\n\ break\n\ }\n\ }\n\ indentLevel = measureIndent(startLine)\n\\n\ # Get the first word of the indentLevel line\n\ FWend = search(\">|\\n\", startLine + indentLevel, \"regex\")\n\ # This search fails on EOF\n\ if (FWend == -1)\n\ FWend = $1\n\\n\ firstWord = get_range(startLine + indentLevel, FWend)\n\\n\ # How shall we change the indent level based on the first word?\n\ if (search_string(firstWord, \\\n\ \"<for>|<function>|<if>|<switch>|<try>|<while>\", 0, \"regex\") == 0) {\n\ return indentLevel + tabsize\n\ }\n\ else if ((firstWord == \"end\") || (search_string(firstWord, \\\n\ \"<case>|<catch>|<else>|<elseif>|<otherwise>\", 0, \"regex\") == 0)) {\n\ # Get the last indent level \n\ if (startLine > 0) # avoid infinite loop\n\ last_indent = matlabNewlineMacro(startLine - 1, 1)\n\ else\n\ last_indent = indentLevel\n\\n\ # Re-indent this line\n\ if ($n_args == 1) {\n\ if (firstWord == \"case\" || firstWord == \"otherwise\")\n\ replace_range(startLine, startLine + indentLevel, \\\n\ makeIndentString(last_indent - tabsize + $caseDepth))\n\ else\n\ replace_range(startLine, startLine + indentLevel, \\\n\ makeIndentString(last_indent - tabsize))\n\ }\n\\n\ if (firstWord == \"end\") {\n\ return max(last_indent - tabsize, 0)\n\ }\n\ else {\n\ return last_indent\n\ }\n\ } \n\ else {\n\ return indentLevel\n\ }\n\}", "return matlabNewlineMacro($1)\n", NULL}};static char DefaultCommonMacros[] = "#\n\# C/C++ Style/tuning parameters\n\#\n\\n\# Number of characters in a normal indent level. May be a number, or the\n\# string \"default\", meaning, guess the value from the current tab settings.\n\$cIndentDist = \"default\"\n\\n\# Number of characters in a line continuation. May be a number or the\n\# string \"default\", meaning, guess the value from the current tab settings.\n\$cContinuationIndent = \"default\"\n\\n\# How far back from the current position to search for an anchoring position\n\# on which to base indent. When no reliable indicators of proper indent level\n\# can be found within the requested distance, reverts to plain auto indent.\n\$cMaxSearchBackLines = 10\n\\n\#\n\# Find the start of the line containing position $1\n\#\n\define startOfLine {\n\\n\ for (i=$1-1; ; i--) {\n\ if (i <= 0)\n\ return 0\n\ if (get_character(i) == \"\\n\")\n\ return i + 1\n\ }\n\}\n\\n\#\n\# Find the indent level of the line containing character position $1\n\#\n\define measureIndent {\n\ \n\ # measure the indentation to the first non-white character on the line\n\ indent = 0\n\ for (i=startOfLine($1); i < $text_length; i++) {\n\ c = get_character(i)\n\ if (c != \" \" && c != \"\\t\")\n\ break\n\ if (c == \"\\t\")\n\ indent += $tab_dist - (indent % $tab_dist)\n\ else\n\ indent++\n\ }\n\ return indent\n\}\n\\n\#\n\# Make a string to produce an indent of $1 characters\n\#\n\define makeIndentString {\n\\n\ if ($use_tabs) {\n\ nTabs = $1 / $tab_dist\n\ nSpaces = $1 % $tab_dist\n\ } else {\n\ nTabs = 0\n\ nSpaces = $1\n\ }\n\ indentString = \"\"\n\ for (i=0; i<nTabs; i++)\n\ indentString = indentString \"\\t\"\n\ for (i=0; i<nSpaces; i++)\n\ indentString = indentString \" \"\n\ return indentString\n\}\n\\n\#\n\# If $1 is a number, just pass it on. If it is the string \"default\",\n\# figure out a reasonable indent distance for a structured languages\n\# like C, based on how tabs are set.\n\#\n\define defaultIndent {\n\\n\ if ($1 != \"default\")\n\ return $1\n\ if ($em_tab_dist != -1)\n\ return $em_tab_dist\n\ if ($tab_dist <= 8)\n\ return $tab_dist\n\ return 4\n\}\n\ \n\#\n\# If $1 is a number, just pass it on. If it is the string \"default\",\n\# figure out a reasonable amount of indentation for continued lines\n\# based on how tabs are set.\n\#\n\define defaultContIndent {\n\\n\ if ($1 != \"default\")\n\ return $1\n\ if ($em_tab_dist != -1)\n\ return $em_tab_dist * 2\n\ if ($tab_dist <= 8)\n\ return $tab_dist * 2\n\ return 8\n\}\n\\n\#\n\# Find the end of the conditional part of if/while/for, by looking for balanced\n\# parenthesis between $1 and $2. returns -1 if parens don't balance before\n\# $2, or if no parens are found\n\#\n\define findBalancingParen {\n\\n\ openParens = 0\n\ parensFound = 0\n\ for (i=$1; i<$2; i++) {\n\ c = get_character(i)\n\ if (c == \"(\") {\n\ openParens++\n\ parensFound = 1\n\ } else if (c == \")\")\n\ openParens--\n\ else if (!parensFound && c != \" \" && c != \"\\t\")\n\ return -1\n\ if (parensFound && openParens <=0)\n\ return i+1\n\ }\n\ return -1\n\}\n\\n\#\n\# Skip over blank space and comments and preprocessor directives from position\n\
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -