4 source/highlightData.c | 2
5 source/macro.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++-
7 4 files changed, 134 insertions(+), 3 deletions(-)
9 diff --quilt old/source/macro.c new/source/macro.c
10 --- old/source/macro.c
11 +++ new/source/macro.c
12 @@ -440,10 +440,13 @@ static int dictsaveMS(WindowInfo *window
13 static int dictappendMS(WindowInfo *window, DataValue *argList, int nArgs,
14 DataValue *result, char **errMsg);
15 static int dictiselementMS(WindowInfo *window, DataValue *argList, int nArgs,
16 DataValue *result, char **errMsg);
18 +static int defineMS(WindowInfo *window, DataValue *argList, int nArgs,
19 + DataValue *result, char **errMsg);
21 /* Built-in subroutines and variables for the macro language */
22 static const BuiltInSubrName MacroSubrs[] = {
23 { "length", lengthMS },
24 { "get_range", getRangeMS },
25 { "t_print", tPrintMS },
26 @@ -506,10 +509,11 @@ static const BuiltInSubrName MacroSubrs[
27 { "dict_insert", dictinsertMS },
28 { "dict_complete", dictcompleteMS },
29 { "dict_save", dictsaveMS },
30 { "dict_append", dictappendMS },
31 { "dict_is_element", dictiselementMS },
32 + { "define", defineMS },
33 { NULL, NULL } /* sentinel */
36 static const BuiltInSubrName SpecialVars[] = {
37 { "$cursor", cursorMV },
38 @@ -977,13 +981,28 @@ static int readCheckMacroString(Widget d
41 Stack* progStack = (Stack*) XtMalloc(sizeof(Stack));
42 progStack->top = NULL;
44 + regexp *defineRE = NULL;
46 + Boolean defineFound;
48 + /* compile the "define" regex, don't honor "define\nfunction_name" */
49 + defineRE = CompileRE("<define(?=\\s+(?!\\())", &defineMsg,
51 + /* should only fail if out of mem */
52 + if (NULL == defineRE)
57 + defineFound = ExecRE(defineRE, inPtr, NULL, False,
58 + '\0', '\0', NULL, NULL, NULL);
60 while (*inPtr != '\0') {
61 + Boolean haveDefine = False;
63 /* skip over white space and comments */
64 while (*inPtr==' ' || *inPtr=='\t' || *inPtr=='\n'|| *inPtr=='#') {
66 while (*inPtr != '\n' && *inPtr != '\0') inPtr++;
67 @@ -991,33 +1010,42 @@ static int readCheckMacroString(Widget d
73 + /* the current "define" location was parsed inside a ParseMacro() */
74 + if (defineFound && inPtr > defineRE->startp[0]) {
75 + defineFound = ExecRE(defineRE, inPtr, NULL, False,
76 + '\0', '\0', NULL, NULL, NULL);
79 /* look for define keyword, and compile and store defined routines */
80 - if (!strncmp(inPtr, "define", 6) && (inPtr[6]==' ' || inPtr[6]=='\t')) {
81 + if (defineFound && defineRE->startp[0] == inPtr) {
83 inPtr += strspn(inPtr, " \t\n");
85 while ((namePtr < &subrName[MAX_SYM_LEN - 1])
86 && (isalnum((unsigned char)*inPtr) || *inPtr == '_')) {
87 *namePtr++ = *inPtr++;
90 if (isalnum((unsigned char)*inPtr) || *inPtr == '_') {
92 return ParseError(dialogParent, string, inPtr, errIn,
93 "subroutine name too long");
95 inPtr += strspn(inPtr, " \t\n");
97 if (errPos != NULL) *errPos = stoppedAt;
99 return ParseError(dialogParent, string, inPtr,
100 errIn, "expected '{'");
102 prog = ParseMacro(inPtr, &errMsg, &stoppedAt, subrName);
104 if (errPos != NULL) *errPos = stoppedAt;
106 return ParseError(dialogParent, string, stoppedAt,
109 if (runWindow != NULL) {
110 sym = LookupSymbol(subrName);
111 @@ -1033,10 +1061,14 @@ static int readCheckMacroString(Widget d
112 sym->value.val.prog = prog;
117 + /* search for the next "define" */
118 + defineFound = ExecRE(defineRE, inPtr, NULL, False,
119 + '\0', '\0', NULL, NULL, NULL);
121 /* Parse and execute immediate (outside of any define) macro commands
122 and WAIT for them to finish executing before proceeding. Note that
123 the code below is not perfect. If you interleave code blocks with
124 definitions in a file which is loaded from another macro file, it
125 will probably run the code blocks in reverse order! */
126 @@ -1045,10 +1077,11 @@ static int readCheckMacroString(Widget d
128 if (errPos != NULL) {
133 return ParseError(dialogParent, string, stoppedAt,
137 if (runWindow != NULL) {
138 @@ -1084,10 +1117,12 @@ static int readCheckMacroString(Widget d
141 /* This stack is empty, so just free it without checking the members. */
142 XtFree((char*) progStack);
150 ** Run a pre-compiled macro, changing the interface state to reflect that
151 @@ -3690,10 +3725,101 @@ static int callMS(WindowInfo *window, Da
154 return OverlayRoutineFromSymbol(sym, nArgs, 1);
158 + * define(func_name, func_body[, "override"])
160 +static int defineMS(WindowInfo *window, DataValue *argList, int nArgs,
161 + DataValue *result, char **errMsg)
163 + char stringStorage[3][TYPE_INT_STR_SIZE(int)];
166 + char *bodysave = NULL;
167 + char *stoppedAt = NULL;
169 + char *override = NULL;
174 + if (nArgs < 2 || nArgs > 3) {
175 + return wrongNArgsErr(errMsg);
177 + if (!readStringArg(argList[0], &name, stringStorage[0], errMsg)) {
180 + if (!readStringArg(argList[1], &body, stringStorage[1], errMsg)) {
184 + if (!readStringArg(argList[2], &override, stringStorage[2], errMsg)) {
187 + if (strcmp(override, "override")) {
188 + *errMsg = "Unknown parameter for subroutine %s";
193 + /* check function name */
194 + if (strlen(name) >= MAX_SYM_LEN) {
195 + *errMsg = "subroutine name too long";
199 + while (isalnum((unsigned char)*namePtr) || *namePtr == '_')
202 + *errMsg = "subroutine name is not a valid identifier";
206 + /* add a terminating newline (which command line users are likely to
207 + omit since they are typically invoking a single routine) */
208 + bodysave = XtMalloc(strlen(body) + 2);
210 + *errMsg = "Internal error";
213 + strcpy(bodysave, body);
214 + strcat(bodysave, "\n");
216 + /* Parse the macro and report errors if it fails */
217 + prog = ParseMacro(bodysave, errMsg, &stoppedAt, name);
219 + ParseError(window->macroCmdData ? window->shell : NULL,
220 + bodysave, stoppedAt, name, *errMsg);
226 + sym = LookupSymbol(name);
229 + *errMsg = "Try to override existing function.";
232 + if (sym->type != MACRO_FUNCTION_SYM) {
233 + *errMsg = "Try to override a non macro function.";
236 + FreeProgram(sym->value.val.prog);
237 + sym->value.val.prog = prog;
240 + subrPtr.val.prog = prog;
241 + subrPtr.tag = NO_TAG;
242 + sym = InstallSymbol(name, MACRO_FUNCTION_SYM, subrPtr);
249 static int listDialogMS(WindowInfo *window, DataValue *argList, int nArgs,
250 DataValue *result, char **errMsg)
252 macroCmdInfo *cmdData;
253 diff --quilt old/source/highlightData.c new/source/highlightData.c
254 --- old/source/highlightData.c
255 +++ new/source/highlightData.c
256 @@ -549,11 +549,11 @@ static char *DefaultPatternSets[] = {
257 README:\"NEdit Macro syntax highlighting patterns, version 2.6, maintainer Thorsten Haude, nedit at thorstenhau.de\":::Flag::D\n\
258 Comment:\"#\":\"$\"::Comment::\n\
259 Built-in Misc Vars:\"(?<!\\Y)\\$(?:active_pane|args|calltip_ID|column|cursor|display_width|empty_array|file_name|file_path|language_mode|line|locked|max_font_width|min_font_width|modified|n_display_lines|n_panes|rangeset_list|read_only|selection_(?:start|end|left|right)|server_name|text_length|top_line|transient|VERSION|NEDIT_HOME)>\":::Identifier::\n\
260 Built-in Pref Vars:\"(?<!\\Y)\\$(?:auto_indent|em_tab_dist|file_format|font_name|font_name_bold|font_name_bold_italic|font_name_italic|highlight_syntax|incremental_backup|incremental_search_line|make_backup_copy|match_syntax_based|overtype_mode|show_line_numbers|show_matching|statistics_line|tab_dist|use_tabs|wrap_margin|wrap_text)>\":::Identifier2::\n\
261 Built-in Special Vars:\"(?<!\\Y)\\$(?:[1-9]|list_dialog_button|n_args|read_status|search_end|shell_cmd_status|string_dialog_button|sub_sep)>\":::String1::\n\
262 - Built-in Subrs:\"<(?:append_file|beep|call|calltip|clipboard_to_string|dialog|filename_dialog|dict_(?:insert|complete|save|append|is_element)|focus_window|get_character|get_matching|get_pattern_(by_name|at_pos)|get_range|get_selection|get_style_(by_name|at_pos)|getenv|highlight_calltip_line|kill_calltip|length|list_dialog|max|min|rangeset_(?:add|create|destroy|get_by_name|includes|info|invert|range|set_color|set_mode|set_name|subtract)|read_file|replace_in_string|replace_range|replace_selection|replace_substring|search|search_string|select|select_rectangle|set_cursor_pos|set_transient|shell_command|split|string_compare|string_dialog|string_to_clipboard|substring|t_print|tolower|toupper|valid_number|write_file)(?=\\s*\\()\":::Subroutine::\n\
263 + Built-in Subrs:\"<(?:append_file|beep|call|calltip|clipboard_to_string|define|dialog|filename_dialog|dict_(?:insert|complete|save|append|is_element)|focus_window|get_character|get_matching|get_pattern_(by_name|at_pos)|get_range|get_selection|get_style_(by_name|at_pos)|getenv|highlight_calltip_line|kill_calltip|length|list_dialog|max|min|rangeset_(?:add|create|destroy|get_by_name|includes|info|invert|range|set_color|set_mode|set_name|subtract)|read_file|replace_in_string|replace_range|replace_selection|replace_substring|search|search_string|select|select_rectangle|set_cursor_pos|set_transient|shell_command|split|string_compare|string_dialog|string_to_clipboard|substring|t_print|tolower|toupper|valid_number|write_file)(?=\\s*\\()\":::Subroutine::\n\
264 Menu Actions:\"<(?:new(?:_tab|_opposite)?|open|open-dialog|open_dialog|open-selected|open_selected|close|save|save-as|save_as|save-as-dialog|save_as_dialog|revert-to-saved|revert_to_saved|revert_to_saved_dialog|include-file|include_file|include-file-dialog|include_file_dialog|load-macro-file|load_macro_file|load-macro-file-dialog|load_macro_file_dialog|load-tags-file|load_tags_file|load-tags-file-dialog|load_tags_file_dialog|unload_tags_file|load_tips_file|load_tips_file_dialog|unload_tips_file|print|print-selection|print_selection|exit|undo|redo|delete|select-all|select_all|shift-left|shift_left|shift-left-by-tab|shift_left_by_tab|shift-right|shift_right|shift-right-by-tab|shift_right_by_tab|find|find-dialog|find_dialog|find-again|find_again|find-selection|find_selection|find_incremental|start_incremental_find|replace|replace-dialog|replace_dialog|replace-all|replace_all|replace-in-selection|replace_in_selection|replace-again|replace_again|replace_find|replace_find_same|replace_find_again|goto-line-number|goto_line_number|goto-line-number-dialog|goto_line_number_dialog|goto-selected|goto_selected|mark|mark-dialog|mark_dialog|goto-mark|goto_mark|goto-mark-dialog|goto_mark_dialog|match|select_to_matching|goto_matching|find-definition|find_definition|show_tip|split-pane|split_pane|close-pane|close_pane|detach_document(?:_dialog)?|move_document_dialog|(?:next|previous|last)_document|uppercase|lowercase|fill-paragraph|fill_paragraph|control-code-dialog|control_code_dialog|filter-selection-dialog|filter_selection_dialog|filter-selection|filter_selection|execute-command|execute_command|execute-command-dialog|execute_command_dialog|execute-command-line|execute_command_line|shell-menu-command|shell_menu_command|macro-menu-command|macro_menu_command|bg_menu_command|post_window_bg_menu|post_tab_context_menu|beginning-of-selection|beginning_of_selection|end-of-selection|end_of_selection|repeat_macro|repeat_dialog|raise_window|focus_pane|set_statistics_line|set_incremental_search_line|set_show_line_numbers|set_auto_indent|set_wrap_text|set_wrap_margin|set_highlight_syntax|set_make_backup_copy|set_incremental_backup|set_show_matching|set_match_syntax_based|set_overtype_mode|set_locked|set_tab_dist|set_em_tab_dist|set_use_tabs|set_fonts|set_language_mode)(?=\\s*\\()\":::Subroutine::\n\
265 Text Actions:\"<(?:self-insert|self_insert|grab-focus|grab_focus|extend-adjust|extend_adjust|extend-start|extend_start|extend-end|extend_end|secondary-adjust|secondary_adjust|secondary-or-drag-adjust|secondary_or_drag_adjust|secondary-start|secondary_start|secondary-or-drag-start|secondary_or_drag_start|process-bdrag|process_bdrag|move-destination|move_destination|move-to|move_to|move-to-or-end-drag|move_to_or_end_drag|end_drag|copy-to|copy_to|copy-to-or-end-drag|copy_to_or_end_drag|exchange|process-cancel|process_cancel|paste-clipboard|paste_clipboard|copy-clipboard|copy_clipboard|cut-clipboard|cut_clipboard|copy-primary|copy_primary|cut-primary|cut_primary|newline|newline-and-indent|newline_and_indent|newline-no-indent|newline_no_indent|delete-selection|delete_selection|delete-previous-character|delete_previous_character|delete-next-character|delete_next_character|delete-previous-word|delete_previous_word|delete-next-word|delete_next_word|delete-to-start-of-line|delete_to_start_of_line|delete-to-end-of-line|delete_to_end_of_line|forward-character|forward_character|backward-character|backward_character|key-select|key_select|process-up|process_up|process-down|process_down|process-shift-up|process_shift_up|process-shift-down|process_shift_down|process-home|process_home|forward-word|forward_word|backward-word|backward_word|forward-paragraph|forward_paragraph|backward-paragraph|backward_paragraph|beginning-of-line|beginning_of_line|end-of-line|end_of_line|beginning-of-file|beginning_of_file|end-of-file|end_of_file|next-page|next_page|previous-page|previous_page|page-left|page_left|page-right|page_right|toggle-overstrike|toggle_overstrike|scroll-up|scroll_up|scroll-down|scroll_down|scroll_left|scroll_right|scroll-to-line|scroll_to_line|select-all|select_all|deselect-all|deselect_all|focusIn|focusOut|process-return|process_return|process-tab|process_tab|insert-string|insert_string|mouse_pan)(?=\\s*\\()\":::Subroutine::\n\
266 Macro Hooks:\"<(?:(?:pre|post)_(?:open|save)|cursor_moved|modified|(?:losing_)?focus)_hook(?=\\s*\\()\":::Subroutine1::\n\
267 Keyword:\"<(?:break|continue|define|delete|else|for|if|in|return|typeof|while)>\":::Keyword::\n\
268 Braces:\"[{}\\[\\]]\":::Keyword::\n\
269 diff --quilt old/doc/help.etx new/doc/help.etx
272 @@ -2688,10 +2688,15 @@ Macro Subroutines
274 **clipboard_to_string()**
275 Returns the contents of the clipboard as a macro string. Returns empty
278 +**define( name, body [, "override"] )**
279 + Defines a new function with name ~name~ and the macro code in ~body~.
280 + If the ~"override"~ option is given the new symbol overrides previously
283 **dialog( message, btn_1_label, btn_2_label, ... )**
284 Pop up a dialog for querying and presenting information to the user. First
285 argument is a string to show in the message area of the dialog.
286 Additional optional arguments represent labels for buttons to appear along
287 the bottom of the dialog. Returns the number of the button pressed (the
288 diff --quilt old/source/parse.y new/source/parse.y
289 --- old/source/parse.y
290 +++ new/source/parse.y
291 @@ -825,11 +825,11 @@ static int yylex(void)
292 if (!strcmp(symName, "continue")) return CONTINUE;
293 if (!strcmp(symName, "return")) return RETURN;
294 if (!strcmp(symName, "in")) return IN;
295 if (!strcmp(symName, "$args")) return ARG_LOOKUP;
296 if (!strcmp(symName, "delete") && follow_non_whitespace('(', SYMBOL, DELETE) == DELETE) return DELETE;
297 - if (!strcmp(symName, "define")) {
298 + if (!strcmp(symName, "define") && follow_non_whitespace('(', SYMBOL, 0) == 0) {
302 if (!strcmp(symName, "typeof")) return TYPEOF;
303 if (nextSymIsField) {