Program memory leaks
[nedit-bw.git] / macro_hooks.patch
blob2a391be6fc535b8b59065328b94c3893a4e13522
1 From: Thorsten Haude <yoo@vranx.de>
2 Subject: macro hooks
4 The following hooks are present:
6 * pre_open_hook
7 * post_open_hook
8 * pre_save_hook
9 * post_save_hook
10 * cursor_moved_hook
11 * modified_hook
12 * focus_hook
13 * losing_focus_hook
15 ---
17 doc/help.etx | 46 ++++++++++++++++++++++++++++++
18 source/Makefile.dependencies | 6 +--
19 source/file.c | 18 +++++++++++
20 source/highlightData.c | 1
21 source/macro.c | 63 ++++++++++++++++++++++++++++++++++++++++-
22 source/macro.h | 3 +
23 source/menu.c | 28 +++++++++++++++++-
24 source/nedit.c | 24 +++++----------
25 source/nedit.h | 1
26 source/selection.c | 65 ++++++++++++++++++++++++++++++++++---------
27 source/window.c | 28 ++++++++++++++++++
28 11 files changed, 247 insertions(+), 36 deletions(-)
30 diff --quilt old/doc/help.etx new/doc/help.etx
31 --- old/doc/help.etx
32 +++ new/doc/help.etx
33 @@ -3746,10 +3746,55 @@ Action Routines
35 **self_insert()**
36 To be attached to a key-press event, inserts the character
37 equivalent of the key pressed.
40 +Hooks
41 +-----
43 + Hooks are macro routines which are called at specific points in NEdit's
44 + execution. You can use hooks to tie in user-defined functionality at these
45 + points.
47 + No hooks are provided. To use a hook, simply define a macro function with
48 + the name of the hook. The next time the hook will catch, the macro function
49 + is called.
51 + You don't have to provide any hook. If a certain hook does not exist, it is
52 + simply skipped.
54 +**pre_open_hook(~filename~)**
55 + Called before NEdit opens a file using a certain name. The parameter is
56 + the filename NEdit intends to open.
58 + Return a string to use instead of the original filename. Return 0 to tell
59 + NEdit to use the original filename.
61 +**post_open_hook()**
62 + Called when an existing file is opened.
64 +**pre_save_hook()**
65 + Called before a file will be save saved.
67 + Return a string to use this as the file name.
69 +**post_save_hook()**
70 + Called after an file was saved.
72 +**cursor_moved_hook()**
73 + Called when the was cursor moved.
75 +**modified_hook()**
76 + Called when the text buffer changed.
78 +**focus_hook()**
79 + Called when a document gets the input focus.
81 +**losing_focus_hook()**
82 + Called before a document lost the input focus.
84 ----------------------------------------------------------------------
86 Customizing
87 ===========
89 @@ -6034,10 +6079,11 @@ Problems/Defects
90 .. Menu: Macro Language # macro_lang
91 .. Menu: M_a_cro Subroutines # macro_subrs
92 .. Menu: Rangesets # rangeset
93 .. Menu: Highlighting Information # hiliteInfo
94 .. Menu: Action Routines # actions
95 +.. Menu: H_o_oks # hooks
97 .. Menu: Customizing # customizing
98 .. Menu: Customizing NEdit # customize
99 .. Menu: Preferences # preferences
100 .. Menu: X Resources # resources
101 diff --quilt old/source/Makefile.dependencies new/source/Makefile.dependencies
102 --- old/source/Makefile.dependencies
103 +++ new/source/Makefile.dependencies
104 @@ -2,11 +2,11 @@
105 calltips.o: calltips.c text.h textBuf.h textP.h textDisp.h calltips.h \
106 nedit.h ../util/misc.h
107 file.o: file.c file.h nedit.h textBuf.h text.h window.h preferences.h \
108 undo.h menu.h tags.h server.h ../util/misc.h ../util/DialogF.h \
109 ../util/fileUtils.h ../util/getfiles.h ../util/printUtils.h \
110 - ../util/utils.h
111 + ../util/utils.h macro.h
112 help.o: help.c help.h help_topic.h textBuf.h text.h textP.h textDisp.h \
113 textSel.h nedit.h search.h window.h preferences.h help_data.h file.h \
114 highlight.h ../util/misc.h ../util/DialogF.h ../util/system.h
115 highlight.o: highlight.c highlight.h nedit.h textBuf.h textDisp.h text.h \
116 textP.h regularExp.h highlightData.h preferences.h window.h \
117 @@ -39,20 +39,20 @@ parse_noyacc.o: parse_noyacc.c parse.h i
118 preferences.o: preferences.c preferences.h nedit.h textBuf.h text.h \
119 search.h window.h userCmds.h highlight.h highlightData.h help.h \
120 help_topic.h regularExp.h smartIndent.h windowTitle.h server.h tags.h \
121 ../util/prefFile.h ../util/misc.h ../util/DialogF.h \
122 ../util/managedList.h ../util/fontsel.h ../util/fileUtils.h \
123 - ../util/utils.h ../util/clearcase.h
124 + ../util/utils.h ../util/clearcase.h macro.h
125 rangeset.o: rangeset.c textBuf.h textDisp.h rangeset.h
126 rbTree.o: rbTree.c rbTree.h
127 regexConvert.o: regexConvert.c regexConvert.h
128 regularExp.o: regularExp.c regularExp.h
129 search.o: search.c search.h nedit.h textBuf.h regularExp.h text.h \
130 server.h window.h preferences.h file.h highlight.h ../util/DialogF.h \
131 ../util/misc.h
132 selection.o: selection.c selection.h nedit.h textBuf.h text.h file.h \
133 - window.h menu.h server.h ../util/DialogF.h ../util/fileUtils.h
134 + window.h menu.h server.h ../util/DialogF.h ../util/fileUtils.h macro.h
135 server.o: server.c server.h window.h nedit.h textBuf.h file.h selection.h \
136 macro.h menu.h preferences.h server_common.h ../util/fileUtils.h \
137 ../util/utils.h
138 server_common.o: server_common.c textBuf.h nedit.h server_common.h \
139 ../util/utils.h
140 diff --quilt old/source/file.c new/source/file.c
141 --- old/source/file.c
142 +++ new/source/file.c
143 @@ -39,10 +39,11 @@ static const char CVSID[] = "$Id: file.c
144 #include "undo.h"
145 #include "menu.h"
146 #include "tags.h"
147 #include "server.h"
148 #include "interpret.h"
149 +#include "macro.h"
150 #include "../util/misc.h"
151 #include "../util/DialogF.h"
152 #include "../util/fileUtils.h"
153 #include "../util/getfiles.h"
154 #include "../util/printUtils.h"
155 @@ -270,10 +271,12 @@ WindowInfo *EditExistingFile(WindowInfo
156 strcat(fullname, name);
157 if(GetPrefAlwaysCheckRelTagsSpecs())
158 AddRelTagsFile(GetPrefTagFile(), path, TAG);
159 AddToPrevOpenMenu(fullname);
161 + MacroApplyHook(window, "post_open_hook", 0, NULL, NULL);
163 return window;
166 void RevertToSaved(WindowInfo *window)
168 @@ -930,10 +933,22 @@ static int doSave(WindowInfo *window)
169 char *fileString = NULL;
170 char fullname[MAXPATHLEN];
171 struct stat statbuf;
172 FILE *fp;
173 int fileLen, result;
174 + DataValue hookResult = {NO_TAG,{0}};
175 + Boolean success;
177 + /* call the "pre_save_hook", if the macro returns a string, interpret this
178 + as the new filename */
179 + success = MacroApplyHook(window, "pre_save_hook", 0, NULL, &hookResult);
180 + if (success && hookResult.tag == STRING_TAG) {
181 + if (ParseFilename(hookResult.val.str.rep,
182 + window->filename, window->path)) {
183 + return FALSE;
187 /* Get the full name of the file */
188 strcpy(fullname, window->path);
189 strcat(fullname, window->filename);
191 @@ -1067,10 +1082,13 @@ static int doSave(WindowInfo *window)
192 window->fileMissing = TRUE;
193 window->device = 0;
194 window->inode = 0;
197 + /* call "post_save_hook" */
198 + MacroApplyHook(window, "post_save_hook", 0, NULL, NULL);
200 return TRUE;
204 ** Create a backup file for the current window. The name for the backup file
205 diff --quilt old/source/highlightData.c new/source/highlightData.c
206 --- old/source/highlightData.c
207 +++ new/source/highlightData.c
208 @@ -552,10 +552,11 @@ static char *DefaultPatternSets[] = {
209 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\
210 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\
211 Built-in Subrs:\"<(?:append_file|beep|call|calltip|clipboard_to_string|dialog|filename_dialog|focus_window|get_character|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|shell_command|split|string_compare|string_dialog|string_to_clipboard|substring|t_print|tolower|toupper|valid_number|write_file)(?=\\s*\\()\":::Subroutine::\n\
212 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\
213 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\
214 + Macro Hooks:\"<(?:(?:pre|post)_(?:open|save)|cursor_moved|modified|(?:losing_)?focus)_hook(?=\\s*\\()\":::Subroutine1::\n\
215 Keyword:\"<(?:break|continue|define|delete|else|for|if|in|return|while)>\":::Keyword::\n\
216 Braces:\"[{}\\[\\]]\":::Keyword::\n\
217 Global Variable:\"\\$[A-Za-z0-9_]+\":::Identifier1::\n\
218 String sq:\"'\":\"'\"::String::\n\
219 String:\"\"\"\":\"\"\"\":\"\\n\":String::\n\
220 diff --quilt old/source/macro.c new/source/macro.c
221 --- old/source/macro.c
222 +++ new/source/macro.c
223 @@ -1209,12 +1209,14 @@ static void finishMacroCmdExecution(Wind
224 void SafeGC(void)
226 WindowInfo *win;
228 for (win=WindowList; win!=NULL; win=win->next)
229 - if (win->macroCmdData != NULL || InSmartIndentMacros(win))
230 - return;
231 + if (win->macroCmdData != NULL
232 + || InSmartIndentMacros(win)
233 + || win->inMacroHook)
234 + return;
235 GarbageCollectStrings();
239 ** Executes macro string "macro" using the lastFocus pane in "window".
240 @@ -5947,5 +5949,62 @@ static int readStringArg(DataValue dv, c
241 return True;
243 *errMsg = "%s called with unknown object";
244 return False;
248 +** call a macro function, if it exists, with the given arguments and store
249 +** the return value in resultDV.
251 +** Currently, only non-preemtable macros are supported.
253 +Boolean MacroApplyHook(WindowInfo *document, const char *hook, int argc,
254 + DataValue *argv, DataValue *resultDV)
256 + Symbol *hookSymbol;
257 + Boolean succ = False;
259 + hookSymbol = LookupSymbol(hook);
260 + if (NULL != hookSymbol && MACRO_FUNCTION_SYM == hookSymbol->type) {
261 + Program *hookProg = hookSymbol->value.val.prog;
262 + RestartData *restartData;
263 + DataValue dummyResultDV;
264 + DataValue *resultDVPtr = &dummyResultDV;
265 + int status;
266 + char *errMsg;
268 + /* ExecuteMacro() can't be called with a NULL resultDV, therefore the
269 + dummyResultDV */
270 + if (resultDV) {
271 + resultDVPtr = resultDV;
274 + /* prevent calling the GC */
275 + document->inMacroHook++;
277 + status = ExecuteMacro(document, hookProg, argc, argv,
278 + resultDVPtr, &restartData, &errMsg);
280 + while (MACRO_TIME_LIMIT == status) {
281 + status = ContinueMacro(restartData, resultDVPtr, &errMsg);
284 + document->inMacroHook--;
286 + /* call the GC only if the caller of this function is not interested
287 + in any result, else it may happen, that strings and arrays are swept
288 + away by the GC. */
289 + if (NULL == resultDV) {
290 + SafeGC();
293 + if (MACRO_PREEMPT == status || MACRO_ERROR == status) {
294 + fprintf(stderr, "nedit: \"%s\" error: %s\n", hook, (MACRO_ERROR == status) ? errMsg : "No dialogs");
295 + } else {
296 + /* Macro is done here without errors */
297 + succ = True;
301 + return succ;
303 diff --quilt old/source/macro.h new/source/macro.h
304 --- old/source/macro.h
305 +++ new/source/macro.h
306 @@ -71,7 +71,10 @@ int ReadMacroString(WindowInfo *window,
307 int CheckMacroString(Widget dialogParent, char *string, const char *errIn,
308 char **errPos);
309 char *GetReplayMacro(void);
310 void ReadMacroInitFile(WindowInfo *window);
311 void ReturnShellCommandOutput(WindowInfo *window, const char *outText, int status);
312 +struct DataValueTag;
313 +Boolean MacroApplyHook(WindowInfo *document, const char *hook, int argc,
314 + struct DataValueTag *argv, struct DataValueTag *resultDV);
316 #endif /* NEDIT_MACRO_H_INCLUDED */
317 diff --quilt old/source/menu.c new/source/menu.c
318 --- old/source/menu.c
319 +++ new/source/menu.c
320 @@ -2847,23 +2847,47 @@ static void openDialogAP(Widget w, XEven
322 static void openAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
324 WindowInfo *window = WidgetToWindow(w);
325 char filename[MAXPATHLEN], pathname[MAXPATHLEN];
326 + DataValue fileNameArg;
327 + DataValue resultDV = {NO_TAG, {0}};
328 + Boolean hook_successful = False;
329 + char *fileNameToOpen;
331 if (*nArgs == 0) {
332 fprintf(stderr, "nedit: open action requires file argument\n");
333 return;
335 - if (0 != ParseFilename(args[0], filename, pathname)
337 + /* call "pre_open_hook", use the returned string as the filename to open.
338 + The macro is not executed in the new window. */
339 + fileNameArg.tag = STRING_TAG;
340 + AllocNStringNCpy(&fileNameArg.val.str, args[0], MAXPATHLEN);
341 + hook_successful = MacroApplyHook(window, "pre_open_hook",
342 + 1, &fileNameArg, &resultDV);
344 + if (hook_successful && resultDV.tag == STRING_TAG) {
345 + fileNameToOpen = resultDV.val.str.rep;
346 + } else {
347 + fileNameToOpen = args[0];
350 + if (0 != ParseFilename(fileNameToOpen, filename, pathname)
351 || strlen(filename) + strlen(pathname) > MAXPATHLEN - 1) {
352 fprintf(stderr, "nedit: invalid file name for open action: %s\n",
353 - args[0]);
354 + fileNameToOpen);
355 return;
358 + /* we call the GC, because the "pre_open_hook" argument and possible
359 + return value are strings */
360 + SafeGC();
362 EditExistingFile(window, filename, pathname, 0, NULL, False,
363 NULL, GetPrefOpenInTab(), False);
365 CheckCloseDim();
368 static void openSelectedAP(Widget w, XEvent *event, String *args,
369 Cardinal *nArgs)
370 diff --quilt old/source/nedit.c new/source/nedit.c
371 --- old/source/nedit.c
372 +++ new/source/nedit.c
373 @@ -386,11 +386,11 @@ static const char cmdLineHelp[] =
374 #endif /*VMS*/
376 int main(int argc, char **argv)
378 int i, lineNum, nRead, fileSpecified = FALSE, editFlags = CREATE;
379 - int gotoLine = False, macroFileRead = False, opts = True;
380 + int gotoLine = False, opts = True;
381 int iconic=False, tabbed = -1, group = 0, isTabbed;
382 char *toDoCommand = NULL, *geometry = NULL, *langMode = NULL;
383 char filename[MAXPATHLEN], pathname[MAXPATHLEN];
384 XtAppContext context;
385 XrmDatabase prefDB;
386 @@ -565,10 +565,14 @@ int main(int argc, char **argv)
388 if (strcmp(GetPrefServerName(), "") != 0) {
389 IsServer = True;
392 + EditNewFile(NULL, geometry, iconic, langMode, NULL);
393 + ReadMacroInitFile(WindowList);
394 + CheckCloseDim();
396 /* Process any command line arguments (-tags, -do, -read, -create,
397 +<line_number>, -line, -server, and files to edit) not already
398 processed by RestoreNEditPrefs. */
399 fileSpecified = FALSE;
400 for (i=1; i<argc; i++) {
401 @@ -680,14 +684,10 @@ int main(int argc, char **argv)
402 if (lastFile && window->shell != lastFile->shell) {
403 CleanUpTabBarExposeQueue(lastFile);
404 RaiseDocument(lastFile);
407 - if (!macroFileRead) {
408 - ReadMacroInitFile(WindowList);
409 - macroFileRead = True;
411 if (gotoLine)
412 SelectNumberedLine(window, lineNum);
413 if (toDoCommand != NULL) {
414 DoMacro(window, toDoCommand, "-do macro");
415 toDoCommand = NULL;
416 @@ -737,14 +737,10 @@ int main(int argc, char **argv)
417 if (lastFile && window->shell != lastFile->shell) {
418 CleanUpTabBarExposeQueue(lastFile);
419 RaiseDocument(lastFile);
422 - if (!macroFileRead) {
423 - ReadMacroInitFile(WindowList);
424 - macroFileRead = True;
426 if (gotoLine)
427 SelectNumberedLine(window, lineNum);
428 if (toDoCommand != NULL) {
429 DoMacro(window, toDoCommand, "-do macro");
430 toDoCommand = NULL;
431 @@ -773,17 +769,13 @@ int main(int argc, char **argv)
432 CleanUpTabBarExposeQueue(lastFile);
433 RaiseDocument(lastFile);
435 CheckCloseDim();
437 - /* If no file to edit was specified, open a window to edit "Untitled" */
438 - if (!fileSpecified) {
439 - EditNewFile(NULL, geometry, iconic, langMode, NULL);
440 - ReadMacroInitFile(WindowList);
441 - CheckCloseDim();
442 - if (toDoCommand != NULL)
443 - DoMacro(WindowList, toDoCommand, "-do macro");
444 + /* If no file to edit was specified, do at least the -do macro */
445 + if (!fileSpecified && toDoCommand != NULL) {
446 + DoMacro(WindowList, toDoCommand, "-do macro");
449 /* Begin remembering last command invoked for "Repeat" menu item */
450 AddLastCommandActionHook(context);
452 diff --quilt old/source/nedit.h new/source/nedit.h
453 --- old/source/nedit.h
454 +++ new/source/nedit.h
455 @@ -564,10 +564,11 @@ typedef struct _WindowInfo {
456 #endif
457 UserMenuCache *userMenuCache; /* cache user menus: */
458 UserBGMenuCache userBGMenuCache; /* shell & macro menu are shared over all
459 "tabbed" documents, while each document
460 has its own background menu. */
461 + int inMacroHook; /* to protect GC in MacroApplyHook() */
462 } WindowInfo;
464 extern WindowInfo *WindowList;
465 extern Display *TheDisplay;
466 extern Widget TheAppShell;
467 diff --quilt old/source/selection.c new/source/selection.c
468 --- old/source/selection.c
469 +++ new/source/selection.c
470 @@ -36,10 +36,12 @@ static const char CVSID[] = "$Id: select
471 #include "file.h"
472 #include "window.h"
473 #include "menu.h"
474 #include "preferences.h"
475 #include "server.h"
476 +#include "interpret.h"
477 +#include "macro.h"
478 #include "../util/DialogF.h"
479 #include "../util/fileUtils.h"
481 #include <stdlib.h>
482 #include <stdio.h>
483 @@ -336,18 +338,36 @@ static void fileCB(Widget widget, Window
484 return;
486 _XmOSGetDirEntries(pathname, filename, XmFILE_ANY_TYPE, False, True,
487 &nameList, &nFiles, &maxFiles);
488 for (i=0; i<nFiles; i++) {
489 - if (ParseFilename(nameList[i], filename, pathname) != 0) {
490 - XBell(TheDisplay, 0);
492 - else {
493 - EditExistingFile(window, filename, pathname, 0,
494 - NULL, False, NULL, GetPrefOpenInTab(), False);
496 + DataValue fileNameArg;
497 + DataValue resultDV = {NO_TAG, {0}};
498 + Boolean hook_successful = False;
499 + char *fileNameToOpen;
501 + fileNameArg.tag = STRING_TAG;
502 + AllocNStringNCpy(&fileNameArg.val.str, nameList[i],
503 + MAXPATHLEN);
504 + hook_successful = MacroApplyHook(window, "pre_open_hook",
505 + 1, &fileNameArg, &resultDV);
507 + if (hook_successful && resultDV.tag == STRING_TAG) {
508 + fileNameToOpen = resultDV.val.str.rep;
509 + } else {
510 + fileNameToOpen = nameList[i];
513 + if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
514 + XBell(TheDisplay, 0);
515 + } else {
516 + EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
517 + pathname, 0, NULL, False, NULL, GetPrefOpenInTab(),
518 + False);
521 + SafeGC();
522 for (i=0; i<nFiles; i++) {
523 XtFree(nameList[i]);
525 XtFree((char *)nameList);
527 @@ -355,17 +375,36 @@ static void fileCB(Widget widget, Window
528 { glob_t globbuf;
529 int i;
531 glob(nameText, GLOB_NOCHECK, NULL, &globbuf);
532 for (i=0; i<(int)globbuf.gl_pathc; i++) {
533 - if (ParseFilename(globbuf.gl_pathv[i], filename, pathname) != 0)
534 - XBell(TheDisplay, 0);
535 - else
536 - EditExistingFile(GetPrefOpenInTab()? window : NULL,
537 - filename, pathname, 0, NULL, False, NULL,
538 - GetPrefOpenInTab(), False);
539 + DataValue fileNameArg;
540 + DataValue resultDV = {NO_TAG, {0}};
541 + Boolean hook_successful = False;
542 + char *fileNameToOpen;
544 + fileNameArg.tag = STRING_TAG;
545 + AllocNStringNCpy(&fileNameArg.val.str, globbuf.gl_pathv[i],
546 + MAXPATHLEN);
547 + hook_successful = MacroApplyHook(window, "pre_open_hook",
548 + 1, &fileNameArg, &resultDV);
550 + if (hook_successful && resultDV.tag == STRING_TAG) {
551 + fileNameToOpen = resultDV.val.str.rep;
552 + } else {
553 + fileNameToOpen = globbuf.gl_pathv[i];
556 + if (ParseFilename(fileNameToOpen, filename, pathname) != 0) {
557 + XBell(TheDisplay, 0);
558 + } else {
559 + EditExistingFile(GetPrefOpenInTab() ? window : NULL, filename,
560 + pathname, 0, NULL, False, NULL, GetPrefOpenInTab(),
561 + False);
564 + SafeGC();
565 globfree(&globbuf);
567 #endif
568 CheckCloseDim();
570 diff --quilt old/source/window.c new/source/window.c
571 --- old/source/window.c
572 +++ new/source/window.c
573 @@ -167,10 +167,11 @@ static void showStats(WindowInfo *window
574 static void showISearch(WindowInfo *window, int state);
575 static void showStatsForm(WindowInfo *window);
576 static void addToWindowList(WindowInfo *window);
577 static void removeFromWindowList(WindowInfo *window);
578 static void focusCB(Widget w, WindowInfo *window, XtPointer callData);
579 +static void losingFocusCB(Widget w, WindowInfo *window, XtPointer callData);
580 static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled,
581 const char *deletedText, void *cbArg);
582 static void movedCB(Widget w, WindowInfo *window, XtPointer callData);
583 static void dragStartCB(Widget w, WindowInfo *window, XtPointer callData);
584 static void dragEndCB(Widget w, WindowInfo *window, dragEndCBStruct *callData);
585 @@ -323,10 +324,11 @@ WindowInfo *CreateWindow(const char *nam
586 window->findLastRegexCase = TRUE;
587 window->findLastLiteralCase = FALSE;
588 window->tab = NULL;
589 window->device = 0;
590 window->inode = 0;
591 + window->inMacroHook = 0;
593 /* If window geometry was specified, split it apart into a window position
594 component and a window size component. Create a new geometry string
595 containing the position component only. Rows and cols are stripped off
596 because we can't easily calculate the size in pixels from them until the
597 @@ -1030,10 +1032,14 @@ void CloseWindow(WindowInfo *window)
598 RefreshTabState(window);
599 updateLineNumDisp(window);
600 return;
603 + if (window->inMacroHook) {
604 + fprintf(stderr, "nedit: warning closing window while in MacroHook\n");
607 /* Free syntax highlighting patterns, if any. w/o redisplaying */
608 FreeHighlightingData(window);
610 /* remove the buffer modification callbacks so the buffer will be
611 deallocated when the last text widget is destroyed */
612 @@ -2322,10 +2328,12 @@ static Widget createTextArea(Widget pare
613 XtVaSetValues(sw, XmNworkWindow, frame, XmNhorizontalScrollBar,
614 hScrollBar, XmNverticalScrollBar, vScrollBar, NULL);
616 /* add focus, drag, cursor tracking, and smart indent callbacks */
617 XtAddCallback(text, textNfocusCallback, (XtCallbackProc)focusCB, window);
618 + XtAddCallback(text, textNlosingFocusCallback,
619 + (XtCallbackProc)losingFocusCB, window);
620 XtAddCallback(text, textNcursorMovementCallback, (XtCallbackProc)movedCB,
621 window);
622 XtAddCallback(text, textNdragStartCallback, (XtCallbackProc)dragStartCB,
623 window);
624 XtAddCallback(text, textNdragEndCallback, (XtCallbackProc)dragEndCB,
625 @@ -2374,10 +2382,14 @@ static void movedCB(Widget w, WindowInfo
626 if (0 != textWidget->text.cursorBlinkProcID)
628 /* Start blinking the caret again. */
629 ResetCursorBlink(textWidget, False);
632 + /* thats a hight frequency hook, should never force a preemptable
633 + context */
634 + MacroApplyHook(window, "cursor_moved_hook", 0, NULL, NULL);
637 static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled,
638 const char *deletedText, void *cbArg)
640 @@ -2445,10 +2457,14 @@ static void modifiedCB(int pos, int nIns
641 /* Update # of bytes, and line and col statistics */
642 UpdateStatsLine(window);
644 /* Check if external changes have been made to file and warn user */
645 CheckForChangesToFile(window);
647 + /* thats a hight frequency hook, should never force a preemptable
648 + context */
649 + MacroApplyHook(window, "modified_hook", 0, NULL, NULL);
652 static void focusCB(Widget w, WindowInfo *window, XtPointer callData)
654 /* record which window pane last had the keyboard focus */
655 @@ -2460,10 +2476,21 @@ static void focusCB(Widget w, WindowInfo
656 /* finish off the current incremental search */
657 EndISearch(window);
659 /* Check for changes to read-only status and/or file modifications */
660 CheckForChangesToFile(window);
662 + /* thats a hight frequency hook, should never force a preemptable
663 + context */
664 + MacroApplyHook(window, "focus_hook", 0, NULL, NULL);
667 +static void losingFocusCB(Widget w, WindowInfo *window, XtPointer callData)
669 + /* thats a hight frequency hook, should never force a preemptable
670 + context */
671 + MacroApplyHook(window, "losing_focus_hook", 0, NULL, NULL);
674 static void dragStartCB(Widget w, WindowInfo *window, XtPointer callData)
676 /* don't record all of the intermediate drag steps for undo */
677 @@ -3467,10 +3494,11 @@ WindowInfo* CreateDocument(WindowInfo* s
678 window->tab = NULL;
679 window->bgMenuUndoItem = NULL;
680 window->bgMenuRedoItem = NULL;
681 window->device = 0;
682 window->inode = 0;
683 + window->inMacroHook = 0;
685 if (window->fontList == NULL)
686 XtVaGetValues(shellWindow->statsLine, XmNfontList,
687 &window->fontList,NULL);