re-fresh
[nedit-bw.git] / macro_hooks.patch
blob56e72232fc2c38314bd1f92fbe30ed9fb88c5e43
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
14 * language_mode_hook
16 ---
18 doc/help.etx | 46 ++++++++++++++++++++++++++++++
19 source/Makefile.dependencies | 6 +--
20 source/file.c | 18 +++++++++++
21 source/highlightData.c | 1
22 source/macro.c | 65 +++++++++++++++++++++++++++++++++++++++++--
23 source/macro.h | 3 +
24 source/menu.c | 28 +++++++++++++++++-
25 source/nedit.c | 24 +++++----------
26 source/nedit.h | 1
27 doc/help.etx | 50 ++++++++++++++++
28 source/Makefile.common | 1
29 source/Makefile.dependencies | 2
30 source/file.c | 22 ++++++-
31 source/highlightData.c | 1
32 source/hooks.c | 133 +++++++++++++++++++++++++++++++++++++++++++
33 source/hooks.h | 15 ++++
34 source/macro.c | 65 ++++++++++++++++++++-
35 source/macro.h | 3
36 source/menu.c | 9 +-
37 source/nedit.c | 31 ++++------
38 source/nedit.h | 1
39 source/preferences.c | 3
40 source/selection.c | 11 ++-
41 source/server.c | 63 ++++++++++----------
42 source/window.c | 22 +++++++
43 16 files changed, 373 insertions(+), 59 deletions(-)
45 diff --quilt old/doc/help.etx new/doc/help.etx
46 --- old/doc/help.etx
47 +++ new/doc/help.etx
48 @@ -3748,6 +3748,55 @@ Action Routines
49 To be attached to a key-press event, inserts the character
50 equivalent of the key pressed.
53 +Hooks
54 +-----
56 + Hooks are macro routines which are called at specific points in NEdit's
57 + execution. You can use hooks to tie in user-defined functionality at these
58 + points.
60 + No hooks are provided. To use a hook, simply define a macro function with
61 + the name of the hook. The next time the hook will catch, the macro function
62 + is called.
64 + You don't have to provide any hook. If a certain hook does not exist, it is
65 + simply skipped.
67 +**pre_open_hook(~filename~)**
68 + Called before NEdit opens a file using a certain name. The parameter is
69 + the filename NEdit intends to open.
71 + Return a string to use instead of the original filename. Return 0 to tell
72 + NEdit to use the original filename.
74 +**post_open_hook()**
75 + Called when an existing file is opened.
77 +**pre_save_hook()**
78 + Called before a file will be save saved.
80 + Return a string to use this as the file name.
82 +**post_save_hook()**
83 + Called after an file was saved.
85 +**language_mode_hook(~previous_mode~)**
86 + Called after a new language mode was applied with the previous mode as the
87 + first argument.
89 +**cursor_moved_hook()**
90 + Called when the was cursor moved.
92 +**modified_hook()**
93 + Called when the text buffer changed.
95 +**focus_hook()**
96 + Called when a document gets the input focus.
98 +**losing_focus_hook()**
99 + Called before a document lost the input focus.
101 ----------------------------------------------------------------------
103 Customizing
104 @@ -6036,6 +6085,7 @@ Problems/Defects
105 .. Menu: Rangesets # rangeset
106 .. Menu: Highlighting Information # hiliteInfo
107 .. Menu: Action Routines # actions
108 +.. Menu: H_o_oks # hooks
110 .. Menu: Customizing # customizing
111 .. Menu: Customizing NEdit # customize
112 diff --quilt old/source/Makefile.dependencies new/source/Makefile.dependencies
113 --- old/source/Makefile.dependencies
114 +++ new/source/Makefile.dependencies
115 @@ -85,3 +85,5 @@ windowTitle.o: windowTitle.c windowTitle
116 ../util/DialogF.h ../util/utils.h ../util/fileUtils.h \
117 ../util/clearcase.h
118 parse.c: parse.h textBuf.h nedit.h rbTree.h interpret.h ops.h
119 +server.o file.o preferences.o selection.o window.o: hooks.h
120 +hooks.o: hooks.c hooks.h macro.h
121 diff --quilt old/source/file.c new/source/file.c
122 --- old/source/file.c
123 +++ new/source/file.c
124 @@ -41,6 +41,7 @@ static const char CVSID[] = "$Id: file.c
125 #include "tags.h"
126 #include "server.h"
127 #include "interpret.h"
128 +#include "hooks.h"
129 #include "../util/misc.h"
130 #include "../util/DialogF.h"
131 #include "../util/fileUtils.h"
132 @@ -207,7 +208,7 @@ WindowInfo *EditExistingFile(WindowInfo
133 else
134 RaiseDocumentWindow(window);
136 - return window;
137 + goto out;
140 /* If an existing window isn't specified; or the window is already
141 @@ -272,6 +273,9 @@ WindowInfo *EditExistingFile(WindowInfo
142 AddRelTagsFile(GetPrefTagFile(), path, TAG);
143 AddToPrevOpenMenu(fullname);
145 +out:
146 + PostOpenHook(window);
148 return window;
151 @@ -934,6 +938,19 @@ static int doSave(WindowInfo *window)
152 int fileLen, result;
153 int ret;
155 + /* call pre_save_hook, and set result as path/name */
156 + fileString = PreSaveHook(window);
157 + if (fileString &&
158 + ParseFilename(fileString, window->filename, window->path)) {
159 + result = DialogF(DF_ERR, window->shell, 2, "Invalid Filename",
160 + "The filename provided by the post_save_hook\n"
161 + "('%s')\n"
162 + "is not a valid filename.",
163 + "Cancel", "Keep Current", fileString);
164 + if (result == 1)
165 + return FALSE;
168 /* Get the full name of the file */
169 strcpy(fullname, window->path);
170 strcat(fullname, window->filename);
171 @@ -1085,6 +1102,9 @@ static int doSave(WindowInfo *window)
172 window->inode = 0;
175 + /* call "post_save_hook" */
176 + PostSaveHook(window);
178 return TRUE;
181 diff --quilt old/source/highlightData.c new/source/highlightData.c
182 --- old/source/highlightData.c
183 +++ new/source/highlightData.c
184 @@ -554,6 +554,7 @@ static char *DefaultPatternSets[] = {
185 Built-in Subrs:\"<(?:args|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|n_args|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\
186 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\
187 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\
188 + Macro Hooks:\"<(?:(?:pre|post)_(?:open|save)|cursor_moved|modified|(?:losing_)?focus|language_mode)_hook(?=\\s*\\()\":::Subroutine1::\n\
189 Keyword:\"<(?:break|continue|define|delete|do|else|for|if|in|return|while)>\":::Keyword::\n\
190 Braces:\"[{}\\[\\]()<>,.:;~!&|^%*/?=+-]\":::Keyword::\n\
191 Global Variable:\"\\$[A-Za-z0-9_]+\":::Identifier1::\n\
192 diff --quilt old/source/macro.c new/source/macro.c
193 --- old/source/macro.c
194 +++ new/source/macro.c
195 @@ -902,8 +902,10 @@ void SafeGC(void)
196 WindowInfo *win;
198 for (win=WindowList; win!=NULL; win=win->next)
199 - if (win->macroCmdData != NULL || InSmartIndentMacros(win))
200 - return;
201 + if (win->macroCmdData != NULL
202 + || InSmartIndentMacros(win)
203 + || win->inMacroHook)
204 + return;
205 GarbageCollectStrings();
208 @@ -5704,3 +5706,62 @@ static int readStringArg(DataValue dv, c
209 *errMsg = "%s called with unknown object";
210 return False;
214 +** call a macro function, if it exists, with the given arguments and store
215 +** the return value in resultDV.
217 +** Currently, only non-preemtable macros are supported.
219 +Boolean MacroApplyHook(WindowInfo *document, const char *hook, int argc,
220 + DataValue *argv, DataValue *resultDV)
222 + Symbol *hookSymbol;
223 + Boolean succ = False;
225 + hookSymbol = LookupSymbol(hook);
226 + if (document &&
227 + NULL != hookSymbol &&
228 + MACRO_FUNCTION_SYM == hookSymbol->type) {
229 + Program *hookProg = hookSymbol->value.val.prog;
230 + RestartData *restartData;
231 + DataValue dummyResultDV;
232 + DataValue *resultDVPtr = &dummyResultDV;
233 + int status;
234 + char *errMsg;
236 + /* ExecuteMacro() can't be called with a NULL resultDV, therefore the
237 + dummyResultDV */
238 + if (resultDV) {
239 + resultDVPtr = resultDV;
242 + /* prevent calling the GC */
243 + document->inMacroHook++;
245 + status = ExecuteMacro(document, hookProg, argc, argv,
246 + resultDVPtr, &restartData, &errMsg);
248 + while (MACRO_TIME_LIMIT == status) {
249 + status = ContinueMacro(restartData, resultDVPtr, &errMsg);
252 + document->inMacroHook--;
254 + /* call the GC only if the caller of this function is not interested
255 + in any result, else it may happen, that strings and arrays are swept
256 + away by the GC. */
257 + if (NULL == resultDV) {
258 + SafeGC();
261 + if (MACRO_PREEMPT == status || MACRO_ERROR == status) {
262 + fprintf(stderr, "nedit: \"%s\" error: %s\n", hook, (MACRO_ERROR == status) ? errMsg : "No dialogs");
263 + } else {
264 + /* Macro is done here without errors */
265 + succ = True;
269 + return succ;
271 diff --quilt old/source/macro.h new/source/macro.h
272 --- old/source/macro.h
273 +++ new/source/macro.h
274 @@ -73,5 +73,8 @@ int CheckMacroString(Widget dialogParent
275 char *GetReplayMacro(void);
276 void ReadMacroInitFile(WindowInfo *window);
277 void ReturnShellCommandOutput(WindowInfo *window, const char *outText, int status);
278 +struct DataValueTag;
279 +Boolean MacroApplyHook(WindowInfo *document, const char *hook, int argc,
280 + struct DataValueTag *argv, struct DataValueTag *resultDV);
282 #endif /* NEDIT_MACRO_H_INCLUDED */
283 diff --quilt old/source/menu.c new/source/menu.c
284 --- old/source/menu.c
285 +++ new/source/menu.c
286 @@ -53,6 +53,7 @@ static const char CVSID[] = "$Id: menu.c
287 #include "smartIndent.h"
288 #include "windowTitle.h"
289 #include "regularExp.h"
290 +#include "hooks.h"
291 #include "../util/getfiles.h"
292 #include "../util/DialogF.h"
293 #include "../util/misc.h"
294 @@ -2850,18 +2851,20 @@ static void openAP(Widget w, XEvent *eve
295 WindowInfo *window = WidgetToWindow(w);
296 char filename[MAXPATHLEN], pathname[MAXPATHLEN];
298 - if (*nArgs == 0) {
299 + if (*nArgs != 1) {
300 fprintf(stderr, "nedit: open action requires file argument\n");
301 return;
303 - if (0 != ParseFilename(args[0], filename, pathname)
304 - || strlen(filename) + strlen(pathname) > MAXPATHLEN - 1) {
306 + if (ParseFilename(PreOpenHook(window, args[0]), filename, pathname)) {
307 fprintf(stderr, "nedit: invalid file name for open action: %s\n",
308 args[0]);
309 return;
312 EditExistingFile(window, filename, pathname, 0, NULL, False,
313 NULL, GetPrefOpenInTab(), False);
315 CheckCloseDim();
318 diff --quilt old/source/nedit.c new/source/nedit.c
319 --- old/source/nedit.c
320 +++ new/source/nedit.c
321 @@ -48,6 +48,7 @@ static const char CVSID[] = "$Id: nedit.
322 #include "interpret.h"
323 #include "parse.h"
324 #include "help.h"
325 +#include "hooks.h"
326 #include "../util/misc.h"
327 #include "../util/printUtils.h"
328 #include "../util/fileUtils.h"
329 @@ -389,7 +390,7 @@ static const char cmdLineHelp[] =
330 int main(int argc, char **argv)
332 int i, lineNum, nRead, fileSpecified = FALSE, editFlags = CREATE;
333 - int gotoLine = False, macroFileRead = False, opts = True;
334 + int gotoLine = False, opts = True;
335 int iconic=False, tabbed = -1, group = 0, isTabbed;
336 char *toDoCommand = NULL, *geometry = NULL, *langMode = NULL;
337 char filename[MAXPATHLEN], pathname[MAXPATHLEN];
338 @@ -578,6 +579,10 @@ int main(int argc, char **argv)
339 IsServer = True;
342 + EditNewFile(NULL, geometry, iconic, langMode, NULL);
343 + ReadMacroInitFile(WindowList);
344 + CheckCloseDim();
346 /* Process any command line arguments (-tags, -do, -read, -create,
347 +<line_number>, -line, -server, and files to edit) not already
348 processed by RestoreNEditPrefs. */
349 @@ -661,7 +666,8 @@ int main(int argc, char **argv)
350 numFiles = VMSFileScan(argv[i], &nameList, NULL, INCLUDE_FNF);
351 /* for each expanded file name do: */
352 for (j = 0; j < numFiles; ++j) {
353 - if (ParseFilename(nameList[j], filename, pathname) == 0) {
354 + if (ParseFilename(PreOpenHook(WindowList, nameList[j]),
355 + filename, pathname) == 0) {
356 /* determine if file is to be openned in new tab, by
357 factoring the options -group, -tabbed & -untabbed */
358 if (group == 2) {
359 @@ -693,10 +699,6 @@ int main(int argc, char **argv)
360 RaiseDocument(lastFile);
363 - if (!macroFileRead) {
364 - ReadMacroInitFile(WindowList);
365 - macroFileRead = True;
367 if (gotoLine)
368 SelectNumberedLine(window, lineNum);
369 if (toDoCommand != NULL) {
370 @@ -720,7 +722,8 @@ int main(int argc, char **argv)
371 if (nameList != NULL)
372 free(nameList);
373 #else
374 - if (ParseFilename(argv[i], filename, pathname) == 0 ) {
375 + if (ParseFilename(PreOpenHook(WindowList, argv[i]),
376 + filename, pathname) == 0 ) {
377 /* determine if file is to be openned in new tab, by
378 factoring the options -group, -tabbed & -untabbed */
379 if (group == 2) {
380 @@ -750,10 +753,6 @@ int main(int argc, char **argv)
381 RaiseDocument(lastFile);
384 - if (!macroFileRead) {
385 - ReadMacroInitFile(WindowList);
386 - macroFileRead = True;
388 if (gotoLine)
389 SelectNumberedLine(window, lineNum);
390 if (toDoCommand != NULL) {
391 @@ -786,13 +785,9 @@ int main(int argc, char **argv)
393 CheckCloseDim();
395 - /* If no file to edit was specified, open a window to edit "Untitled" */
396 - if (!fileSpecified) {
397 - EditNewFile(NULL, geometry, iconic, langMode, NULL);
398 - ReadMacroInitFile(WindowList);
399 - CheckCloseDim();
400 - if (toDoCommand != NULL)
401 - DoMacro(WindowList, toDoCommand, "-do macro");
402 + /* If no file to edit was specified, do at least the -do macro */
403 + if (!fileSpecified && toDoCommand != NULL) {
404 + DoMacro(WindowList, toDoCommand, "-do macro");
407 /* Begin remembering last command invoked for "Repeat" menu item */
408 diff --quilt old/source/nedit.h new/source/nedit.h
409 --- old/source/nedit.h
410 +++ new/source/nedit.h
411 @@ -566,6 +566,7 @@ typedef struct _WindowInfo {
412 UserBGMenuCache userBGMenuCache; /* shell & macro menu are shared over all
413 "tabbed" documents, while each document
414 has its own background menu. */
415 + int inMacroHook; /* to protect GC in MacroApplyHook() */
416 } WindowInfo;
418 extern WindowInfo *WindowList;
419 diff --quilt old/source/selection.c new/source/selection.c
420 --- old/source/selection.c
421 +++ new/source/selection.c
422 @@ -38,6 +38,7 @@ static const char CVSID[] = "$Id: select
423 #include "menu.h"
424 #include "preferences.h"
425 #include "server.h"
426 +#include "hooks.h"
427 #include "../util/DialogF.h"
428 #include "../util/fileUtils.h"
430 @@ -321,7 +322,7 @@ static void fileCB(Widget widget, Window
431 guranteed to be available, but in practice is there and does work. */
432 #if defined(DONT_HAVE_GLOB) || defined(VMS)
433 /* Open the file */
434 - if (ParseFilename(nameText, filename, pathname) != 0) {
435 + if (ParseFilename(PreOpenHook(window, nameText), filename, pathname) != 0) {
436 XBell(TheDisplay, 0);
437 return;
439 @@ -331,14 +332,15 @@ static void fileCB(Widget widget, Window
440 { char **nameList = NULL;
441 int i, nFiles = 0, maxFiles = 30;
443 - if (ParseFilename(nameText, filename, pathname) != 0) {
444 + if (ParseFilename(PreOpenHook(window, nameText), filename, pathname)) {
445 XBell(TheDisplay, 0);
446 return;
448 _XmOSGetDirEntries(pathname, filename, XmFILE_ANY_TYPE, False, True,
449 &nameList, &nFiles, &maxFiles);
450 for (i=0; i<nFiles; i++) {
451 - if (ParseFilename(nameList[i], filename, pathname) != 0) {
452 + if (ParseFilename(PreOpenHook(window, nameList[i]),
453 + filename, pathname)) {
454 XBell(TheDisplay, 0);
456 else {
457 @@ -357,7 +359,8 @@ static void fileCB(Widget widget, Window
459 glob(nameText, GLOB_NOCHECK, NULL, &globbuf);
460 for (i=0; i<(int)globbuf.gl_pathc; i++) {
461 - if (ParseFilename(globbuf.gl_pathv[i], filename, pathname) != 0)
462 + if (ParseFilename(PreOpenHook(window, globbuf.gl_pathv[i]),
463 + filename, pathname))
464 XBell(TheDisplay, 0);
465 else
466 EditExistingFile(GetPrefOpenInTab()? window : NULL,
467 diff --quilt old/source/window.c new/source/window.c
468 --- old/source/window.c
469 +++ new/source/window.c
470 @@ -55,6 +55,7 @@ static const char CVSID[] = "$Id: window
471 #include "windowTitle.h"
472 #include "interpret.h"
473 #include "rangeset.h"
474 +#include "hooks.h"
475 #include "../util/clearcase.h"
476 #include "../util/misc.h"
477 #include "../util/fileUtils.h"
478 @@ -169,6 +170,7 @@ static void showStatsForm(WindowInfo *wi
479 static void addToWindowList(WindowInfo *window);
480 static void removeFromWindowList(WindowInfo *window);
481 static void focusCB(Widget w, WindowInfo *window, XtPointer callData);
482 +static void losingFocusCB(Widget w, WindowInfo *window, XtPointer callData);
483 static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled,
484 const char *deletedText, void *cbArg);
485 static void movedCB(Widget w, WindowInfo *window, XtPointer callData);
486 @@ -325,6 +327,7 @@ WindowInfo *CreateWindow(const char *nam
487 window->tab = NULL;
488 window->device = 0;
489 window->inode = 0;
490 + window->inMacroHook = 0;
492 /* If window geometry was specified, split it apart into a window position
493 component and a window size component. Create a new geometry string
494 @@ -958,6 +961,11 @@ void CloseWindow(WindowInfo *window)
495 int keepWindow, state;
496 WindowInfo *win, *topBuf = NULL, *nextBuf = NULL;
498 + if (window->inMacroHook) {
499 + fprintf(stderr, "nedit: error: closing window while in MacroHook\n");
500 + return;
503 /* Free smart indent macro programs */
504 EndSmartIndent(window);
506 @@ -2321,6 +2329,8 @@ static Widget createTextArea(Widget pare
508 /* add focus, drag, cursor tracking, and smart indent callbacks */
509 XtAddCallback(text, textNfocusCallback, (XtCallbackProc)focusCB, window);
510 + XtAddCallback(text, textNlosingFocusCallback,
511 + (XtCallbackProc)losingFocusCB, window);
512 XtAddCallback(text, textNcursorMovementCallback, (XtCallbackProc)movedCB,
513 window);
514 XtAddCallback(text, textNdragStartCallback, (XtCallbackProc)dragStartCB,
515 @@ -2373,6 +2383,8 @@ static void movedCB(Widget w, WindowInfo
516 /* Start blinking the caret again. */
517 ResetCursorBlink(textWidget, False);
520 + CursorMovedHook(window);
523 static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled,
524 @@ -2444,6 +2456,8 @@ static void modifiedCB(int pos, int nIns
526 /* Check if external changes have been made to file and warn user */
527 CheckForChangesToFile(window);
529 + ModifiedHook(window);
532 static void focusCB(Widget w, WindowInfo *window, XtPointer callData)
533 @@ -2459,6 +2473,13 @@ static void focusCB(Widget w, WindowInfo
535 /* Check for changes to read-only status and/or file modifications */
536 CheckForChangesToFile(window);
538 + FocusHook(window);
541 +static void losingFocusCB(Widget w, WindowInfo *window, XtPointer callData)
543 + LosingFocusHook(window);
546 static void dragStartCB(Widget w, WindowInfo *window, XtPointer callData)
547 @@ -3466,6 +3487,7 @@ WindowInfo* CreateDocument(WindowInfo* s
548 window->bgMenuRedoItem = NULL;
549 window->device = 0;
550 window->inode = 0;
551 + window->inMacroHook = 0;
553 if (window->fontList == NULL)
554 XtVaGetValues(shellWindow->statsLine, XmNfontList,
555 diff --quilt /dev/null new/source/hooks.c
556 --- /dev/null
557 +++ new/source/hooks.c
558 @@ -0,0 +1,133 @@
559 +#ifdef HAVE_CONFIG_H
560 +#include "../config.h"
561 +#endif
563 +#include "preferences.h"
564 +#include "interpret.h"
565 +#include "macro.h"
567 +#include <errno.h>
568 +#include <limits.h>
569 +#include <stdio.h>
570 +#include <stdlib.h>
571 +#include <string.h>
572 +#include <unistd.h>
574 +#ifdef VMS
575 +#include "../util/VMSparam.h"
576 +#include <types.h>
577 +#include <stat.h>
578 +#include <unixio.h>
579 +#else
580 +#include <sys/types.h>
581 +#include <sys/stat.h>
582 +#include <utime.h>
583 +#ifndef __MVS__
584 +#include <sys/param.h>
585 +#endif
586 +#include <fcntl.h>
587 +#endif /*VMS*/
588 +#include <utime.h>
590 +#ifdef HAVE_DEBUG_H
591 +#include "../debug.h"
592 +#endif
594 +const char *
595 +PreOpenHook(WindowInfo *window, const char *fullname)
597 + DataValue fileNameArg;
598 + DataValue resultDV = {NO_TAG, {0}};
599 + Boolean succ = False;
601 + if (!window) {
602 + /* search a window which does not execute a macro currently */
603 + window = WindowList;
604 + while (window != NULL && window->macroCmdData != NULL) {
605 + window = window->next;
608 + if (!window) {
609 + XBell(TheDisplay, 0);
610 + fprintf(stderr, "nedit: warning: can't call pre_open_hook for "
611 + "file \"%s\"", fullname);
612 + return fullname;
615 + fileNameArg.tag = STRING_TAG;
616 + AllocNStringCpy(&fileNameArg.val.str, fullname);
617 + succ = MacroApplyHook(window, "pre_open_hook", 1, &fileNameArg, &resultDV);
619 + if (succ && resultDV.tag == STRING_TAG) {
620 + return resultDV.val.str.rep;
621 + } else {
622 + return fullname;
626 +void
627 +PostOpenHook(WindowInfo *window)
629 + MacroApplyHook(window, "post_open_hook", 0, NULL, NULL);
632 +const char *
633 +PreSaveHook(WindowInfo *window)
635 + DataValue resultDV = {NO_TAG,{0}};
636 + Boolean succ;
638 + /* call the "pre_save_hook", if the macro returns a string, interpret this
639 + as the new filename */
640 + succ = MacroApplyHook(window, "pre_save_hook", 0, NULL, &resultDV);
641 + if (succ && resultDV.tag == STRING_TAG) {
642 + return resultDV.val.str.rep;
645 + return NULL;
648 +void
649 +PostSaveHook(WindowInfo *window)
651 + MacroApplyHook(window, "post_save_hook", 0, NULL, NULL);
654 +void
655 +LanguageModeHook(WindowInfo *window, int oldMode)
657 + DataValue oldModeArg;
658 + const char *oldModeName = LanguageModeName(oldMode);
660 + if (oldModeName == NULL)
661 + oldModeName = "Plain";
663 + oldModeArg.tag = STRING_TAG;
664 + AllocNStringCpy(&oldModeArg.val.str, oldModeName);
665 + MacroApplyHook(window, "language_mode_hook", 1, &oldModeArg, NULL);
668 +void
669 +CursorMovedHook(WindowInfo *window)
671 + MacroApplyHook(window, "cursor_moved_hook", 0, NULL, NULL);
674 +void
675 +ModifiedHook(WindowInfo *window)
677 + MacroApplyHook(window, "modified_hook", 0, NULL, NULL);
680 +void
681 +FocusHook(WindowInfo *window)
683 + MacroApplyHook(window, "focus_hook", 0, NULL, NULL);
686 +void
687 +LosingFocusHook(WindowInfo *window)
689 + MacroApplyHook(window, "losing_focusHook", 0, NULL, NULL);
692 diff --quilt /dev/null new/source/hooks.h
693 --- /dev/null
694 +++ new/source/hooks.h
695 @@ -0,0 +1,15 @@
696 +#ifndef NEDIT_HOOKS_H_INCLUDED
697 +#define NEDIT_HOOKS_H_INCLUDED
699 +const char *PreOpenHook(WindowInfo *window, const char *fullname);
700 +void PostOpenHook(WindowInfo *window);
701 +const char *PreSaveHook(WindowInfo *window);
702 +void PostSaveHook(WindowInfo *window);
703 +void LanguageModeHook(WindowInfo *window, int oldMode);
705 +void CursorMovedHook(WindowInfo *window);
706 +void ModifiedHook(WindowInfo *window);
707 +void FocusHook(WindowInfo *window);
708 +void LosingFocusHook(WindowInfo *window);
710 +#endif /* NEDIT_HOOKS_H_INCLUDED */
711 diff --quilt old/source/server.c new/source/server.c
712 --- old/source/server.c
713 +++ new/source/server.c
714 @@ -41,6 +41,7 @@ static const char CVSID[] = "$Id: server
715 #include "menu.h"
716 #include "preferences.h"
717 #include "server_common.h"
718 +#include "hooks.h"
719 #include "../util/fileUtils.h"
720 #include "../util/utils.h"
721 #include "../util/misc.h"
722 @@ -76,7 +77,7 @@ static const char CVSID[] = "$Id: server
723 static void processServerCommand(void);
724 static void cleanUpServerCommunication(void);
725 static void processServerCommandString(char *string);
726 -static void getFileClosedProperty(WindowInfo *window);
727 +static void getFileClosedProperty(WindowInfo *window, const char *fulname);
728 static int isLocatedOnDesktop(WindowInfo *window, long currentDesktop);
729 static WindowInfo *findWindowOnDesktop(int tabbed, long currentDesktop);
731 @@ -213,62 +214,53 @@ Boolean ServerDispatchEvent(XEvent *even
734 /* Try to find existing 'FileOpen' property atom for path. */
735 -static Atom findFileOpenProperty(const char* filename,
736 - const char* pathname) {
737 - char path[MAXPATHLEN];
738 +static Atom findFileOpenProperty(const char *fullname)
740 Atom atom;
742 if (!IsServer) return(None);
744 - strcpy(path, pathname);
745 - strcat(path, filename);
746 - atom = CreateServerFileOpenAtom(GetPrefServerName(), path);
747 + atom = CreateServerFileOpenAtom(GetPrefServerName(), fullname);
748 return(atom);
751 /* Destroy the 'FileOpen' atom to inform nc that this file has
752 ** been opened.
754 -static void deleteFileOpenProperty(WindowInfo *window)
755 +static void deleteFileOpenProperty(WindowInfo *window, const char *fullname)
757 if (window->filenameSet) {
758 - Atom atom = findFileOpenProperty(window->filename, window->path);
759 + Atom atom = findFileOpenProperty(fullname);
760 deleteProperty(&atom);
764 -static void deleteFileOpenProperty2(const char* filename,
765 - const char* pathname)
766 +static void deleteFileOpenProperty2(const char *fullname)
768 - Atom atom = findFileOpenProperty(filename, pathname);
769 + Atom atom = findFileOpenProperty(fullname);
770 deleteProperty(&atom);
775 /* Try to find existing 'FileClosed' property atom for path. */
776 -static Atom findFileClosedProperty(const char* filename,
777 - const char* pathname)
778 +static Atom findFileClosedProperty(const char *fullname)
780 - char path[MAXPATHLEN];
781 Atom atom;
783 if (!IsServer) return(None);
785 - strcpy(path, pathname);
786 - strcat(path, filename);
787 atom = CreateServerFileClosedAtom(GetPrefServerName(),
788 - path,
789 + fullname,
790 True); /* don't create */
791 return(atom);
794 /* Get hold of the property to use when closing the file. */
795 -static void getFileClosedProperty(WindowInfo *window)
796 +static void getFileClosedProperty(WindowInfo *window, const char *fullname)
798 if (window->filenameSet) {
799 - window->fileClosedAtom = findFileClosedProperty(window->filename,
800 - window->path);
801 + window->fileClosedAtom = findFileClosedProperty(fullname);
805 @@ -282,10 +274,9 @@ void DeleteFileClosedProperty(WindowInfo
809 -static void deleteFileClosedProperty2(const char* filename,
810 - const char* pathname)
811 +static void deleteFileClosedProperty2(const char* fullname)
813 - Atom atom = findFileClosedProperty(filename, pathname);
814 + Atom atom = findFileClosedProperty(fullname);
815 deleteProperty(&atom);
818 @@ -338,7 +329,8 @@ static WindowInfo *findWindowOnDesktop(i
820 static void processServerCommandString(char *string)
822 - char *fullname, filename[MAXPATHLEN], pathname[MAXPATHLEN];
823 + const char *fullname, *requestname;
824 + char filename[MAXPATHLEN], pathname[MAXPATHLEN];
825 char *doCommand, *geometry, *langMode, *inPtr;
826 int editFlags, stringLen = strlen(string);
827 int lineNum, createFlag, readFlag, iconicFlag, lastIconic = 0, tabbed = -1;
828 @@ -371,6 +363,7 @@ static void processServerCommandString(c
830 inPtr = string;
831 while (TRUE) {
832 + int needToCallPostOpenHook = False;
834 if (*inPtr == '\0')
835 break;
836 @@ -388,7 +381,7 @@ static void processServerCommandString(c
837 inPtr += charsRead + 1;
838 if (inPtr - string + fileLen > stringLen)
839 goto readError;
840 - fullname = inPtr;
841 + requestname = inPtr;
842 inPtr += fileLen;
843 *inPtr++ = '\0';
844 if (inPtr - string + doLen > stringLen)
845 @@ -407,6 +400,8 @@ static void processServerCommandString(c
846 inPtr += geomLen;
847 *inPtr++ = '\0';
849 + fullname = PreOpenHook(NULL, requestname);
851 /* An empty file name means:
852 * put up an empty, Untitled window, or use an existing one
853 * choose a random window for executing the -do macro upon
854 @@ -456,7 +451,7 @@ static void processServerCommandString(c
855 (createFlag ? SUPPRESS_CREATE_WARN : 0);
856 if (ParseFilename(fullname, filename, pathname) != 0) {
857 fprintf(stderr, "NEdit: invalid file name\n");
858 - deleteFileClosedProperty2(filename, pathname);
859 + deleteFileClosedProperty2(requestname);
860 break;
863 @@ -482,16 +477,22 @@ static void processServerCommandString(c
867 + else
868 + needToCallPostOpenHook = True;
870 /* Do the actions requested (note DoMacro is last, since the do
871 command can do anything, including closing the window!) */
872 if (window != NULL) {
873 - deleteFileOpenProperty(window);
874 - getFileClosedProperty(window);
875 + deleteFileOpenProperty(window, requestname);
876 + getFileClosedProperty(window, requestname);
878 if (lineNum > 0)
879 SelectNumberedLine(window, lineNum);
881 + /* post_open can't close the document */
882 + if (needToCallPostOpenHook)
883 + PostOpenHook(window);
885 if (*doCommand != '\0') {
886 RaiseDocument(window);
888 @@ -519,8 +520,8 @@ static void processServerCommandString(c
889 lastIconic = iconicFlag;
891 } else {
892 - deleteFileOpenProperty2(filename, pathname);
893 - deleteFileClosedProperty2(filename, pathname);
894 + deleteFileOpenProperty2(requestname);
895 + deleteFileClosedProperty2(requestname);
899 diff --quilt old/source/Makefile.common new/source/Makefile.common
900 --- old/source/Makefile.common
901 +++ new/source/Makefile.common
902 @@ -8,6 +8,7 @@ OBJS = nedit.o file.o menu.o window.o se
903 text.o textSel.o textDisp.o textBuf.o textDrag.o server.o highlight.o \
904 highlightData.o interpret.o parse.o smartIndent.o regexConvert.o \
905 rbTree.o windowTitle.o calltips.o server_common.o rangeset.o
906 +OBJS += hooks.o
908 XLTLIB = ../Xlt/libXlt.a
909 XMLLIB = ../Microline/XmL/libXmL.a
910 diff --quilt old/source/preferences.c new/source/preferences.c
911 --- old/source/preferences.c
912 +++ new/source/preferences.c
913 @@ -47,6 +47,7 @@ static const char CVSID[] = "$Id: prefer
914 #include "windowTitle.h"
915 #include "server.h"
916 #include "tags.h"
917 +#include "hooks.h"
918 #include "../util/prefFile.h"
919 #include "../util/misc.h"
920 #include "../util/DialogF.h"
921 @@ -4643,6 +4644,8 @@ static void reapplyLanguageMode(WindowIn
923 /* Add/remove language specific menu items */
924 UpdateUserMenus(window);
926 + LanguageModeHook(window, oldMode);