1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
32
33 #include "smartIndent.h"
34 #include "textBuf.h"
35 #include "nedit.h"
36 #include "text.h"
37 #include "preferences.h"
38 #include "interpret.h"
39 #include "macro.h"
40 #include "window.h"
41 #include "parse.h"
42 #include "shift.h"
43 #include "help.h"
44 #include "../util/DialogF.h"
45 #include "../util/misc.h"
46 #include "../util/nedit_malloc.h"
47
48 #include <stdio.h>
49 #include <string.h>
50 #include <limits.h>
51
52 #include <Xm/Xm.h>
53 #include <sys/param.h>
54 #include <Xm/Xm.h>
55 #include <Xm/Form.h>
56 #include <Xm/Text.h>
57 #include <Xm/LabelG.h>
58 #include <Xm/PushB.h>
59 #include <Xm/RowColumn.h>
60 #include <Xm/SeparatoG.h>
61 #include <Xm/PanedW.h>
62
63 #ifdef HAVE_DEBUG_H
64 #include "../debug.h"
65 #endif
66
67
68 static char MacroEndBoundary[] =
"--End-of-Macro--";
69
70 typedef struct {
71 char *lmName;
72 char *initMacro;
73 char *newlineMacro;
74 char *modMacro;
75 } smartIndentRec;
76
77 typedef struct {
78 Program *newlineMacro;
79 int inNewLineMacro;
80 Program *modMacro;
81 int inModMacro;
82 } windowSmartIndentData;
83
84
85 static struct {
86 Widget shell;
87 Widget lmOptMenu;
88 Widget lmPulldown;
89 Widget initMacro;
90 Widget newlineMacro;
91 Widget modMacro;
92 char *langModeName;
93 } SmartIndentDialog = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL};
94
95
96 static struct {
97 Widget shell;
98 Widget text;
99 } CommonDialog = {
NULL,
NULL};
100
101 static int NSmartIndentSpecs =
0;
102 static smartIndentRec *SmartIndentSpecs[
MAX_LANGUAGE_MODES];
103 static char *CommonMacros =
NULL;
104
105 static void executeNewlineMacro(WindowInfo *window,smartIndentCBStruct *cbInfo);
106 static void executeModMacro(WindowInfo *window,smartIndentCBStruct *cbInfo);
107 static void insertShiftedMacro(textBuffer *buf,
char *macro);
108 static int isDefaultIndentSpec(smartIndentRec *indentSpec);
109 static smartIndentRec *findIndentSpec(
const char *modeName);
110 static char *ensureNewline(
char *string);
111 static int loadDefaultIndentSpec(
char *lmName);
112 static int siParseError(
char *stringStart,
char *stoppedAt,
char *message);
113 static void destroyCB(Widget w, XtPointer clientData, XtPointer callData);
114 static void langModeCB(Widget w, XtPointer clientData, XtPointer callData);
115 static void commonDialogCB(Widget w, XtPointer clientData, XtPointer callData);
116 static void lmDialogCB(Widget w, XtPointer clientData, XtPointer callData);
117 static void okCB(Widget w, XtPointer clientData, XtPointer callData);
118 static void applyCB(Widget w, XtPointer clientData, XtPointer callData);
119 static void checkCB(Widget w, XtPointer clientData, XtPointer callData);
120 static void restoreCB(Widget w, XtPointer clientData, XtPointer callData);
121 static void deleteCB(Widget w, XtPointer clientData, XtPointer callData);
122 static void closeCB(Widget w, XtPointer clientData, XtPointer callData);
123 static void helpCB(Widget w, XtPointer clientData, XtPointer callData);
124 static int checkSmartIndentDialogData(
void);
125 static smartIndentRec *getSmartIndentDialogData(
void);
126 static void setSmartIndentDialogData(smartIndentRec *is);
127 static void comDestroyCB(Widget w, XtPointer clientData, XtPointer callData);
128 static void comOKCB(Widget w, XtPointer clientData, XtPointer callData);
129 static void comApplyCB(Widget w, XtPointer clientData, XtPointer callData);
130 static void comCheckCB(Widget w, XtPointer clientData, XtPointer callData);
131 static void comRestoreCB(Widget w, XtPointer clientData, XtPointer callData);
132 static void comCloseCB(Widget w, XtPointer clientData, XtPointer callData);
133 static int updateSmartIndentCommonData(
void);
134 static int checkSmartIndentCommonDialogData(
void);
135 static int updateSmartIndentData(
void);
136 static char *readSIMacro(
char **inPtr);
137 static smartIndentRec *copyIndentSpec(smartIndentRec *is);
138 static void freeIndentSpec(smartIndentRec *is);
139 static int indentSpecsDiffer(smartIndentRec *is1, smartIndentRec *is2);
140
141 #define N_DEFAULT_INDENT_SPECS 4
142 static smartIndentRec DefaultIndentSpecs[
N_DEFAULT_INDENT_SPECS] = {
143 {
"C",
144 "# C Macros and tuning parameters are shared with C++, and are declared\n\
145 # in the common section. Press Common / Shared Initialization above.\n",
146 "return cFindSmartIndentDist($1)\n",
147 "if ($2 == \"}\" || $2 == \"{\" || $2 == \"#\")\n\
148 cBraceOrPound($1, $2)\n"},
149 {
"C++",
150 "# C++ Macros and tuning parameters are shared with C, and are declared\n\
151 # in the common section. Press Common / Shared Initialization above.\n",
152 "return cFindSmartIndentDist($1)\n",
153 "if ($2 == \"}\" || $2 == \"{\" || $2 == \"#\")\n\
154 cBraceOrPound($1, $2)\n"},
155 {
"Python",
156 "# Number of characters in a normal indent level. May be a number, or the\n\
157 # string \"default\", meaning, guess the value from the current tab settings.\n\
158 $pyIndentDist = \"default\"\n",
159 "if (get_range($1-1, $1) != \":\")\n\
160 return -1\n\
161 return measureIndent($1) + defaultIndent($pyIndentDist)\n",
NULL},
162 {
"Matlab",
163 "# Number of spaces to indent \"case\" statements\n\
164 $caseDepth = 2\n\
165 define matlabNewlineMacro\n\
166 {\n\
167 if (!$em_tab_dist)\n\
168 tabsize = $tab_dist\n\
169 else\n\
170 tabsize = $em_tab_dist\n\
171 startLine = startOfLine($1)\n\
172 indentLevel = measureIndent($1)\n\
173 \n\
174 # If this line is continued on next, return default:\n\
175 lastLine = get_range(startLine, $1)\n\
176 if (search_string(lastLine, \"...\", 0) != -1) {\n\
177 if ($n_args == 2)\n\
178 return matlabNewlineMacro(startLine - 1, 1)\n\
179 else {\n\
180 return -1\n\
181 }\n\
182 }\n\
183 \n\
184 # Correct the indentLevel if this was a continued line.\n\
185 while (startLine > 1)\n\
186 {\n\
187 endLine = startLine - 1\n\
188 startLine = startOfLine(endLine)\n\
189 lastLine = get_range(startLine, endLine)\n\
190 # No \"...\" means we''ve found the root\n\
191 if (search_string(lastLine, \"...\", 0) == -1) {\n\
192 startLine = endLine + 1\n\
193 break\n\
194 }\n\
195 }\n\
196 indentLevel = measureIndent(startLine)\n\
197 \n\
198 # Get the first word of the indentLevel line\n\
199 FWend = search(\">|\\n\", startLine + indentLevel, \"regex\")\n\
200 # This search fails on EOF\n\
201 if (FWend == -1)\n\
202 FWend = $1\n\
203 \n\
204 firstWord = get_range(startLine + indentLevel, FWend)\n\
205 \n\
206 # How shall we change the indent level based on the first word?\n\
207 if (search_string(firstWord, \\\n\
208 \"<for>|<function>|<if>|<switch>|<try>|<while>\", 0, \"regex\") == 0) {\n\
209 return indentLevel + tabsize\n\
210 }\n\
211 else if ((firstWord == \"end\") || (search_string(firstWord, \\\n\
212 \"<case>|<catch>|<else>|<elseif>|<otherwise>\", 0, \"regex\") == 0)) {\n\
213 # Get the last indent level \n\
214 if (startLine > 0) # avoid infinite loop\n\
215 last_indent = matlabNewlineMacro(startLine - 1, 1)\n\
216 else\n\
217 last_indent = indentLevel\n\
218 \n\
219 # Re-indent this line\n\
220 if ($n_args == 1) {\n\
221 if (firstWord == \"case\" || firstWord == \"otherwise\")\n\
222 replace_range(startLine, startLine + indentLevel, \\\n\
223 makeIndentString(last_indent - tabsize + $caseDepth))\n\
224 else\n\
225 replace_range(startLine, startLine + indentLevel, \\\n\
226 makeIndentString(last_indent - tabsize))\n\
227 }\n\
228 \n\
229 if (firstWord == \"end\") {\n\
230 return max(last_indent - tabsize, 0)\n\
231 }\n\
232 else {\n\
233 return last_indent\n\
234 }\n\
235 } \n\
236 else {\n\
237 return indentLevel\n\
238 }\n\
239 }\n\
240 ",
"return matlabNewlineMacro($1)\n",
NULL}
241 };
242
243 static char DefaultCommonMacros[] =
"#\n\
244 # C/C++ Style/tuning parameters\n\
245 #\n\
246 \n\
247 # Number of characters in a normal indent level. May be a number, or the\n\
248 # string \"default\", meaning, guess the value from the current tab settings.\n\
249 $cIndentDist = \"default\"\n\
250 \n\
251 # Number of characters in a line continuation. May be a number or the\n\
252 # string \"default\", meaning, guess the value from the current tab settings.\n\
253 $cContinuationIndent = \"default\"\n\
254 \n\
255 # How far back from the current position to search for an anchoring position\n\
256 # on which to base indent. When no reliable indicators of proper indent level\n\
257 # can be found within the requested distance, reverts to plain auto indent.\n\
258 $cMaxSearchBackLines = 10\n\
259 \n\
260 #\n\
261 # Find the start of the line containing position $1\n\
262 #\n\
263 define startOfLine {\n\
264 \n\
265 for (i=$1-1; ; i--) {\n\
266 if (i <= 0)\n\
267 return 0\n\
268 if (get_character(i) == \"\\n\")\n\
269 return i + 1\n\
270 }\n\
271 }\n\
272 \n\
273 #\n\
274 # Find the indent level of the line containing character position $1\n\
275 #\n\
276 define measureIndent {\n\
277 \n\
278 # measure the indentation to the first non-white character on the line\n\
279 indent = 0\n\
280 for (i=startOfLine($1); i < $text_length; i++) {\n\
281 c = get_character(i)\n\
282 if (c != \" \" && c != \"\\t\")\n\
283 break\n\
284 if (c == \"\\t\")\n\
285 indent += $tab_dist - (indent % $tab_dist)\n\
286 else\n\
287 indent++\n\
288 }\n\
289 return indent\n\
290 }\n\
291 \n\
292 #\n\
293 # Make a string to produce an indent of $1 characters\n\
294 #\n\
295 define makeIndentString {\n\
296 \n\
297 if ($use_tabs) {\n\
298 nTabs = $1 / $tab_dist\n\
299 nSpaces = $1 % $tab_dist\n\
300 } else {\n\
301 nTabs = 0\n\
302 nSpaces = $1\n\
303 }\n\
304 indentString = \"\"\n\
305 for (i=0; i<nTabs; i++)\n\
306 indentString = indentString \"\\t\"\n\
307 for (i=0; i<nSpaces; i++)\n\
308 indentString = indentString \" \"\n\
309 return indentString\n\
310 }\n\
311 \n\
312 #\n\
313 # If $1 is a number, just pass it on. If it is the string \"default\",\n\
314 # figure out a reasonable indent distance for a structured languages\n\
315 # like C, based on how tabs are set.\n\
316 #\n\
317 define defaultIndent {\n\
318 \n\
319 if ($1 != \"default\")\n\
320 return $1\n\
321 if ($em_tab_dist)\n\
322 return $em_tab_dist\n\
323 if ($tab_dist <= 8)\n\
324 return $tab_dist\n\
325 return 4\n\
326 }\n\
327 \n\
328 #\n\
329 # If $1 is a number, just pass it on. If it is the string \"default\",\n\
330 # figure out a reasonable amount of indentation for continued lines\n\
331 # based on how tabs are set.\n\
332 #\n\
333 define defaultContIndent {\n\
334 \n\
335 if ($1 != \"default\")\n\
336 return $1\n\
337 if ($em_tab_dist)\n\
338 return $em_tab_dist * 2\n\
339 if ($tab_dist <= 8)\n\
340 return $tab_dist * 2\n\
341 return 8\n\
342 }\n\
343 \n\
344 #\n\
345 # Find the end of the conditional part of if/while/for, by looking for balanced\n\
346 # parenthesis between $1 and $2. returns -1 if parens don''t balance before\n\
347 # $2, or if no parens are found\n\
348 #\n\
349 define findBalancingParen {\n\
350 \n\
351 openParens = 0\n\
352 parensFound = 0\n\
353 for (i=$1; i<$2; i++) {\n\
354 c = get_character(i)\n\
355 if (c == \"(\") {\n\
356 openParens++\n\
357 parensFound = 1\n\
358 } else if (c == \")\")\n\
359 openParens--\n\
360 else if (!parensFound && c != \" \" && c != \"\\t\")\n\
361 return -1\n\
362 if (parensFound && openParens <=0)\n\
363 return i+1\n\
364 }\n\
365 return -1\n\
366 }\n\
367 \n\
368 #\n\
369 # Skip over blank space and comments and preprocessor directives from position\n\
370 # $1 to a maximum of $2.\n\
371 # if $3 is non-zero, newlines are considered blank space as well. Return -1\n\
372 # if the maximum position ($2) is hit mid-comment or mid-directive\n\
373 #\n\
374 define cSkipBlankSpace {\n\
375 \n\
376 for (i=$1; i<$2; i++) {\n\
377 c = get_character(i)\n\
378 if (c == \"/\") {\n\
379 if (i+1 >= $2)\n\
380 return i\n\
381 if (get_character(i+1) == \"*\") {\n\
382 for (i=i+1; ; i++) {\n\
383 if (i+1 >= $2)\n\
384 return -1\n\
385 if (get_character(i) == \"*\" && get_character(i+1) == \"/\") {\n\
386 i++\n\
387 break\n\
388 }\n\
389 }\n\
390 } else if (get_character(i+1) == \"/\") {\n\
391 for (i=i+1; i<$2; i++) {\n\
392 if (get_character(i) == \"\\n\") {\n\
393 if (!$3)\n\
394 return i\n\
395 break\n\
396 }\n\
397 }\n\
398 }\n\
399 } else if (c == \"#\" && $3) {\n\
400 for (i=i+1; ; i++) {\n\
401 if (i >= $2) {\n\
402 if (get_character(i-1) == \"\\\\\")\n\
403 return -1\n\
404 else\n\
405 break\n\
406 }\n\
407 if (get_character(i) == \"\\n\" && get_character(i-1) != \"\\\\\")\n\
408 break\n\
409 }\n\
410 } else if (!(c == \" \" || c == \"\\t\" || ($3 && c==\"\\n\")))\n\
411 return i\n\
412 }\n\
413 return $2\n\
414 }\n\
415 \n\
416 #\n\
417 # Search backward for an anchor point: a line ending brace, or semicolon\n\
418 # or case statement, followed (ignoring blank lines and comments) by what we\n\
419 # assume is a properly indented line, a brace on a line by itself, or a case\n\
420 # statement. Returns the position of the first non-white, non comment\n\
421 # character on the line. returns -1 if an anchor position can''t be found\n\
422 # before $cMaxSearchBackLines.\n\
423 #\n\
424 define cFindIndentAnchorPoint {\n\
425 \n\
426 nLines = 0\n\
427 anchorPos = $1\n\
428 for (i=$1-1; i>0; i--) {\n\
429 c = get_character(i)\n\
430 if (c == \";\" || c == \"{\" || c == \"}\" || c == \":\") {\n\
431 \n\
432 # Verify that it''s line ending\n\
433 lineEnd = cSkipBlankSpace(i+1, $1, 0)\n\
434 if (lineEnd == -1 || \\\n\
435 (lineEnd != $text_length && get_character(lineEnd) != \"\\n\"))\n\
436 continue\n\
437 \n\
438 # if it''s a colon, it''s only meaningful if \"case\" begins the line\n\
439 if (c == \":\") {\n\
440 lineStart = startOfLine(i)\n\
441 caseStart = cSkipBlankSpace(lineStart, lineEnd, 0)\n\
442 if (get_range(caseStart, caseStart+4) != \"case\")\n\
443 continue\n\
444 delim = get_character(caseStart+4)\n\
445 if (delim!=\" \" && delim!=\"\\t\" && delim!=\"(\" && delim!=\":\")\n\
446 continue\n\
447 isCase = 1\n\
448 } else\n\
449 isCase = 0\n\
450 \n\
451 # Move forward past blank lines and comment lines to find\n\
452 # non-blank, non-comment line-start\n\
453 anchorPos = cSkipBlankSpace(lineEnd, $1, 1)\n\
454 \n\
455 # Accept if it''s before the requested position, otherwise\n\
456 # continue further back in the file and try again\n\
457 if (anchorPos != -1 && anchorPos < $1)\n\
458 break\n\
459 \n\
460 # A case statement by itself is an acceptable anchor\n\
461 if (isCase)\n\
462 return caseStart\n\
463 \n\
464 # A brace on a line by itself is an acceptable anchor, even\n\
465 # if it doesn''t follow a semicolon or another brace\n\
466 if (c == \"{\" || c == \"}\") {\n\
467 for (j = i-1; ; j--) {\n\
468 if (j == 0)\n\
469 return i\n\
470 ch = get_character(j)\n\
471 if (ch == \"\\n\")\n\
472 return i\n\
473 if (ch != \"\\t\" && ch != \" \")\n\
474 break\n\
475 }\n\
476 }\n\
477 \n\
478 } else if (c == \"\\n\")\n\
479 if (++nLines > $cMaxSearchBackLines)\n\
480 return -1\n\
481 }\n\
482 if (i <= 0)\n\
483 return -1\n\
484 return anchorPos\n\
485 }\n\
486 \n\
487 #\n\
488 # adjust the indent on a line about to recive either a right or left brace\n\
489 # or pound (#) character ($2) following position $1\n\
490 #\n\
491 define cBraceOrPound {\n\
492 \n\
493 # Find start of the line, and make sure there''s nothing but white-space\n\
494 # before the character. If there''s anything before it, do nothing\n\
495 for (i=$1-1; ; i--) {\n\
496 if (i < 0) {\n\
497 lineStart = 0\n\
498 break\n\
499 }\n\
500 c = get_character(i)\n\
501 if (c == \"\\n\") {\n\
502 lineStart = i + 1\n\
503 break\n\
504 }\n\
505 if (c != \" \" && c != \"\\t\")\n\
506 return\n\
507 }\n\
508 \n\
509 # If the character was a pound, drag it all the way to the left margin\n\
510 if ($2 == \"#\") {\n\
511 replace_range(lineStart, $1, \"\")\n\
512 return\n\
513 }\n\
514 \n\
515 # Find the position on which to base the indent\n\
516 indent = cFindSmartIndentDist($1 - 1, \"noContinue\")\n\
517 if (indent == -1)\n\
518 return\n\
519 \n\
520 # Adjust the indent if it''s a right brace (left needs no adjustment)\n\
521 if ($2 == \"}\") {\n\
522 indent -= defaultIndent($cIndentDist)\n\
523 if (indent < 0)\n\
524 indent = 0\n\
525 }\n\
526 \n\
527 # Replace the current indent with the new indent string\n\
528 insertStr = makeIndentString(indent)\n\
529 replace_range(lineStart, $1, insertStr)\n\
530 }\n\
531 \n\
532 #\n\
533 # Find Smart Indent Distance for a newline character inserted at $1,\n\
534 # or return -1 to give up. Adding the optional argument \"noContinue\"\n\
535 # will stop the routine from inserting line continuation indents\n\
536 #\n\
537 define cFindSmartIndentDist {\n\
538 \n\
539 # Find a known good indent to base the new indent upon\n\
540 anchorPos = cFindIndentAnchorPoint($1)\n\
541 if (anchorPos == -1)\n\
542 return -1\n\
543 \n\
544 # Find the indentation of that line\n\
545 anchorIndent = measureIndent(anchorPos)\n\
546 \n\
547 # Look for special keywords which affect indent (for, if, else while, do)\n\
548 # and modify the continuation indent distance to the normal indent\n\
549 # distance when a completed statement of this type occupies the line.\n\
550 if ($n_args >= 2 && $2 == \"noContinue\") {\n\
551 continueIndent = 0\n\
552 $allowSemi = 0\n\
553 } else\n\
554 continueIndent = cCalcContinueIndent(anchorPos, $1)\n\
555 \n\
556 # Move forward from anchor point, ignoring comments and blank lines,\n\
557 # remembering the last non-white, non-comment character. If $1 is\n\
558 # in the middle of a comment, give up\n\
559 lastChar = get_character(anchorPos)\n\
560 if (anchorPos < $1) {\n\
561 for (i=anchorPos;;) {\n\
562 i = cSkipBlankSpace(i, $1, 1)\n\
563 if (i == -1)\n\
564 return -1\n\
565 if (i >= $1)\n\
566 break\n\
567 lastChar = get_character(i++)\n\
568 }\n\
569 }\n\
570 \n\
571 # Return the new indent based on the type of the last character.\n\
572 # In a for stmt, however, last character may be a semicolon and not\n\
573 # signal the end of the statement\n\
574 if (lastChar == \"{\")\n\
575 return anchorIndent + defaultIndent($cIndentDist)\n\
576 else if (lastChar == \"}\")\n\
577 return anchorIndent\n\
578 else if (lastChar == \";\") {\n\
579 if ($allowSemi)\n\
580 return anchorIndent + continueIndent\n\
581 else\n\
582 return anchorIndent\n\
583 } else if (lastChar == \":\" && get_range(anchorPos, anchorPos+4) == \"case\")\n\
584 return anchorIndent + defaultIndent($cIndentDist)\n\
585 return anchorIndent + continueIndent\n\
586 }\n\
587 \n\
588 #\n\
589 # Calculate the continuation indent distance for statements not ending in\n\
590 # semicolons or braces. This is not necessarily $continueIndent. It may\n\
591 # be adjusted if the statement contains if, while, for, or else.\n\
592 #\n\
593 # As a side effect, also return $allowSemi to help distinguish statements\n\
594 # which might contain an embedded semicolon, which should not be interpreted\n\
595 # as an end of statement character.\n\
596 #\n\
597 define cCalcContinueIndent {\n\
598 \n\
599 anchorPos = $1\n\
600 maxPos = $2\n\
601 \n\
602 # Figure out if the anchor is on a keyword which changes indent. A special\n\
603 # case is made for elses nested in after braces\n\
604 anchorIsFor = 0\n\
605 $allowSemi = 0\n\
606 if (get_character(anchorPos) == \"}\") {\n\
607 for (i=anchorPos+1; i<maxPos; i++) {\n\
608 c = get_character(i)\n\
609 if (c != \" \" && c != \"\\t\")\n\
610 break\n\
611 }\n\
612 if (get_range(i, i+4) == \"else\") {\n\
613 keywordEnd = i + 4\n\
614 needsBalancedParens = 0\n\
615 } else\n\
616 return defaultContIndent($cContinuationIndent)\n\
617 } else if (get_range(anchorPos, anchorPos + 4) == \"else\") {\n\
618 keywordEnd = anchorPos + 4\n\
619 needsBalancedParens = 0\n\
620 } else if (get_range(anchorPos, anchorPos + 2) == \"do\") {\n\
621 keywordEnd = anchorPos + 2\n\
622 needsBalancedParens = 0\n\
623 } else if (get_range(anchorPos, anchorPos + 3) == \"for\") {\n\
624 keywordEnd = anchorPos + 3\n\
625 anchorIsFor = 1\n\
626 needsBalancedParens = 1\n\
627 } else if (get_range(anchorPos, anchorPos + 2) == \"if\") {\n\
628 keywordEnd = anchorPos + 2\n\
629 needsBalancedParens = 1\n\
630 } else if (get_range(anchorPos, anchorPos + 5) == \"while\") {\n\
631 keywordEnd = anchorPos + 5\n\
632 needsBalancedParens = 1\n\
633 } else\n\
634 return defaultContIndent($cContinuationIndent)\n\
635 \n\
636 # If the keyword must be followed balanced parenthesis, find the end of\n\
637 # the statement by following balanced parens. If the parens aren''t\n\
638 # balanced by maxPos, continue the condition. In the special case of\n\
639 # the for keyword, a semicolon can end the line and the caller should be\n\
640 # signaled to allow that\n\
641 if (needsBalancedParens) {\n\
642 stmtEnd = findBalancingParen(keywordEnd, maxPos)\n\
643 if (stmtEnd == -1) {\n\
644 $allowSemi = anchorIsFor\n\
645 return defaultContIndent($cContinuationIndent)\n\
646 }\n\
647 } else\n\
648 stmtEnd = keywordEnd\n\
649 \n\
650 # check if the statement ends the line\n\
651 lineEnd = cSkipBlankSpace(stmtEnd, maxPos, 0)\n\
652 if (lineEnd == -1) # ends in comment or preproc\n\
653 return -1\n\
654 if (lineEnd == maxPos) # maxPos happens at stmt end\n\
655 return defaultIndent($cIndentDist)\n\
656 c = get_character(lineEnd)\n\
657 if (c != \"\\n\") # something past last paren on line,\n\
658 return defaultIndent($cIndentDist) # probably quoted or extra braces\n\
659 \n\
660 # stmt contintinues beyond matching paren && newline, we''re in\n\
661 # the conditional part, calculate the continue indent distance\n\
662 # recursively, based on the anchor point of the new line\n\
663 newAnchor = cSkipBlankSpace(lineEnd+1, maxPos, 1)\n\
664 if (newAnchor == -1)\n\
665 return -1\n\
666 if (newAnchor == maxPos)\n\
667 return defaultIndent($cIndentDist)\n\
668 return cCalcContinueIndent(newAnchor, maxPos) + defaultIndent($cIndentDist)\n\
669 }\n\
670 ";
671
672
673
674
675
676
677
678
679
680
681 void BeginSmartIndent(WindowInfo *window,
int warn)
682 {
683 windowSmartIndentData *winData;
684 smartIndentRec *indentMacros;
685 char *modeName, *stoppedAt, *errMsg;
686 static int initialized;
687
688
689 modeName = LanguageModeName(window->languageMode);
690 if (modeName ==
NULL)
691 {
692 if (warn)
693 {
694 DialogF(
DF_WARN, window->shell,
1,
"Smart Indent",
695 "No language-specific mode has been set for this file.\n\n"
696 "To use smart indent in this window, please select a\n"
697 "language from the Preferences -> Language Modes menu.",
698 "OK");
699 }
700 return;
701 }
702
703
704 indentMacros = findIndentSpec(modeName);
705 if (indentMacros ==
NULL)
706 {
707 if (warn)
708 {
709 DialogF(
DF_WARN, window->shell,
1,
"Smart Indent",
710 "Smart indent is not available in languagemode\n%s.\n\n"
711 "You can create new smart indent macros in the\n"
712 "Preferences -> Default Settings -> Smart Indent\n"
713 "dialog, or choose a different language mode from:\n"
714 "Preferences -> Language Mode.",
"OK", modeName);
715 }
716 return;
717 }
718
719
720
721
722 ReadMacroInitFile(window);
723
724
725
726
727 if (!initialized) {
728 if (!ReadMacroString(window, CommonMacros,
729 "smart indent common initialization macros"))
730 return;
731 initialized = True;
732 }
733 if (indentMacros->initMacro !=
NULL) {
734 if (!ReadMacroString(window, indentMacros->initMacro,
735 "smart indent initialization macro"))
736 return;
737 }
738
739
740 winData = (windowSmartIndentData *)NEditMalloc(
sizeof(windowSmartIndentData));
741 winData->inNewLineMacro =
0;
742 winData->inModMacro =
0;
743 winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg,
744 &stoppedAt);
745 if (winData->newlineMacro ==
NULL) {
746 NEditFree(winData);
747 ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
748 "newline macro", errMsg);
749 return;
750 }
751 if (indentMacros->modMacro ==
NULL)
752 winData->modMacro =
NULL;
753 else {
754 winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
755 &stoppedAt);
756 if (winData->modMacro ==
NULL) {
757 FreeProgram(winData->newlineMacro);
758 NEditFree(winData);
759 ParseError(window->shell, indentMacros->modMacro, stoppedAt,
760 "smart indent modify macro", errMsg);
761 return;
762 }
763 }
764 window->smartIndentData = (
void *)winData;
765 }
766
767 void EndSmartIndent(WindowInfo *window)
768 {
769 windowSmartIndentData *winData =
770 (windowSmartIndentData *)window->smartIndentData;
771
772 if (winData ==
NULL)
773 return;
774
775
776 if (winData->modMacro !=
NULL)
777 FreeProgram(winData->modMacro);
778 FreeProgram(winData->newlineMacro);
779 NEditFree(winData);
780 window->smartIndentData =
NULL;
781 }
782
783
784
785
786 int SmartIndentMacrosAvailable(
char *languageModeName)
787 {
788 return findIndentSpec(languageModeName) !=
NULL;
789 }
790
791
792
793
794
795
796
797 void SmartIndentCB(Widget w, XtPointer clientData, XtPointer callData)
798 {
799 WindowInfo *window = WidgetToWindow(w);
800 smartIndentCBStruct *cbInfo = (smartIndentCBStruct *)callData;
801
802 if (window->smartIndentData ==
NULL)
803 return;
804 if (cbInfo->reason ==
CHAR_TYPED)
805 executeModMacro(window, cbInfo);
806 else if (cbInfo->reason ==
NEWLINE_INDENT_NEEDED)
807 executeNewlineMacro(window, cbInfo);
808 }
809
810
811
812
813
814 static void executeNewlineMacro(WindowInfo *window, smartIndentCBStruct *cbInfo)
815 {
816 windowSmartIndentData *winData =
817 (windowSmartIndentData *)window->smartIndentData;
818
819 static DataValue posValue = {
INT_TAG, {
0}};
820 DataValue result;
821 RestartData *continuation;
822 char *errMsg;
823 int stat;
824
825
826
827
828
829 if (winData->inNewLineMacro)
830 return;
831
832
833 posValue.val.n = cbInfo->pos;
834 ++(winData->inNewLineMacro);
835 stat = ExecuteMacro(window, winData->newlineMacro,
1, &posValue, &result,
836 &continuation, &errMsg);
837
838
839 while (stat ==
MACRO_TIME_LIMIT)
840 stat = ContinueMacro(continuation, &result, &errMsg);
841
842 --(winData->inNewLineMacro);
843
844
845
846 SafeGC();
847
848
849 if (stat ==
MACRO_PREEMPT || stat ==
MACRO_ERROR)
850 {
851 DialogF(
DF_ERR, window->shell,
1,
"Smart Indent",
852 "Error in smart indent macro:\n%s",
"OK",
853 stat ==
MACRO_ERROR
854 ? errMsg
855 :
"dialogs and shell commands not permitted");
856 EndSmartIndent(window);
857 return;
858 }
859
860
861 if (result.tag !=
INT_TAG || result.val.n < -
1 || result.val.n >
1000)
862 {
863 DialogF(
DF_ERR, window->shell,
1,
"Smart Indent",
864 "Smart indent macros must return\ninteger indent distance",
865 "OK");
866 EndSmartIndent(window);
867 return;
868 }
869
870 cbInfo->indentRequest = result.val.n;
871 }
872
873
874 Boolean InSmartIndentMacros(WindowInfo *window) {
875 windowSmartIndentData *winData =
876 (windowSmartIndentData *)window->smartIndentData;
877
878 return((winData && (winData->inModMacro || winData->inNewLineMacro)));
879 }
880
881
882
883
884
885 static void executeModMacro(WindowInfo *window,smartIndentCBStruct *cbInfo)
886 {
887 windowSmartIndentData *winData =
888 (windowSmartIndentData *)window->smartIndentData;
889
890 static DataValue args[
2] = {{
INT_TAG, {
0}}, {
STRING_TAG, {
0}}};
891
892 static int inModCB = False;
893 DataValue result;
894 RestartData *continuation;
895 char *errMsg;
896 int stat;
897
898
899
900 if (winData ==
NULL || winData->modMacro ==
NULL || inModCB)
901 return;
902
903
904
905
906 args[
0].val.n = cbInfo->pos;
907 AllocNStringCpy(&args[
1].val.str, cbInfo->charsTyped);
908
909 inModCB = True;
910 ++(winData->inModMacro);
911
912 stat = ExecuteMacro(window, winData->modMacro,
2, args, &result,
913 &continuation, &errMsg);
914 while (stat ==
MACRO_TIME_LIMIT)
915 stat = ContinueMacro(continuation, &result, &errMsg);
916
917 --(winData->inModMacro);
918 inModCB = False;
919
920
921 if (stat ==
MACRO_PREEMPT || stat ==
MACRO_ERROR)
922 {
923 DialogF(
DF_ERR, window->shell,
1,
"Smart Indent",
924 "Error in smart indent modification macro:\n%s",
"OK",
925 stat ==
MACRO_ERROR
926 ? errMsg
927 :
"dialogs and shell commands not permitted");
928 EndSmartIndent(window);
929 return;
930 }
931 }
932
933 void EditSmartIndentMacros(WindowInfo *window)
934 {
935 #define BORDER 4
936 Widget form, lmOptMenu, lmForm, lmBtn;
937 Widget okBtn, applyBtn, checkBtn, deleteBtn, commonBtn;
938 Widget closeBtn, helpBtn, restoreBtn, pane;
939 Widget initForm, newlineForm, modifyForm;
940 Widget initLbl, newlineLbl, modifyLbl;
941 XmString s1;
942 char *lmName;
943 Arg args[
20];
944 int n;
945
946
947 if (SmartIndentDialog.shell !=
NULL) {
948 RaiseDialogWindow(SmartIndentDialog.shell);
949 return;
950 }
951
952 if (LanguageModeName(
0) ==
NULL)
953 {
954 DialogF(
DF_WARN, window->shell,
1,
"Language Mode",
955 "No Language Modes defined",
"OK");
956 return;
957 }
958
959
960 lmName = LanguageModeName(window->languageMode ==
PLAIN_LANGUAGE_MODE ?
0 :
961 window->languageMode);
962 SmartIndentDialog.langModeName = NEditStrdup(lmName);
963
964
965 n =
0;
966 XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); n++;
967 XtSetArg(args[n], XmNiconName,
"NEdit Smart Indent Macros"); n++;
968 XtSetArg(args[n], XmNtitle,
"Program Smart Indent Macros"); n++;
969 SmartIndentDialog.shell = CreateWidget(TheAppShell,
"smartIndent",
970 topLevelShellWidgetClass, args, n);
971 AddSmallIcon(SmartIndentDialog.shell);
972 form = XtVaCreateManagedWidget(
"editSmartIndentMacros", xmFormWidgetClass,
973 SmartIndentDialog.shell, XmNautoUnmanage, False,
974 XmNresizePolicy, XmRESIZE_NONE,
NULL);
975 XtAddCallback(form, XmNdestroyCallback, destroyCB,
NULL);
976 AddMotifCloseCallback(SmartIndentDialog.shell, closeCB,
NULL);
977
978 lmForm = XtVaCreateManagedWidget(
"lmForm", xmFormWidgetClass,
979 form,
980 XmNleftAttachment, XmATTACH_POSITION,
981 XmNleftPosition,
1,
982 XmNtopAttachment, XmATTACH_POSITION,
983 XmNtopPosition,
1,
984 XmNrightAttachment, XmATTACH_POSITION,
985 XmNrightPosition,
99,
NULL);
986
987 SmartIndentDialog.lmPulldown = CreateLanguageModeMenu(lmForm, langModeCB,
988 NULL);
989 n =
0;
990 XtSetArg(args[n], XmNspacing,
0); n++;
991 XtSetArg(args[n], XmNmarginWidth,
0); n++;
992 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
993 XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
994 XtSetArg(args[n], XmNleftPosition,
50); n++;
995 XtSetArg(args[n], XmNsubMenuId, SmartIndentDialog.lmPulldown); n++;
996 lmOptMenu = XmCreateOptionMenu(lmForm,
"langModeOptMenu", args, n);
997 XtManageChild(lmOptMenu);
998 SmartIndentDialog.lmOptMenu = lmOptMenu;
999
1000 XtVaCreateManagedWidget(
"lmLbl", xmLabelGadgetClass, lmForm,
1001 XmNlabelString, s1=XmStringCreateSimple(
"Language Mode:"),
1002 XmNmnemonic,
'L',
1003 XmNuserData, XtParent(SmartIndentDialog.lmOptMenu),
1004 XmNalignment, XmALIGNMENT_END,
1005 XmNrightAttachment, XmATTACH_POSITION,
1006 XmNrightPosition,
50,
1007 XmNtopAttachment, XmATTACH_FORM,
1008 XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
1009 XmNbottomWidget, lmOptMenu,
NULL);
1010 XmStringFree(s1);
1011
1012 lmBtn = XtVaCreateManagedWidget(
"lmBtn", xmPushButtonWidgetClass, lmForm,
1013 XmNlabelString, s1=
MKSTRING(
"Add / Modify\nLanguage Mode..."),
1014 XmNmnemonic,
'A',
1015 XmNrightAttachment, XmATTACH_FORM,
1016 XmNtopAttachment, XmATTACH_FORM,
NULL);
1017 XtAddCallback(lmBtn, XmNactivateCallback, lmDialogCB,
NULL);
1018 XmStringFree(s1);
1019
1020 commonBtn = XtVaCreateManagedWidget(
"commonBtn", xmPushButtonWidgetClass,
1021 lmForm,
1022 XmNlabelString, s1=
MKSTRING(
"Common / Shared\nInitialization..."),
1023 XmNmnemonic,
'C',
1024 XmNleftAttachment, XmATTACH_FORM,
1025 XmNtopAttachment, XmATTACH_FORM,
NULL);
1026 XtAddCallback(commonBtn, XmNactivateCallback, commonDialogCB,
NULL);
1027 XmStringFree(s1);
1028
1029 okBtn = XtVaCreateManagedWidget(
"ok", xmPushButtonWidgetClass, form,
1030 XmNlabelString, s1=XmStringCreateSimple(
"OK"),
1031 XmNmarginWidth,
BUTTON_WIDTH_MARGIN,
1032 XmNleftAttachment, XmATTACH_POSITION,
1033 XmNleftPosition,
1,
1034 XmNrightAttachment, XmATTACH_POSITION,
1035 XmNrightPosition,
13,
1036 XmNbottomAttachment, XmATTACH_FORM,
1037 XmNbottomOffset,
BORDER,
NULL);
1038 XtAddCallback(okBtn, XmNactivateCallback, okCB,
NULL);
1039 XmStringFree(s1);
1040
1041 applyBtn = XtVaCreateManagedWidget(
"apply", xmPushButtonWidgetClass, form,
1042 XmNlabelString, s1=XmStringCreateSimple(
"Apply"),
1043 XmNmnemonic,
'y',
1044 XmNleftAttachment, XmATTACH_POSITION,
1045 XmNleftPosition,
13,
1046 XmNrightAttachment, XmATTACH_POSITION,
1047 XmNrightPosition,
26,
1048 XmNbottomAttachment, XmATTACH_FORM,
1049 XmNbottomOffset,
BORDER,
NULL);
1050 XtAddCallback(applyBtn, XmNactivateCallback, applyCB,
NULL);
1051 XmStringFree(s1);
1052
1053 checkBtn = XtVaCreateManagedWidget(
"check", xmPushButtonWidgetClass, form,
1054 XmNlabelString, s1=XmStringCreateSimple(
"Check"),
1055 XmNmnemonic,
'k',
1056 XmNleftAttachment, XmATTACH_POSITION,
1057 XmNleftPosition,
26,
1058 XmNrightAttachment, XmATTACH_POSITION,
1059 XmNrightPosition,
39,
1060 XmNbottomAttachment, XmATTACH_FORM,
1061 XmNbottomOffset,
BORDER,
NULL);
1062 XtAddCallback(checkBtn, XmNactivateCallback, checkCB,
NULL);
1063 XmStringFree(s1);
1064
1065 deleteBtn = XtVaCreateManagedWidget(
"delete", xmPushButtonWidgetClass, form,
1066 XmNlabelString, s1=XmStringCreateSimple(
"Delete"),
1067 XmNmnemonic,
'D',
1068 XmNleftAttachment, XmATTACH_POSITION,
1069 XmNleftPosition,
39,
1070 XmNrightAttachment, XmATTACH_POSITION,
1071 XmNrightPosition,
52,
1072 XmNbottomAttachment, XmATTACH_FORM,
1073 XmNbottomOffset,
BORDER,
NULL);
1074 XtAddCallback(deleteBtn, XmNactivateCallback, deleteCB,
NULL);
1075 XmStringFree(s1);
1076
1077 restoreBtn = XtVaCreateManagedWidget(
"restore", xmPushButtonWidgetClass, form,
1078 XmNlabelString, s1=XmStringCreateSimple(
"Restore Defaults"),
1079 XmNmnemonic,
'f',
1080 XmNleftAttachment, XmATTACH_POSITION,
1081 XmNleftPosition,
52,
1082 XmNrightAttachment, XmATTACH_POSITION,
1083 XmNrightPosition,
73,
1084 XmNbottomAttachment, XmATTACH_FORM,
1085 XmNbottomOffset,
BORDER,
NULL);
1086 XtAddCallback(restoreBtn, XmNactivateCallback, restoreCB,
NULL);
1087 XmStringFree(s1);
1088
1089 closeBtn = XtVaCreateManagedWidget(
"close", xmPushButtonWidgetClass,
1090 form,
1091 XmNlabelString, s1=XmStringCreateSimple(
"Close"),
1092 XmNleftAttachment, XmATTACH_POSITION,
1093 XmNleftPosition,
73,
1094 XmNrightAttachment, XmATTACH_POSITION,
1095 XmNrightPosition,
86,
1096 XmNbottomAttachment, XmATTACH_FORM,
1097 XmNbottomOffset,
BORDER,
NULL);
1098 XtAddCallback(closeBtn, XmNactivateCallback, closeCB,
NULL);
1099 XmStringFree(s1);
1100
1101 helpBtn = XtVaCreateManagedWidget(
"help", xmPushButtonWidgetClass,
1102 form,
1103 XmNlabelString, s1=XmStringCreateSimple(
"Help"),
1104 XmNmnemonic,
'H',
1105 XmNleftAttachment, XmATTACH_POSITION,
1106 XmNleftPosition,
86,
1107 XmNrightAttachment, XmATTACH_POSITION,
1108 XmNrightPosition,
99,
1109 XmNbottomAttachment, XmATTACH_FORM,
1110 XmNbottomOffset,
BORDER,
NULL);
1111 XtAddCallback(helpBtn, XmNactivateCallback, helpCB,
NULL);
1112 XmStringFree(s1);
1113
1114 pane = XtVaCreateManagedWidget(
"pane", xmPanedWindowWidgetClass, form,
1115 XmNleftAttachment, XmATTACH_POSITION,
1116 XmNleftPosition,
1,
1117 XmNrightAttachment, XmATTACH_POSITION,
1118 XmNrightPosition,
99,
1119 XmNtopAttachment, XmATTACH_WIDGET,
1120 XmNtopWidget, lmForm,
1121 XmNbottomAttachment, XmATTACH_WIDGET,
1122 XmNbottomWidget, okBtn,
NULL);
1123
1124
1125
1126 initForm = XtVaCreateManagedWidget(
"initForm", xmFormWidgetClass,
1127 pane,
NULL);
1128 initLbl = XtVaCreateManagedWidget(
"initLbl", xmLabelGadgetClass, initForm,
1129 XmNlabelString, s1=XmStringCreateSimple(
1130 "Language Specific Initialization Macro Commands and Definitions"),
1131 XmNmnemonic,
'I',
NULL);
1132 XmStringFree(s1);
1133 n =
0;
1134 XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
1135 XtSetArg(args[n], XmNrows,
5); n++;
1136 XtSetArg(args[n], XmNcolumns,
80); n++;
1137 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1138 XtSetArg(args[n], XmNtopWidget, initLbl); n++;
1139 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1140 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1141 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1142 SmartIndentDialog.initMacro = XmCreateScrolledText(initForm,
1143 "initMacro", args, n);
1144 AddMouseWheelSupport(SmartIndentDialog.initMacro);
1145 XtManageChild(SmartIndentDialog.initMacro);
1146 RemapDeleteKey(SmartIndentDialog.initMacro);
1147 XtVaSetValues(initLbl, XmNuserData, SmartIndentDialog.initMacro,
NULL);
1148
1149 newlineForm = XtVaCreateManagedWidget(
"newlineForm", xmFormWidgetClass,
1150 pane,
NULL);
1151 newlineLbl = XtVaCreateManagedWidget(
"newlineLbl", xmLabelGadgetClass,
1152 newlineForm,
1153 XmNlabelString, s1=XmStringCreateSimple(
"Newline Macro"),
1154 XmNmnemonic,
'N',
NULL);
1155 XmStringFree(s1);
1156 XtVaCreateManagedWidget(
"newlineArgsLbl", xmLabelGadgetClass,
1157 newlineForm, XmNalignment, XmALIGNMENT_END,
1158 XmNlabelString, s1=XmStringCreateSimple(
1159 "($1 is insert position, return indent request or -1)"),
1160 XmNrightAttachment, XmATTACH_FORM,
NULL);
1161 XmStringFree(s1);
1162 n =
0;
1163 XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
1164 XtSetArg(args[n], XmNrows,
5); n++;
1165 XtSetArg(args[n], XmNcolumns,
80); n++;
1166 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1167 XtSetArg(args[n], XmNtopWidget, newlineLbl); n++;
1168 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1169 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1170 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1171 SmartIndentDialog.newlineMacro = XmCreateScrolledText(newlineForm,
1172 "newlineMacro", args, n);
1173 AddMouseWheelSupport(SmartIndentDialog.newlineMacro);
1174 XtManageChild(SmartIndentDialog.newlineMacro);
1175 RemapDeleteKey(SmartIndentDialog.newlineMacro);
1176 XtVaSetValues(newlineLbl, XmNuserData, SmartIndentDialog.newlineMacro,
NULL);
1177
1178 modifyForm = XtVaCreateManagedWidget(
"modifyForm", xmFormWidgetClass,
1179 pane,
NULL);
1180 modifyLbl = XtVaCreateManagedWidget(
"modifyLbl", xmLabelGadgetClass,
1181 modifyForm, XmNlabelString,s1=XmStringCreateSimple(
"Type-in Macro"),
1182 XmNmnemonic,
'M',
NULL);
1183 XmStringFree(s1);
1184 XtVaCreateManagedWidget(
"modifyArgsLbl", xmLabelGadgetClass,
1185 modifyForm, XmNalignment, XmALIGNMENT_END,
1186 XmNlabelString, s1=XmStringCreateSimple(
1187 "($1 is position, $2 is character to be inserted)"),
1188 XmNrightAttachment, XmATTACH_FORM,
NULL);
1189 XmStringFree(s1);
1190 n =
0;
1191 XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
1192 XtSetArg(args[n], XmNrows,
5); n++;
1193 XtSetArg(args[n], XmNcolumns,
80); n++;
1194 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1195 XtSetArg(args[n], XmNtopWidget, modifyLbl); n++;
1196 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1197 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1198 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1199 SmartIndentDialog.modMacro = XmCreateScrolledText(modifyForm,
1200 "modifyMacro", args, n);
1201 AddMouseWheelSupport(SmartIndentDialog.modMacro);
1202 XtManageChild(SmartIndentDialog.modMacro);
1203 RemapDeleteKey(SmartIndentDialog.modMacro);
1204 XtVaSetValues(modifyLbl, XmNuserData, SmartIndentDialog.modMacro,
NULL);
1205
1206
1207 XtVaSetValues(form, XmNdefaultButton, okBtn,
NULL);
1208 XtVaSetValues(form, XmNcancelButton, closeBtn,
NULL);
1209
1210
1211 AddDialogMnemonicHandler(form,
FALSE);
1212
1213
1214 setSmartIndentDialogData(findIndentSpec(lmName));
1215 SetLangModeMenu(SmartIndentDialog.lmOptMenu,SmartIndentDialog.langModeName);
1216
1217
1218 RealizeWithoutForcingPosition(SmartIndentDialog.shell);
1219 }
1220
1221 static void destroyCB(Widget w, XtPointer clientData, XtPointer callData)
1222 {
1223 NEditFree(SmartIndentDialog.langModeName);
1224 SmartIndentDialog.shell =
NULL;
1225 }
1226
1227 static void langModeCB(Widget w, XtPointer clientData, XtPointer callData)
1228 {
1229 char *modeName;
1230 int i, resp;
1231 static smartIndentRec emptyIndentSpec = {
NULL,
NULL,
NULL,
NULL};
1232 smartIndentRec *oldMacros, *newMacros;
1233
1234
1235 XtVaGetValues(w, XmNuserData, &modeName,
NULL);
1236 if (!strcmp(modeName, SmartIndentDialog.langModeName))
1237 return;
1238
1239
1240 for (i=
0; i<NSmartIndentSpecs; i++)
1241 if (!strcmp(SmartIndentDialog.langModeName,SmartIndentSpecs[i]->lmName))
1242 break;
1243 oldMacros = i == NSmartIndentSpecs ? &emptyIndentSpec : SmartIndentSpecs[i];
1244
1245
1246
1247 newMacros = getSmartIndentDialogData();
1248 if (indentSpecsDiffer(oldMacros, newMacros))
1249 {
1250 resp = DialogF(
DF_QUES, SmartIndentDialog.shell,
3,
"Smart Indent",
1251 "Smart indent macros for language mode\n"
1252 "%s were changed. Apply changes?",
"Apply",
"Discard",
1253 "Cancel", SmartIndentDialog.langModeName);
1254
1255 if (resp ==
3)
1256 {
1257 SetLangModeMenu(SmartIndentDialog.lmOptMenu,
1258 SmartIndentDialog.langModeName);
1259 return;
1260 }
else if (resp ==
1)
1261 {
1262 if (checkSmartIndentDialogData())
1263 {
1264 if (oldMacros == &emptyIndentSpec)
1265 {
1266 SmartIndentSpecs[NSmartIndentSpecs++]
1267 = copyIndentSpec(newMacros);
1268 }
else
1269 {
1270 freeIndentSpec(oldMacros);
1271 SmartIndentSpecs[i] = copyIndentSpec(newMacros);
1272 }
1273 }
else
1274 {
1275 SetLangModeMenu(SmartIndentDialog.lmOptMenu,
1276 SmartIndentDialog.langModeName);
1277 return;
1278 }
1279 }
1280 }
1281 freeIndentSpec(newMacros);
1282
1283
1284 SmartIndentDialog.langModeName = NEditStrdup(modeName);
1285 setSmartIndentDialogData(findIndentSpec(modeName));
1286 }
1287
1288 static void lmDialogCB(Widget w, XtPointer clientData, XtPointer callData)
1289 {
1290 EditLanguageModes();
1291 }
1292
1293 static void commonDialogCB(Widget w, XtPointer clientData, XtPointer callData)
1294 {
1295 EditCommonSmartIndentMacro();
1296 }
1297
1298 static void okCB(Widget w, XtPointer clientData, XtPointer callData)
1299 {
1300
1301 if (!updateSmartIndentData())
1302 return;
1303
1304
1305 CloseAllPopupsFor(SmartIndentDialog.shell);
1306 XtDestroyWidget(SmartIndentDialog.shell);
1307 }
1308
1309 static void applyCB(Widget w, XtPointer clientData, XtPointer callData)
1310 {
1311
1312 updateSmartIndentData();
1313 }
1314
1315 static void checkCB(Widget w, XtPointer clientData, XtPointer callData)
1316 {
1317 if (checkSmartIndentDialogData())
1318 DialogF(
DF_INF, SmartIndentDialog.shell,
1,
"Macro compiled",
1319 "Macros compiled without error",
"OK");
1320 }
1321
1322 static void restoreCB(Widget w, XtPointer clientData, XtPointer callData)
1323 {
1324 int i;
1325 smartIndentRec *defaultIS;
1326
1327
1328 for (i=
0; i<
N_DEFAULT_INDENT_SPECS; i++)
1329 {
1330 if (!strcmp(SmartIndentDialog.langModeName,
1331 DefaultIndentSpecs[i].lmName))
1332 {
1333 break;
1334 }
1335 }
1336
1337 if (i ==
N_DEFAULT_INDENT_SPECS)
1338 {
1339 DialogF(
DF_WARN, SmartIndentDialog.shell,
1,
"Smart Indent",
1340 "There are no default indent macros\nfor language mode %s",
1341 "OK", SmartIndentDialog.langModeName);
1342 return;
1343 }
1344 defaultIS = &DefaultIndentSpecs[i];
1345
1346 if (DialogF(
DF_WARN, SmartIndentDialog.shell,
2,
"Discard Changes",
1347 "Are you sure you want to discard\n"
1348 "all changes to smart indent macros\n"
1349 "for language mode %s?",
"Discard",
"Cancel",
1350 SmartIndentDialog.langModeName) ==
2)
1351 {
1352 return;
1353 }
1354
1355
1356
1357 for (i=
0; i<NSmartIndentSpecs; i++)
1358 if (!strcmp(SmartIndentDialog.langModeName,SmartIndentSpecs[i]->lmName))
1359 break;
1360 if (i < NSmartIndentSpecs) {
1361 freeIndentSpec(SmartIndentSpecs[i]);
1362 SmartIndentSpecs[i] = copyIndentSpec(defaultIS);
1363 }
else
1364 SmartIndentSpecs[NSmartIndentSpecs++] = copyIndentSpec(defaultIS);
1365
1366
1367 setSmartIndentDialogData(defaultIS);
1368 }
1369
1370 static void deleteCB(Widget w, XtPointer clientData, XtPointer callData)
1371 {
1372 int i;
1373
1374 if (DialogF(
DF_WARN, SmartIndentDialog.shell,
2,
"Delete Macros",
1375 "Are you sure you want to delete smart indent\n"
1376 "macros for language mode %s?",
"Yes, Delete",
"Cancel",
1377 SmartIndentDialog.langModeName) ==
2)
1378 {
1379 return;
1380 }
1381
1382
1383 for (i=
0; i<NSmartIndentSpecs; i++)
1384 if (!strcmp(SmartIndentDialog.langModeName,SmartIndentSpecs[i]->lmName))
1385 break;
1386 if (i < NSmartIndentSpecs) {
1387 freeIndentSpec(SmartIndentSpecs[i]);
1388 memmove(&SmartIndentSpecs[i], &SmartIndentSpecs[i+
1],
1389 (NSmartIndentSpecs-
1 - i) *
sizeof(smartIndentRec *));
1390 NSmartIndentSpecs--;
1391 }
1392
1393
1394 setSmartIndentDialogData(
NULL);
1395 }
1396
1397 static void closeCB(Widget widget, XtPointer clientData, XtPointer callData)
1398 {
1399
1400 CloseAllPopupsFor(SmartIndentDialog.shell);
1401 XtDestroyWidget(SmartIndentDialog.shell);
1402 }
1403
1404 static void helpCB(Widget w, XtPointer clientData, XtPointer callData)
1405 {
1406 Help(
HELP_SMART_INDENT);
1407 }
1408
1409 static int checkSmartIndentDialogData(
void)
1410 {
1411 char *widgetText, *errMsg, *stoppedAt;
1412 Program *prog;
1413
1414
1415 if (!TextWidgetIsBlank(SmartIndentDialog.initMacro)) {
1416 widgetText =ensureNewline(XmTextGetString(SmartIndentDialog.initMacro));
1417 if (!CheckMacroString(SmartIndentDialog.shell, widgetText,
1418 "initialization macro", &stoppedAt)) {
1419 XmTextSetInsertionPosition(SmartIndentDialog.initMacro,
1420 stoppedAt - widgetText);
1421 XmProcessTraversal(SmartIndentDialog.initMacro, XmTRAVERSE_CURRENT);
1422 NEditFree(widgetText);
1423 return False;
1424 }
1425 NEditFree(widgetText);
1426 }
1427
1428
1429 if (TextWidgetIsBlank(SmartIndentDialog.newlineMacro))
1430 {
1431 DialogF(
DF_WARN, SmartIndentDialog.shell,
1,
"Smart Indent",
1432 "Newline macro required",
"OK");
1433 return False;
1434 }
1435
1436 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
1437 prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
1438 if (prog ==
NULL) {
1439 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
1440 "newline macro", errMsg);
1441 XmTextSetInsertionPosition(SmartIndentDialog.newlineMacro,
1442 stoppedAt - widgetText);
1443 XmProcessTraversal(SmartIndentDialog.newlineMacro, XmTRAVERSE_CURRENT);
1444 NEditFree(widgetText);
1445 return False;
1446 }
1447 NEditFree(widgetText);
1448 FreeProgram(prog);
1449
1450
1451 if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) {
1452 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
1453 prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
1454 if (prog ==
NULL) {
1455 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
1456 "modify macro", errMsg);
1457 XmTextSetInsertionPosition(SmartIndentDialog.modMacro,
1458 stoppedAt - widgetText);
1459 XmProcessTraversal(SmartIndentDialog.modMacro, XmTRAVERSE_CURRENT);
1460 NEditFree(widgetText);
1461 return False;
1462 }
1463 NEditFree(widgetText);
1464 FreeProgram(prog);
1465 }
1466 return True;
1467 }
1468
1469 static smartIndentRec *getSmartIndentDialogData(
void)
1470 {
1471 smartIndentRec *is;
1472
1473 is = (smartIndentRec *)NEditMalloc(
sizeof(smartIndentRec));
1474 is->lmName = NEditStrdup(SmartIndentDialog.langModeName);
1475 is->initMacro = TextWidgetIsBlank(SmartIndentDialog.initMacro) ?
NULL :
1476 ensureNewline(XmTextGetString(SmartIndentDialog.initMacro));
1477 is->newlineMacro = TextWidgetIsBlank(SmartIndentDialog.newlineMacro) ?
NULL:
1478 ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
1479 is->modMacro = TextWidgetIsBlank(SmartIndentDialog.modMacro) ?
NULL :
1480 ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
1481 return is;
1482 }
1483
1484 static void setSmartIndentDialogData(smartIndentRec *is)
1485 {
1486 if (is ==
NULL) {
1487 XmTextSetString(SmartIndentDialog.initMacro,
"");
1488 XmTextSetString(SmartIndentDialog.newlineMacro,
"");
1489 XmTextSetString(SmartIndentDialog.modMacro,
"");
1490 }
else {
1491 if (is->initMacro ==
NULL)
1492 XmTextSetString(SmartIndentDialog.initMacro,
"");
1493 else
1494 XmTextSetString(SmartIndentDialog.initMacro, is->initMacro);
1495 XmTextSetString(SmartIndentDialog.newlineMacro, is->newlineMacro);
1496 if (is->modMacro ==
NULL)
1497 XmTextSetString(SmartIndentDialog.modMacro,
"");
1498 else
1499 XmTextSetString(SmartIndentDialog.modMacro, is->modMacro);
1500 }
1501 }
1502
1503 void EditCommonSmartIndentMacro(
void)
1504 {
1505 #define VERT_BORDER 4
1506 Widget form, topLbl;
1507 Widget okBtn, applyBtn, checkBtn;
1508 Widget closeBtn, restoreBtn;
1509 XmString s1;
1510 Arg args[
20];
1511 int n;
1512
1513
1514 if (CommonDialog.shell !=
NULL) {
1515 RaiseDialogWindow(CommonDialog.shell);
1516 return;
1517 }
1518
1519
1520 n =
0;
1521 XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); n++;
1522 XtSetArg(args[n], XmNiconName,
"NEdit Common Smart Indent Macros"); n++;
1523 XtSetArg(args[n], XmNtitle,
"Common Smart Indent Macros"); n++;
1524 CommonDialog.shell = CreateWidget(TheAppShell,
"smartIndent",
1525 topLevelShellWidgetClass, args, n);
1526 AddSmallIcon(CommonDialog.shell);
1527 form = XtVaCreateManagedWidget(
"editCommonSIMacros", xmFormWidgetClass,
1528 CommonDialog.shell, XmNautoUnmanage, False,
1529 XmNresizePolicy, XmRESIZE_NONE,
NULL);
1530 XtAddCallback(form, XmNdestroyCallback, comDestroyCB,
NULL);
1531 AddMotifCloseCallback(CommonDialog.shell, comCloseCB,
NULL);
1532
1533 topLbl = XtVaCreateManagedWidget(
"topLbl", xmLabelGadgetClass, form,
1534 XmNlabelString, s1=XmStringCreateSimple(
1535 "Common Definitions for Smart Indent Macros"),
1536 XmNmnemonic,
'C',
1537 XmNtopAttachment, XmATTACH_FORM,
1538 XmNtopOffset,
VERT_BORDER,
1539 XmNleftAttachment, XmATTACH_POSITION,
1540 XmNleftPosition,
1,
NULL);
1541
1542 okBtn = XtVaCreateManagedWidget(
"ok", xmPushButtonWidgetClass, form,
1543 XmNlabelString, s1=XmStringCreateSimple(
"OK"),
1544 XmNmarginWidth,
BUTTON_WIDTH_MARGIN,
1545 XmNleftAttachment, XmATTACH_POSITION,
1546 XmNleftPosition,
6,
1547 XmNrightAttachment, XmATTACH_POSITION,
1548 XmNrightPosition,
18,
1549 XmNbottomAttachment, XmATTACH_FORM,
1550 XmNbottomOffset,
VERT_BORDER,
NULL);
1551 XtAddCallback(okBtn, XmNactivateCallback, comOKCB,
NULL);
1552 XmStringFree(s1);
1553
1554 applyBtn = XtVaCreateManagedWidget(
"apply", xmPushButtonWidgetClass, form,
1555 XmNlabelString, s1=XmStringCreateSimple(
"Apply"),
1556 XmNmnemonic,
'y',
1557 XmNleftAttachment, XmATTACH_POSITION,
1558 XmNleftPosition,
22,
1559 XmNrightAttachment, XmATTACH_POSITION,
1560 XmNrightPosition,
35,
1561 XmNbottomAttachment, XmATTACH_FORM,
1562 XmNbottomOffset,
VERT_BORDER,
NULL);
1563 XtAddCallback(applyBtn, XmNactivateCallback, comApplyCB,
NULL);
1564 XmStringFree(s1);
1565
1566 checkBtn = XtVaCreateManagedWidget(
"check", xmPushButtonWidgetClass, form,
1567 XmNlabelString, s1=XmStringCreateSimple(
"Check"),
1568 XmNmnemonic,
'k',
1569 XmNleftAttachment, XmATTACH_POSITION,
1570 XmNleftPosition,
39,
1571 XmNrightAttachment, XmATTACH_POSITION,
1572 XmNrightPosition,
52,
1573 XmNbottomAttachment, XmATTACH_FORM,
1574 XmNbottomOffset,
VERT_BORDER,
NULL);
1575 XtAddCallback(checkBtn, XmNactivateCallback, comCheckCB,
NULL);
1576 XmStringFree(s1);
1577
1578 restoreBtn = XtVaCreateManagedWidget(
"restore", xmPushButtonWidgetClass,
1579 form,
1580 XmNlabelString, s1=XmStringCreateSimple(
"Restore Default"),
1581 XmNmnemonic,
'f',
1582 XmNleftAttachment, XmATTACH_POSITION,
1583 XmNleftPosition,
56,
1584 XmNrightAttachment, XmATTACH_POSITION,
1585 XmNrightPosition,
77,
1586 XmNbottomAttachment, XmATTACH_FORM,
1587 XmNbottomOffset,
VERT_BORDER,
NULL);
1588 XtAddCallback(restoreBtn, XmNactivateCallback, comRestoreCB,
NULL);
1589 XmStringFree(s1);
1590
1591 closeBtn = XtVaCreateManagedWidget(
"close", xmPushButtonWidgetClass,
1592 form,
1593 XmNlabelString, s1=XmStringCreateSimple(
"Close"),
1594 XmNleftAttachment, XmATTACH_POSITION,
1595 XmNleftPosition,
81,
1596 XmNrightAttachment, XmATTACH_POSITION,
1597 XmNrightPosition,
94,
1598 XmNbottomAttachment, XmATTACH_FORM,
1599 XmNbottomOffset,
VERT_BORDER,
NULL);
1600 XtAddCallback(closeBtn, XmNactivateCallback, comCloseCB,
NULL);
1601 XmStringFree(s1);
1602
1603 n =
0;
1604 XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
1605 XtSetArg(args[n], XmNrows,
24); n++;
1606 XtSetArg(args[n], XmNcolumns,
80); n++;
1607 XtSetArg(args[n], XmNvalue, CommonMacros); n++;
1608 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1609 XtSetArg(args[n], XmNtopWidget, topLbl); n++;
1610 XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
1611 XtSetArg(args[n], XmNleftPosition,
1); n++;
1612 XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
1613 XtSetArg(args[n], XmNrightPosition,
99); n++;
1614 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
1615 XtSetArg(args[n], XmNbottomWidget, okBtn); n++;
1616 XtSetArg(args[n], XmNbottomOffset,
VERT_BORDER); n++;
1617 CommonDialog.text = XmCreateScrolledText(form,
"commonText", args, n);
1618 AddMouseWheelSupport(CommonDialog.text);
1619 XtManageChild(CommonDialog.text);
1620 RemapDeleteKey(CommonDialog.text);
1621 XtVaSetValues(topLbl, XmNuserData, CommonDialog.text,
NULL);
1622
1623
1624 XtVaSetValues(form, XmNdefaultButton, okBtn,
NULL);
1625 XtVaSetValues(form, XmNcancelButton, closeBtn,
NULL);
1626
1627
1628 AddDialogMnemonicHandler(form,
FALSE);
1629
1630
1631 RealizeWithoutForcingPosition(CommonDialog.shell);
1632 }
1633
1634 static void comDestroyCB(Widget w, XtPointer clientData, XtPointer callData)
1635 {
1636 CommonDialog.shell =
NULL;
1637 }
1638
1639 static void comOKCB(Widget w, XtPointer clientData, XtPointer callData)
1640 {
1641
1642 if (!updateSmartIndentCommonData())
1643 return;
1644
1645
1646 XtDestroyWidget(CommonDialog.shell);
1647 }
1648
1649 static void comApplyCB(Widget w, XtPointer clientData, XtPointer callData)
1650 {
1651
1652 updateSmartIndentCommonData();
1653 }
1654
1655 static void comCheckCB(Widget w, XtPointer clientData, XtPointer callData)
1656 {
1657 if (checkSmartIndentCommonDialogData())
1658 {
1659 DialogF(
DF_INF, CommonDialog.shell,
1,
"Macro compiled",
1660 "Macros compiled without error",
"OK");
1661 }
1662 }
1663
1664 static void comRestoreCB(Widget w, XtPointer clientData, XtPointer callData)
1665 {
1666 if (DialogF(
DF_WARN, CommonDialog.shell,
2,
"Discard Changes",
1667 "Are you sure you want to discard all\n"
1668 "changes to common smart indent macros",
"Discard",
"Cancel") ==
2)
1669 {
1670 return;
1671 }
1672
1673
1674 NEditFree(CommonMacros);
1675 CommonMacros = NEditStrdup(DefaultCommonMacros);
1676
1677
1678 XmTextSetString(CommonDialog.text, CommonMacros);
1679 }
1680
1681 static void comCloseCB(Widget w, XtPointer clientData, XtPointer callData)
1682 {
1683
1684 XtDestroyWidget(CommonDialog.shell);
1685 }
1686
1687
1688
1689
1690
1691
1692 static int updateSmartIndentCommonData(
void)
1693 {
1694 WindowInfo *window;
1695
1696
1697 if (!checkSmartIndentCommonDialogData())
1698 return False;
1699
1700
1701 CommonMacros = ensureNewline(XmTextGetString(CommonDialog.text));
1702
1703
1704
1705
1706 if (!ReadMacroString(WindowList, CommonMacros,
"common macros"))
1707 return False;
1708
1709
1710
1711
1712 for (window=WindowList; window!=
NULL; window=window->next) {
1713 if (window->indentStyle ==
SMART_INDENT &&
1714 window->languageMode !=
PLAIN_LANGUAGE_MODE) {
1715 EndSmartIndent(window);
1716 BeginSmartIndent(window, False);
1717 }
1718 }
1719
1720
1721 MarkPrefsChanged();
1722
1723 return True;
1724 }
1725
1726 static int checkSmartIndentCommonDialogData(
void)
1727 {
1728 char *widgetText, *stoppedAt;
1729
1730 if (!TextWidgetIsBlank(CommonDialog.text)) {
1731 widgetText = ensureNewline(XmTextGetString(CommonDialog.text));
1732 if (!CheckMacroString(CommonDialog.shell, widgetText,
1733 "macros", &stoppedAt)) {
1734 XmTextSetInsertionPosition(CommonDialog.text, stoppedAt-widgetText);
1735 XmProcessTraversal(CommonDialog.text, XmTRAVERSE_CURRENT);
1736 NEditFree(widgetText);
1737 return False;
1738 }
1739 NEditFree(widgetText);
1740 }
1741 return True;
1742 }
1743
1744
1745
1746
1747
1748
1749 static int updateSmartIndentData(
void)
1750 {
1751 smartIndentRec *newMacros;
1752 WindowInfo *window;
1753 char *lmName;
1754 int i;
1755
1756
1757 if (!checkSmartIndentDialogData())
1758 return False;
1759
1760
1761 newMacros = getSmartIndentDialogData();
1762
1763
1764 for (i=
0; i<NSmartIndentSpecs; i++)
1765 if (!strcmp(SmartIndentDialog.langModeName,SmartIndentSpecs[i]->lmName))
1766 break;
1767
1768
1769
1770 if (i == NSmartIndentSpecs) {
1771 SmartIndentSpecs[NSmartIndentSpecs++] = newMacros;
1772 }
else {
1773 freeIndentSpec(SmartIndentSpecs[i]);
1774 SmartIndentSpecs[i] = newMacros;
1775 }
1776
1777
1778
1779 for (window=WindowList; window!=
NULL; window=window->next) {
1780 lmName = LanguageModeName(window->languageMode);
1781 if (lmName !=
NULL && !strcmp(lmName, newMacros->lmName)) {
1782 SetSensitive(window, window->smartIndentItem, True);
1783 if (window->indentStyle ==
SMART_INDENT &&
1784 window->languageMode !=
PLAIN_LANGUAGE_MODE) {
1785 EndSmartIndent(window);
1786 BeginSmartIndent(window, False);
1787 }
1788 }
1789 }
1790
1791
1792 MarkPrefsChanged();
1793
1794 return True;
1795 }
1796
1797 static int loadDefaultIndentSpec(
char *lmName)
1798 {
1799 int i;
1800
1801 for (i=
0; i<
N_DEFAULT_INDENT_SPECS; i++) {
1802 if (!strcmp(lmName, DefaultIndentSpecs[i].lmName)) {
1803 SmartIndentSpecs[NSmartIndentSpecs++] =
1804 copyIndentSpec(&DefaultIndentSpecs[i]);
1805 return True;
1806 }
1807 }
1808 return False;
1809 }
1810
1811 int LoadSmartIndentString(
char *inString)
1812 {
1813 char *errMsg, *inPtr = inString;
1814 smartIndentRec is, *isCopy;
1815 int i;
1816
1817 for (;;) {
1818
1819
1820 inPtr += strspn(inPtr,
" \t\n");
1821
1822
1823 if (*inPtr ==
'\0')
1824 return True;
1825
1826
1827 is.lmName = ReadSymbolicField(&inPtr);
1828 if (is.lmName ==
NULL)
1829 return siParseError(inString, inPtr,
"language mode name required");
1830 if (!SkipDelimiter(&inPtr, &errMsg)) {
1831 NEditFree(is.lmName);
1832 return siParseError(inString, inPtr, errMsg);
1833 }
1834
1835
1836
1837 if (!strncmp(inPtr,
"Default",
7)) {
1838 inPtr +=
7;
1839 if (!loadDefaultIndentSpec(is.lmName)) {
1840 NEditFree(is.lmName);
1841 return siParseError(inString, inPtr,
1842 "no default smart indent macros");
1843 }
1844 NEditFree(is.lmName);
1845 continue;
1846 }
1847
1848
1849
1850 is.initMacro = readSIMacro(&inPtr);
1851 if (is.initMacro ==
NULL) {
1852 NEditFree(is.lmName);
1853 return siParseError(inString, inPtr,
1854 "no end boundary to initialization macro");
1855 }
1856
1857
1858 is.newlineMacro = readSIMacro(&inPtr);
1859 if (is.newlineMacro ==
NULL) {
1860 NEditFree(is.lmName);
1861 NEditFree(is.initMacro);
1862 return siParseError(inString, inPtr,
1863 "no end boundary to newline macro");
1864 }
1865
1866
1867 is.modMacro = readSIMacro(&inPtr);
1868 if (is.modMacro ==
NULL) {
1869 NEditFree(is.lmName);
1870 NEditFree(is.initMacro);
1871 NEditFree(is.newlineMacro);
1872 return siParseError(inString, inPtr,
1873 "no end boundary to modify macro");
1874 }
1875
1876
1877 if (is.modMacro[
0] ==
'\0') {
1878 NEditFree(is.modMacro);
1879 is.modMacro =
NULL;
1880 }
1881
1882
1883 isCopy = (smartIndentRec *)NEditMalloc(
sizeof(smartIndentRec));
1884 *isCopy = is;
1885 for (i=
0; i<NSmartIndentSpecs; i++) {
1886 if (!strcmp(SmartIndentSpecs[i]->lmName, is.lmName)) {
1887 freeIndentSpec(SmartIndentSpecs[i]);
1888 SmartIndentSpecs[i] = isCopy;
1889 break;
1890 }
1891 }
1892 if (i == NSmartIndentSpecs)
1893 SmartIndentSpecs[NSmartIndentSpecs++] = isCopy;
1894 }
1895 }
1896
1897 int LoadSmartIndentCommonString(
char *inString)
1898 {
1899 int shiftedLen;
1900 char *inPtr = inString;
1901
1902
1903 NEditFree(CommonMacros);
1904
1905
1906 inPtr += strspn(inPtr,
" \t\n");
1907
1908
1909
1910 if (!strncmp(inPtr,
"Default",
7)) {
1911 CommonMacros = NEditStrdup(DefaultCommonMacros);
1912 return True;
1913 }
1914
1915
1916 CommonMacros = ShiftText(inPtr,
SHIFT_LEFT, True,
8,
8, &shiftedLen);
1917 return True;
1918 }
1919
1920
1921
1922
1923
1924
1925
1926 static char *readSIMacro(
char **inPtr)
1927 {
1928 char *retStr, *macroStr, *macroEnd;
1929 int shiftedLen;
1930
1931
1932 if (**inPtr ==
'\n')
1933 (*inPtr)++;
1934
1935
1936 macroEnd = strstr(*inPtr, MacroEndBoundary);
1937 if (macroEnd ==
NULL)
1938 return NULL;
1939
1940
1941 macroStr = (
char*)NEditMalloc(macroEnd - *inPtr +
1);
1942 strncpy(macroStr, *inPtr, macroEnd - *inPtr);
1943 macroStr[macroEnd - *inPtr] =
'\0';
1944
1945
1946 *inPtr = macroEnd + strlen(MacroEndBoundary);
1947 retStr = ShiftText(macroStr,
SHIFT_LEFT, True,
8,
8, &shiftedLen);
1948 NEditFree(macroStr);
1949 return retStr;
1950 }
1951
1952 static smartIndentRec *copyIndentSpec(smartIndentRec *is)
1953 {
1954 smartIndentRec *ris = (smartIndentRec *)NEditMalloc(
sizeof(smartIndentRec));
1955 ris->lmName = NEditStrdup(is->lmName);
1956 ris->initMacro = NEditStrdup(is->initMacro);
1957 ris->newlineMacro = NEditStrdup(is->newlineMacro);
1958 ris->modMacro = NEditStrdup(is->modMacro);
1959 return ris;
1960 }
1961
1962 static void freeIndentSpec(smartIndentRec *is)
1963 {
1964 NEditFree(is->lmName);
1965 NEditFree(is->initMacro);
1966 NEditFree(is->newlineMacro);
1967 NEditFree(is->modMacro);
1968 }
1969
1970 static int indentSpecsDiffer(smartIndentRec *is1, smartIndentRec *is2)
1971 {
1972 return AllocatedStringsDiffer(is1->initMacro, is2->initMacro) ||
1973 AllocatedStringsDiffer(is1->newlineMacro, is2->newlineMacro) ||
1974 AllocatedStringsDiffer(is1->modMacro, is2->modMacro);
1975 }
1976
1977 static int siParseError(
char *stringStart,
char *stoppedAt,
char *message)
1978 {
1979 return ParseError(
NULL, stringStart, stoppedAt,
1980 "smart indent specification", message);
1981 }
1982
1983 char *WriteSmartIndentString(
void)
1984 {
1985 int i;
1986 smartIndentRec *sis;
1987 textBuffer *outBuf;
1988 char *outStr, *escapedStr;
1989
1990 outBuf = BufCreate();
1991 for (i=
0; i<NSmartIndentSpecs; i++) {
1992 sis = SmartIndentSpecs[i];
1993 BufInsert(outBuf, outBuf->length,
"\t");
1994 BufInsert(outBuf, outBuf->length, sis->lmName);
1995 BufInsert(outBuf, outBuf->length,
":");
1996 if (isDefaultIndentSpec(sis))
1997 BufInsert(outBuf, outBuf->length,
"Default\n");
1998 else {
1999 insertShiftedMacro(outBuf, sis->initMacro);
2000 insertShiftedMacro(outBuf, sis->newlineMacro);
2001 insertShiftedMacro(outBuf, sis->modMacro);
2002 }
2003 }
2004
2005
2006 outStr = BufGetRange(outBuf,
0, outBuf->length >
0 ? outBuf->length-
1 :
0);
2007 BufFree(outBuf);
2008
2009
2010
2011 escapedStr = EscapeSensitiveChars(outStr);
2012 NEditFree(outStr);
2013 return escapedStr;
2014 }
2015
2016 char *WriteSmartIndentCommonString(
void)
2017 {
2018 int len;
2019 char *outStr, *escapedStr;
2020
2021 if (!strcmp(CommonMacros, DefaultCommonMacros))
2022 return NEditStrdup(
"Default");
2023 if (CommonMacros ==
NULL)
2024 return NEditStrdup(
"");
2025
2026
2027 outStr = ShiftText(CommonMacros,
SHIFT_RIGHT, True,
8,
8, &len);
2028
2029
2030
2031 escapedStr = EscapeSensitiveChars(outStr);
2032 NEditFree(outStr);
2033
2034
2035 len = strlen(escapedStr);
2036 if (len >
1 && escapedStr[len-
1] ==
'\n' && escapedStr[len-
2] ==
'\\')
2037 escapedStr[len-
2] =
'\0';
2038 return escapedStr;
2039 }
2040
2041
2042
2043
2044
2045
2046 static void insertShiftedMacro(textBuffer *buf,
char *macro)
2047 {
2048 char *shiftedMacro;
2049 int shiftedLen;
2050
2051 if (macro !=
NULL) {
2052 shiftedMacro = ShiftText(macro,
SHIFT_RIGHT, True,
8,
8, &shiftedLen);
2053 BufInsert(buf, buf->length, shiftedMacro);
2054 NEditFree(shiftedMacro);
2055 }
2056 BufInsert(buf, buf->length,
"\t");
2057 BufInsert(buf, buf->length, MacroEndBoundary);
2058 BufInsert(buf, buf->length,
"\n");
2059 }
2060
2061 static int isDefaultIndentSpec(smartIndentRec *indentSpec)
2062 {
2063 int i;
2064
2065 for (i=
0; i<
N_DEFAULT_INDENT_SPECS; i++)
2066 if (!strcmp(indentSpec->lmName, DefaultIndentSpecs[i].lmName))
2067 return !indentSpecsDiffer(indentSpec, &DefaultIndentSpecs[i]);
2068 return False;
2069 }
2070
2071 static smartIndentRec *findIndentSpec(
const char *modeName)
2072 {
2073 int i;
2074
2075 if (modeName ==
NULL)
2076 return NULL;
2077
2078 for (i=
0; i<NSmartIndentSpecs; i++)
2079 if (!strcmp(modeName, SmartIndentSpecs[i]->lmName))
2080 return SmartIndentSpecs[i];
2081 return NULL;
2082 }
2083
2084
2085
2086
2087
2088
2089
2090
2091 static char *ensureNewline(
char *string)
2092 {
2093 char *newString;
2094 int length;
2095
2096 if (string ==
NULL)
2097 return NULL;
2098 length = strlen(string);
2099 if (length ==
0 || string[length-
1] ==
'\n')
2100 return string;
2101 newString = (
char*)NEditMalloc(length +
2);
2102 strcpy(newString, string);
2103 newString[length] =
'\n';
2104 newString[length+
1] =
'\0';
2105 NEditFree(string);
2106 return newString;
2107 }
2108
2109
2110
2111
2112
2113 int LMHasSmartIndentMacros(
const char *languageMode)
2114 {
2115 if (findIndentSpec(languageMode) !=
NULL)
2116 return True;
2117 return SmartIndentDialog.shell!=
NULL && !strcmp(SmartIndentDialog.langModeName,
2118 languageMode);
2119 }
2120
2121
2122
2123
2124
2125
2126 void RenameSmartIndentMacros(
const char *oldName,
const char *newName)
2127 {
2128 int i;
2129
2130 for (i=
0; i<NSmartIndentSpecs; i++) {
2131 if (!strcmp(oldName, SmartIndentSpecs[i]->lmName)) {
2132 NEditFree(SmartIndentSpecs[i]->lmName);
2133 SmartIndentSpecs[i]->lmName = NEditStrdup(newName);
2134 }
2135 }
2136 if (SmartIndentDialog.shell !=
NULL) {
2137 if (!strcmp(SmartIndentDialog.langModeName, oldName)) {
2138 NEditFree(SmartIndentDialog.langModeName);
2139 SmartIndentDialog.langModeName = NEditStrdup(newName);
2140 }
2141 }
2142 }
2143
2144
2145
2146
2147
2148 void UpdateLangModeMenuSmartIndent(
void)
2149 {
2150 Widget oldMenu;
2151
2152 if (SmartIndentDialog.shell ==
NULL)
2153 return;
2154
2155 oldMenu = SmartIndentDialog.lmPulldown;
2156 SmartIndentDialog.lmPulldown = CreateLanguageModeMenu(
2157 XtParent(XtParent(oldMenu)), langModeCB,
NULL);
2158 XtVaSetValues(XmOptionButtonGadget(SmartIndentDialog.lmOptMenu),
2159 XmNsubMenuId, SmartIndentDialog.lmPulldown,
NULL);
2160 SetLangModeMenu(SmartIndentDialog.lmOptMenu, SmartIndentDialog.langModeName);
2161
2162 XtDestroyWidget(oldMenu);
2163 }
2164