Here's a revised patch including a more rigorous way of parsing the error code from a error message.
Another use-case I've been trying recently: if wrapscan is initially disabled, enable it when the search hits top/bottom. This way one is notified that the search reached the end but pressing n/N again will temporary enable wrapscan in order to redo the search from the opposite end. set nowrapscan let s:wrapscan = 0 func! s:ToggleWrapScan(rhs) abort if s:wrapscan set wrapscan let s:wrapscan = 0 else set nowrapscan endif return a:rhs endfunc nnoremap <expr> n <SID>ToggleWrapScan('n') nnoremap <expr> N <SID>ToggleWrapScan('N') augroup error au! Error E38[45] let s:wrapscan = 1 augroup END -- :wq -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
diff --git a/src/fileio.c b/src/fileio.c index ecec757..9a1e294 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -7666,6 +7666,7 @@ static struct event_name {"CursorMoved", EVENT_CURSORMOVED}, {"CursorMovedI", EVENT_CURSORMOVEDI}, {"EncodingChanged", EVENT_ENCODINGCHANGED}, + {"Error", EVENT_ERROR}, {"FileEncoding", EVENT_ENCODINGCHANGED}, {"FileAppendPost", EVENT_FILEAPPENDPOST}, {"FileAppendPre", EVENT_FILEAPPENDPRE}, @@ -7725,6 +7726,21 @@ static struct event_name {NULL, (event_T)0} }; + +/* + * Mapping of error code to pattern used for <amatch> when triggering the Error + * event. + */ +static struct error_pat +{ + const char *code; + const char *pat; +} error_pats[] = +{ + {"E426", "tagnotfound"}, + {NULL, NULL} +}; + static AutoPat *first_autopat[NUM_EVENTS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -9351,7 +9367,7 @@ apply_autocmds_group( { sfname = vim_strsave(fname); /* Don't try expanding FileType, Syntax, FuncUndefined, WindowID, - * ColorScheme or QuickFixCmd* */ + * ColorScheme, Error or QuickFixCmd* */ if (event == EVENT_FILETYPE || event == EVENT_SYNTAX || event == EVENT_FUNCUNDEFINED @@ -9359,6 +9375,7 @@ apply_autocmds_group( || event == EVENT_SPELLFILEMISSING || event == EVENT_QUICKFIXCMDPRE || event == EVENT_COLORSCHEME + || event == EVENT_ERROR || event == EVENT_OPTIONSET || event == EVENT_QUICKFIXCMDPOST) fname = vim_strsave(fname); @@ -9750,20 +9767,26 @@ has_autocmd(event_T event, char_u *sfname, buf_T *buf) char_u *tail = gettail(sfname); int retval = FALSE; - fname = FullName_save(sfname, FALSE); - if (fname == NULL) - return FALSE; - + /* don't try expanding Error */ + if (event == EVENT_ERROR) { + fname = vim_strsave(sfname); + if (fname == NULL) + return FALSE; + } else { + fname = FullName_save(sfname, FALSE); + if (fname == NULL) + return FALSE; #ifdef BACKSLASH_IN_FILENAME - /* - * Replace all backslashes with forward slashes. This makes the - * autocommand patterns portable between Unix and MS-DOS. - */ - sfname = vim_strsave(sfname); - if (sfname != NULL) - forward_slash(sfname); - forward_slash(fname); + /* + * Replace all backslashes with forward slashes. This makes the + * autocommand patterns portable between Unix and MS-DOS. + */ + sfname = vim_strsave(sfname); + if (sfname != NULL) + forward_slash(sfname); + forward_slash(fname); #endif + } for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) if (ap->pat != NULL && ap->cmds != NULL @@ -10358,3 +10381,22 @@ write_eintr(int fd, void *buf, size_t bufsize) return ret; } #endif + + +/* + * Get the corresponding pattern for the given error message code. The returned + * value is used for <amatch> when triggering the Error autocmd event. + */ + char_u * +get_error_pat(char_u *code) +{ + size_t len; + int i; + + len = STRLEN(code); + for (i = 0; error_pats[i].code; i++) + if (STRNCMP(error_pats[i].code, code, len) == 0) + return (char_u *)error_pats[i].pat; + + return NULL; +} diff --git a/src/globals.h b/src/globals.h index 4c1b41f..4342b71 100644 --- a/src/globals.h +++ b/src/globals.h @@ -184,6 +184,10 @@ EXTERN int did_emsg; /* set by emsg() when the message EXTERN int did_emsg_syntax; /* did_emsg set because of a syntax error */ EXTERN int called_emsg; /* always set by emsg() */ +#ifdef FEAT_AUTOCMD +EXTERN char_u *emsg_code INIT(= NULL); /* last error message code set by + emsg() */ +#endif EXTERN int ex_exitval INIT(= 0); /* exit value for ex mode */ EXTERN int emsg_on_display INIT(= FALSE); /* there is an error message */ EXTERN int rc_did_emsg INIT(= FALSE); /* vim_regcomp() called emsg() */ diff --git a/src/main.c b/src/main.c index e412641..aad656a 100644 --- a/src/main.c +++ b/src/main.c @@ -1278,6 +1278,20 @@ main_loop( fileinfo(FALSE, TRUE, FALSE); need_fileinfo = FALSE; } +#ifdef FEAT_AUTOCMD + if (did_emsg && emsg_code) { + char_u *pat = get_error_pat(emsg_code); + if (pat && has_autocmd(EVENT_ERROR, pat, curbuf)) + apply_autocmds(EVENT_ERROR, pat, curbuf->b_fname, FALSE, + curbuf); + else if (has_autocmd(EVENT_ERROR, emsg_code, curbuf)) + apply_autocmds(EVENT_ERROR, emsg_code, curbuf->b_fname, + FALSE, curbuf); + + vim_free(emsg_code); + emsg_code = NULL; + } +#endif emsg_on_display = FALSE; /* can delete error message now */ did_emsg = FALSE; diff --git a/src/message.c b/src/message.c index b352590..1c8c7f0 100644 --- a/src/message.c +++ b/src/message.c @@ -22,6 +22,7 @@ static int other_sourcing_name(void); static char_u *get_emsg_source(void); static char_u *get_emsg_lnum(void); +static char_u *get_emsg_code(char_u *s); static void add_msg_hist(char_u *s, int len, int attr); static void hit_return_msg(void); static void msg_home_replace_attr(char_u *fname, int attr); @@ -453,6 +454,32 @@ get_emsg_lnum(void) } /* + * Extract the error code from a error message. + */ + static char_u * +get_emsg_code(char_u *s) +{ + int i, j; + + i = 0; + while (s[i]) { + if (s[i] == 'E') { + j = i + 1; + while (VIM_ISDIGIT(s[j])) + j++; + if (s[j] == ':') + return vim_strnsave(&s[i], j - i); + else + i = j; + } else { + i++; + } + } + + return NULL; +} + +/* * Display name and line number for the source of an error. * Remember the file name and line number, so that for the next error the info * is only displayed if it changed. @@ -559,6 +586,10 @@ emsg(char_u *s) return TRUE; } +#ifdef FEAT_AUTOCMD + emsg_code = get_emsg_code(s); +#endif + /* set "v:errmsg", also when using ":silent! cmd" */ set_vim_var_string(VV_ERRMSG, s, -1); #endif diff --git a/src/proto/fileio.pro b/src/proto/fileio.pro index 9cd6414..dd8453e 100644 --- a/src/proto/fileio.pro +++ b/src/proto/fileio.pro @@ -64,4 +64,5 @@ int match_file_list(char_u *list, char_u *sfname, char_u *ffname); char_u *file_pat_to_reg_pat(char_u *pat, char_u *pat_end, char *allow_dirs, int no_bslash); long read_eintr(int fd, void *buf, size_t bufsize); long write_eintr(int fd, void *buf, size_t bufsize); +char_u *get_error_pat(char_u *code); /* vim: set ft=c : */ diff --git a/src/vim.h b/src/vim.h index 02f3036..b9c0c22 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1295,6 +1295,7 @@ enum auto_event EVENT_WINENTER, /* after entering a window */ EVENT_WINLEAVE, /* before leaving a window */ EVENT_ENCODINGCHANGED, /* after changing the 'encoding' option */ + EVENT_ERROR, /* an error occured */ EVENT_INSERTCHARPRE, /* before inserting a char */ EVENT_CURSORHOLD, /* cursor in same position for a while */ EVENT_CURSORHOLDI, /* idem, in Insert mode */