Re: [PATCH] Ignore comments when jumping to a declaration
Updated patch attach which adds support for skipping strings and characters that include the identifier. With the patch applied, pressing gd in the example below would end up on line 4 as opposed of line 3: int func(void) { char *s = "x"; // line #3 int x = 1; // line #4 return x; ^ | cursor } While at it, I added a few more tests to cover this new behavior. -- -- 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/normal.c b/src/normal.c index 8302ffb..9a27d3c 100644 --- a/src/normal.c +++ b/src/normal.c @@ -4240,6 +4240,52 @@ nv_gd( } /* + * Return TRUE if line[offset] is not inside a C-style comment or string, FALSE + * otherwise. + */ +static int +is_ident(char_u *line, int offset) +{ +inti; +intincomment = FALSE; +intinstring = FALSE; +intprev; +intstrdel; /* string delimiter character */ + +for (i = prev = 0; i < offset && line[i] != NUL; i++) +{ + if (incomment) + { + if (prev == '*' && line[i] == '/') + incomment = FALSE; + } + else if (prev == '/' && line[i] == '*') + { + incomment = TRUE; + } + else if (prev == '/' && line[i] == '/') + { + return FALSE; + } + + if (instring) + { + if (prev != '\\' && line[i] == strdel) + instring = FALSE; + } + else if (prev != '\\' && (line[i] == '"' || line[i] == '\'')) + { + instring = TRUE; + strdel = line[i]; + } + + prev = line[i]; +} + +return incomment == FALSE && instring == FALSE; +} + +/* * Search for variable declaration of "ptr[len]". * When "locally" is TRUE in the current function ("gd"), otherwise in the * current file ("gD"). @@ -4264,6 +4310,7 @@ find_decl( intretval = OK; intincll; intsearchflags = flags_arg; +intvalid; if ((pat = alloc(len + 7)) == NULL) return FAIL; @@ -4301,6 +4348,7 @@ find_decl( clearpos(_pos); for (;;) { + valid = FALSE; t = searchit(curwin, curbuf, >w_cursor, FORWARD, pat, 1L, searchflags, RE_LAST, (linenr_T)0, NULL); if (curwin->w_cursor.lnum >= old_pos.lnum) @@ -4337,9 +4385,20 @@ find_decl( continue; } #endif - if (!locally) /* global search: use first match found */ + + /* If the current position is not a valid identifier and a previous +* match is present, favor that one instead. */ + if ((valid = is_ident(ml_get_curline(), curwin->w_cursor.col)) == FALSE + && found_pos.lnum != 0) + { + curwin->w_cursor = found_pos; break; - if (curwin->w_cursor.lnum >= par_pos.lnum) + } + + /* Global search: use first valid match found */ + if (valid && !locally) + break; + if (valid && curwin->w_cursor.lnum >= par_pos.lnum) { /* If we previously found a valid position, use it. */ if (found_pos.lnum != 0) @@ -4347,11 +4406,20 @@ find_decl( break; } - /* For finding a local variable and the match is before the "{" search -* to find a later match. For K style function declarations this -* skips the function header without types. Remove SEARCH_START from -* flags to avoid getting stuck at one position. */ - found_pos = curwin->w_cursor; + /* For finding a local variable and the match is before the "{" or +* inside a comment, continue searching. For K style function +* declarations this skips the function header without types. */ + if (!valid) + { + /* Braces needed due to macro expansion of clearpos. */ + clearpos(_pos); + } + else + { + found_pos = curwin->w_cursor; + } + /* Remove SEARCH_START from flags to avoid getting stuck at one +* position. */ searchflags &= ~SEARCH_START; } diff --git a/src/testdir/test_goto.vim b/src/testdir/test_goto.vim index 2afd96b..7ea5169 100644 --- a/src/testdir/test_goto.vim +++ b/src/testdir/test_goto.vim @@ -1,20 +1,237 @@ " Test commands that jump somewhere. -func Test_geeDEE() +" Create a new buffer using lines and place the cursor on the word after the +" first occurrence of return and invoke key. The cursor should now be positioned +" at the given line and col. +func
[PATCH] Ignore comments when jumping to a declaration
Hi, The goto declaration commands (gd and gD) only discards completely commented out lines. In the following scenario pressing 'gd' would place the cursor on the occurrence of x inside the trailing comment: int func(int x) /* x is an int */ { return x; ^ | cursor } This is by design, the search is not terminated at the first occurrence of the identifier in order to handle K function declarations correctly. The attached patch add support for discarding any type of C-style comment. Thus, it does not respect the commentstring option. I think this is reasonable since the behavior of gd and gD is tailored for C code but occasionally works well with other similar languages. Another limitation of the attached patch is that it does not recognize nested multi-line comments (/* /* nested */ */) but should one care? While at it, improve the test coverage for both gd and gD. -- -- 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/normal.c b/src/normal.c index bbcd618..ce75e90 100644 --- a/src/normal.c +++ b/src/normal.c @@ -4238,6 +4238,46 @@ nv_gd( } /* + * Find the first inline C-style comment in line starting from offset. The + * comment boundaries (inclusive) will be written to start and end. Return TRUE + * if a comment is found, FALSE otherwise. + */ +static int +find_comment(char_u *line, int offset, int *start, int *end) +{ +inti; +intincomment = FALSE; +intprev = 0; + +for (i = offset; line[i] != NUL; i++) +{ + if (incomment) + { + if (prev == '*' && line[i] == '/') + { + *end = i; + return TRUE; + } + } + else if (prev == '/' && line[i] == '*') + { + incomment = TRUE; + *start = i > 0 ? i - 1 : 0; + } + else if (prev == '/' && line[i] == '/') + { + *start = i > 0 ? i - 1 : 0; + *end = *start + STRLEN([i]); + return TRUE; + } + + prev = line[i]; +} + +return FALSE; +} + +/* * Search for variable declaration of "ptr[len]". * When "locally" is TRUE in the current function ("gd"), otherwise in the * current file ("gD"). @@ -4262,6 +4302,9 @@ find_decl( intretval = OK; intincll; intsearchflags = flags_arg; +intcstart; /* comment start offset */ +intcend; /* comment end offset */ +intincomment; if ((pat = alloc(len + 7)) == NULL) return FAIL; @@ -4299,6 +4342,7 @@ find_decl( clearpos(_pos); for (;;) { + incomment = FALSE; t = searchit(curwin, curbuf, >w_cursor, FORWARD, pat, 1L, searchflags, RE_LAST, (linenr_T)0, NULL); if (curwin->w_cursor.lnum >= old_pos.lnum) @@ -4335,9 +4379,33 @@ find_decl( continue; } #endif - if (!locally) /* global search: use first match found */ + + /* If the identifier is present inside a comment and a previous match is +* present, favor that one instead. */ + for (cstart = 0; + find_comment(ml_get_curline(), cstart, , ) == TRUE; + cstart++) + { + if (curwin->w_cursor.col > cstart + && curwin->w_cursor.col + len < cend) + { + if (found_pos.lnum != 0) + { + curwin->w_cursor = found_pos; + goto done; + } + else + { + incomment = TRUE; + break; + } + } + } + + /* Global search: use first match found unless inside comment */ + if (!incomment && !locally) break; - if (curwin->w_cursor.lnum >= par_pos.lnum) + if (!incomment && curwin->w_cursor.lnum >= par_pos.lnum) { /* If we previously found a valid position, use it. */ if (found_pos.lnum != 0) @@ -4345,14 +4413,24 @@ find_decl( break; } - /* For finding a local variable and the match is before the "{" search -* to find a later match. For K style function declarations this -* skips the function header without types. Remove SEARCH_START from -* flags to avoid getting stuck at one position. */ - found_pos = curwin->w_cursor; + /* For finding a local variable and the match is before the "{" or +* inside a comment, continue
[patch] Fix compiler warning in quickfix.c
Hi, Compiling commit e0d3797 with GCC and -pedantic gives the following warning: quickfix.c: In function 'qf_init_ext': quickfix.c:795: warning: initializer element is not computable at load time quickfix.c:795: warning: initializer element is not computable at load time Attached is a patch that gets rid of this warning. -- :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/quickfix.c b/src/quickfix.c index 4be1d91..fa76e5d 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -792,7 +792,7 @@ qf_init_ext( interrmsglen; char_u *pattern; qfstate_T state = {NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, -NULL, lnumfirst, lnumlast}; +NULL, 0, 0}; intcol = 0; char_u use_viscol = FALSE; inttype = 0; @@ -816,6 +816,8 @@ qf_init_ext( char_u *tail = NULL; regmatch_T regmatch; +state.buflnum = lnumfirst; +state.lnumlast = lnumlast; namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf); errmsglen = CMDBUFFSIZE + 1; errmsg = alloc_id(errmsglen, aid_qf_errmsg);
Re: [patch] Fix quickfix handling of long lines
On Sat, Apr 30, 2016 at 01:17:22PM +0200, Bram Moolenaar wrote: > > Anton Lindqvist wrote: > > > I managed to crash Vim yesterday due to a off-by-one allocation bug > > related to the quickfix changes. Fixed in the attached patch. > > Well, if I run test_quickfix after including this patch, Vim crashes. > I found that a statement was missing, setting linelen to len. > I did some minor cleanups. Nice catch! > I'll include it now. However, the code to increase the size of the > buffer is repeated three times, would be nice to put it in one place. Here's a proposal: static char_u * buffer_alloc(char_u *buf, int *bufsiz, int *newsiz) { if (*newsiz > LINE_MAXLEN) *newsiz = LINE_MAXLEN - 1; if (buf == NULL) { if ((buf = alloc(*newsiz)) == NULL) return NULL; } else { if (*newsiz < *bufsiz) return buf; if ((buf = vim_realloc(buf, *newsiz)) == NULL) return NULL; } /* allocation succeed */ *bufsiz = *newsiz; return buf; } Then the following logic: linelen = len > LINE_MAXLEN ? LINE_MAXLEN - 1 : len; if (growbuf == NULL) { growbuf = alloc(linelen); growbufsiz = linelen; } else if (linelen > growbufsiz) { growbuf = vim_realloc(growbuf, linelen); if (growbuf == NULL) goto qf_init_end; growbufsiz = linelen; } linebuf = growbuf; ... could be replaced with: linelen = len; if ((growbuf = buffer_alloc(growbuf, , )) == NULL) goto qf_init_end; Would you like me to submit such a patch? -- :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.
Re: [patch] Fix quickfix handling of long lines
The patch did no longer apply without a conflict, updated patch attached. -- :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/quickfix.c b/src/quickfix.c index 510d8dd..cad2877 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -175,6 +175,11 @@ qf_init( } /* + * Maximum number of bytes allowed per line while reading a errorfile. + */ +#define LINE_MAXLEN 4096 + +/* * Read the errorfile "efile" into memory, line by line, building the error * list. * Alternative: when "efile" is null read errors from buffer "buf". @@ -197,8 +202,15 @@ qf_init_ext( { char_u *namebuf; char_u *errmsg; +interrmsglen; char_u *pattern; char_u *fmtstr = NULL; +char_u *growbuf = NULL; +intgrowbuflen; +intgrowbufsiz; +char_u *linebuf; +intlinelen; +intdiscard; intcol = 0; char_u use_viscol = FALSE; inttype = 0; @@ -227,6 +239,7 @@ qf_init_ext( char_u *directory = NULL; char_u *currfile = NULL; char_u *tail = NULL; +char_u *p_buf = NULL; char_u *p_str = NULL; listitem_T *p_li = NULL; struct dir_stack_T *file_stack = NULL; @@ -250,7 +263,8 @@ qf_init_ext( }; namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf); -errmsg = alloc_id(CMDBUFFSIZE + 1, aid_qf_errmsg); +errmsglen = CMDBUFFSIZE + 1; +errmsg = alloc_id(errmsglen, aid_qf_errmsg); pattern = alloc_id(CMDBUFFSIZE + 1, aid_qf_pattern); if (namebuf == NULL || errmsg == NULL || pattern == NULL) goto qf_init_end; @@ -523,10 +537,37 @@ qf_init_ext( len = (int)STRLEN(p_str); if (len > CMDBUFFSIZE - 2) - vim_strncpy(IObuff, p_str, CMDBUFFSIZE - 2); + { + /* +* If the line exceeds LINE_MAXLEN exclude the last byte +* since it's not a NL character. +*/ + linelen = len > LINE_MAXLEN ? LINE_MAXLEN - 1 : len; + if (growbuf == NULL) + { + growbuf = alloc(linelen); + growbufsiz = linelen; + } + else if (linelen > growbufsiz) + { + if ((growbuf = vim_realloc(growbuf, + linelen)) == NULL) + goto qf_init_end; + growbufsiz = linelen; + } + linebuf = growbuf; + } else - vim_strncpy(IObuff, p_str, len); + { + linebuf = IObuff; + linelen = len; + } + vim_strncpy(linebuf, p_str, linelen); + /* +* Increment using len in order to discard the rest of the +* line if it exceeds LINE_MAXLEN. +*/ p_str += len; } else if (tv->v_type == VAR_LIST) @@ -541,9 +582,30 @@ qf_init_ext( len = (int)STRLEN(p_li->li_tv.vval.v_string); if (len > CMDBUFFSIZE - 2) - len = CMDBUFFSIZE - 2; + { + if (linelen > LINE_MAXLEN) + linelen = LINE_MAXLEN - 1; + if (growbuf == NULL) + { + growbuf = alloc(linelen); + growbufsiz = linelen; + } + else if (linelen > growbufsiz) + { + if ((growbuf = vim_realloc(growbuf, + linelen)) == NULL) + goto qf_init_end; + growbufsiz = linelen; + } + linebuf = growbuf; + } + else + { + linebuf = IObuff; + linelen = len; + } - vim_strncpy(IObuff, p_li->li_tv.vval.v_string,
Re: [patch] Add optiontype function
On Sun, Mar 27, 2016 at 06:11:10PM +0200, Anton Lindqvist wrote: > On Sat, Mar 26, 2016 at 04:52:47PM +0100, Bram Moolenaar wrote: > > > > Anton Lindqvist wrote: > > > > > > > Hi, > > > > > This patch adds a function with the declaration optiontype({option}) > > > > > which returns the type of the given option. I'm currently using it to > > > > > achieve the following option toggle mapping: > > > > > > > > > > " :NMapChangeOption[!] {letter} {option} [enable] > > > > > " > > > > > " Create a normal mode option toggle mapping for {option}. The > > > > > mapping key > > > > > " sequence will be prefixed with 'co' followed by {letter}. > > > > > " > > > > > " By default the option will only be changed in the current buffer. > > > > > Using [!] > > > > > " will change the option globally. > > > > > " > > > > > " Boolean option example: > > > > > " > > > > > " :NMapChangeOption s spell > > > > > " > > > > > " Pressing 'cos' will toggle the spell option on and off. > > > > > " > > > > > " Non boolean option example: > > > > > " > > > > > " :NMapChangeOption y syntax ON > > > > > " > > > > > " The optional [enable] argument can be used for string and comma > > > > > separated > > > > > " list options. Pressing 'coy' will add/remove 'ON' from the syntax > > > > > option. > > > > > " > > > > > " This functionality is borrowed from Tim Pope's unimpaired.vim > > > > > plugin. > > > > > command! -bang -complete=option -nargs=+ NMapChangeOption > > > > > \ call s:NMapChangeOption(0, ) > > > > > func! s:NMapChangeOption(global, letter, option, ...) abort > > > > > let set = a:global ? 'set' : 'setlocal' > > > > > let type = optiontype(a:option) > > > > > if type == 0 " boolean > > > > > let rhs = printf(':%s =&%s ? "no" : ""%s', > > > > > \ set, a:option, a:option) > > > > > elseif type == 2 " comma separated list > > > > > let rhs = printf(':%s %s=&%s !~# "%s" ? "+=" : > > > > > "-="%s', > > > > > \ set, a:option, a:option, a:1, a:1) > > > > > elseif type == 4 " string > > > > > let rhs = printf(':%s %s=&%s == "%s" ? "&" : > > > > > "=%s"', > > > > > \ set, a:option, a:option, a:1, a:1) > > > > > endif > > > > > exe 'nnoremap co' . a:letter rhs > > > > > endfunc > > > > > > > > > > NMapChangeOption c colorcolumn +1 > > > > > NMapChangeOption! h hlsearch > > > > > NMapChangeOption l list > > > > > NMapChangeOption! p paste > > > > > NMapChangeOption s spell > > > > > NMapChangeOption w wrap > > > > > NMapChangeOption y syntax ON > > > > > > > > > > The patch includes tests and docs. > > > > > > > > I can see how this would be useful. But returning just a number is > > > > limited. There are many more properties of an option, such as whether > > > > it is window-local, was set or not, can be set from a modeline, etc. > > > > Not that we need to add all those properties now, but I'm sure someone > > > > will want to add them later. Perhaps using "optionproperties()" and > > > > returning a Dictionary? > > > > > > Great feedback. Attached is a revised patch with you ideas applied. > > > For now the 'optionproperties()' function returns a Dictionary with only > > > one entry called 'type'. > > > > Thanks. I wonder if "type" would just return bool/number/string. Then > > for a string type there would be a subtype for comma/flaglist. > > I suppose it depends on what you want to do if you want to know what > > kind of string option it is. Also, if we later add another kind (colon > > separate?) that is also a string, it would still be possible to >
Re: [patch] Fix quickfix handling of long lines
On Sat, Apr 09, 2016 at 04:45:23PM +0200, Anton Lindqvist wrote: > On Tue, Apr 05, 2016 at 09:56:26PM +0200, Bram Moolenaar wrote: > > > > Anton Lindqvist wrote: > > > > > > > If a file passed to the 'qf_init_ext' function contains lines longer > > > > > than 1021 bytes (might be platform specific) the rest of the line is > > > > > recognized as a separate error without a valid filename and lnum. If a > > > > > string or list is passed to 'qf_init_ext' the rest of a long line is > > > > > discarded. This patch adds the same behavior while reading errors > > > > > from a > > > > > file. This is done by continue reading from the file in to a temporary > > > > > buffer until end-of-line is encountered. Could any existing general > > > > > purpose buffer with a known size be used instead of allocation a new > > > > > one? > > > > > > > > This code comes from when memory was scarce and error messages were > > > > short. Using a fixed size buffer isn't so nice these days. > > > > > > > > A good strategy could be to use IObuff as it is, and when an error > > > > message is longer then allocate a larger buffer and append to it. > > > > It does require growing (doubling?) the buffer further until a NL is > > > > found. That can be slow, e.g. if the error file has no NL at all > > > > (that's a mistake, but you don't want Vim to hang then). So some upper > > > > limit would still be useful. > > > > > > I would prefer allocating a buffer using BUFSIZ defined in stdio.h and > > > then make it grow exponentially. Instead of using a upper limit I would > > > prefer to continue reading until NL/EOF occurs or realloc fails. > > > > Well, if arbitrary long lines are supported, where would they be useful? > > Certainly not for displaying, it would scroll through many pages. > > Perhaps for a script that analizes the error further. But I find that a > > bit far fetched. I think a 100 Kbyte limit is very resonable. > > Especially since currently it's chopped up after 1 Kbyte. > > > > > > I have seen error messages from a test that say "expected > > > > but got ". Not sure what a useful > > > > upper limit would be. 100 Kbyte perhaps? > > > > > > Reading and displaying the whole line despite its length is a reasonable > > > behavior nowadays, however like marius@ pointed out I would not mind if > > > the lines where truncated since they seldom adds value. > > > > > > > Are you interested in implementing this? > > > > > > Sure! But what's your take on the concerns above? > > > > I think reading into IObuff at first, and using a growing buffer after > > that would be a good solution. Probably keep the buffer until all > > errors are done, if one line is long there is a bigger change of another > > one. > > Here's a first attempt on implementing the proposed changes. Some notes > regarding the patch in no particular order: > > - The maximum number of bytes per line is defined at compile-time using > LINE_MAXLEN. It's currently set a lower value than the proposed 100Kb > for the sake of testing but can easily be adjusted. If changed, the > tests needs to adjusted as well. > > - The behavior for long lines is consistent for all types of > invocations, reading from a file, list, string or buffer > > - The file `src/testdir/samples/quickfix.txt' is used for the tests. > Should it be placed somewhere else? > > - The following logic is removed: > > if ((efmp = vim_strrchr(IObuff, '\n')) != NULL) > *efmp = NUL; > > As far as I can tell this should never be true since any trailing > new-line character is removed from the buffer and reading always halts > on new-line which implies that only one new-line character can be > present in buffer at once. > > Feedback and testing would be much appreciated. I compiled the changes with a stricter set of flags and discovered two mixed signedness warnings. Fixed the attached patch. -- :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.
Re: [patch] Fix quickfix handling of long lines
On Tue, Apr 05, 2016 at 09:56:26PM +0200, Bram Moolenaar wrote: > > Anton Lindqvist wrote: > > > > > If a file passed to the 'qf_init_ext' function contains lines longer > > > > than 1021 bytes (might be platform specific) the rest of the line is > > > > recognized as a separate error without a valid filename and lnum. If a > > > > string or list is passed to 'qf_init_ext' the rest of a long line is > > > > discarded. This patch adds the same behavior while reading errors from a > > > > file. This is done by continue reading from the file in to a temporary > > > > buffer until end-of-line is encountered. Could any existing general > > > > purpose buffer with a known size be used instead of allocation a new > > > > one? > > > > > > This code comes from when memory was scarce and error messages were > > > short. Using a fixed size buffer isn't so nice these days. > > > > > > A good strategy could be to use IObuff as it is, and when an error > > > message is longer then allocate a larger buffer and append to it. > > > It does require growing (doubling?) the buffer further until a NL is > > > found. That can be slow, e.g. if the error file has no NL at all > > > (that's a mistake, but you don't want Vim to hang then). So some upper > > > limit would still be useful. > > > > I would prefer allocating a buffer using BUFSIZ defined in stdio.h and > > then make it grow exponentially. Instead of using a upper limit I would > > prefer to continue reading until NL/EOF occurs or realloc fails. > > Well, if arbitrary long lines are supported, where would they be useful? > Certainly not for displaying, it would scroll through many pages. > Perhaps for a script that analizes the error further. But I find that a > bit far fetched. I think a 100 Kbyte limit is very resonable. > Especially since currently it's chopped up after 1 Kbyte. > > > > I have seen error messages from a test that say "expected > > > but got ". Not sure what a useful > > > upper limit would be. 100 Kbyte perhaps? > > > > Reading and displaying the whole line despite its length is a reasonable > > behavior nowadays, however like marius@ pointed out I would not mind if > > the lines where truncated since they seldom adds value. > > > > > Are you interested in implementing this? > > > > Sure! But what's your take on the concerns above? > > I think reading into IObuff at first, and using a growing buffer after > that would be a good solution. Probably keep the buffer until all > errors are done, if one line is long there is a bigger change of another > one. Here's a first attempt on implementing the proposed changes. Some notes regarding the patch in no particular order: - The maximum number of bytes per line is defined at compile-time using LINE_MAXLEN. It's currently set a lower value than the proposed 100Kb for the sake of testing but can easily be adjusted. If changed, the tests needs to adjusted as well. - The behavior for long lines is consistent for all types of invocations, reading from a file, list, string or buffer - The file `src/testdir/samples/quickfix.txt' is used for the tests. Should it be placed somewhere else? - The following logic is removed: if ((efmp = vim_strrchr(IObuff, '\n')) != NULL) *efmp = NUL; As far as I can tell this should never be true since any trailing new-line character is removed from the buffer and reading always halts on new-line which implies that only one new-line character can be present in buffer at once. Feedback and testing would be much appreciated. -- :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/quickfix.c b/src/quickfix.c index 00762bd..e5be238 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -175,6 +175,11 @@ qf_init( } /* + * Maximum number of bytes allowed per line while reading a errorfile. + */ +#define LINE_MAXLEN 4096 + +/* * Read the errorfile "efile" into memory, line by line, building the error * list. * Alternative: when "efile" is null read errors from buffer "buf". @@ -197,8 +202,15 @@ qf_init_ext( { char_u *namebuf; char_u *errmsg; +i
Re: [patch] Add optional argument to bufwinnr to return all windows
On Sun, Feb 21, 2016 at 03:15:17PM +0100, Bram Moolenaar wrote: > > Anton Lindqvist wrote: > > > Hi, > > This patch adds an optional second argument to the bufwinnr function > > which if present returns all windows associated with the given buffer > > across all tabs. This is useful in order to determine if a buffer is > > present in several windows. I'm currently using this patch in order to > > get backspace to behave accordingly: if the current buffer is present in > > other windows than the current one, close the window, otherwise wipe the > > current buffer. > > > > nnoremap :call BufferClose() > > func BufferClose() > > if len(bufwinnr('%', 1)) > 1 > > wincmd c > > else > > bwipe > > endif > > endfunc > > > > I didn't end up using the FOR_ALL_TAB_WINDOWS macro since I needed to > > reset winnr and increment tabnr in the outer loop. > > Thanks. Seems useful. > > I have been thinking of adding a unique window number. Some plugins > have problems finding the right window after splitting and closing > windows. The current window number changes then, thus it requires > looping over windows to find the right window. Netrw had a bug related > to this. > > getwinid() ID of current winow > getwinnr({id}) window nr of {id} or -1 if not open > gettabnr({id}) tab page nr of {id} or -1 if not open > gotowin({id}) > > I wonder how this bufwinnr() change fits in. With the addition of the unique window IDs the returned tabnr and winnr from bufwinnr() can be used to retrieve the window ID using the new win_getid() function. Once the window ID is obtain all the new functions can be utilized. -- :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.
Re: [patch] Fix quickfix handling of long lines
Bram, On Mon, Apr 04, 2016 at 10:03:22PM +0200, Bram Moolenaar wrote: > > Anton Lindqvist wrote: > > > If a file passed to the 'qf_init_ext' function contains lines longer > > than 1021 bytes (might be platform specific) the rest of the line is > > recognized as a separate error without a valid filename and lnum. If a > > string or list is passed to 'qf_init_ext' the rest of a long line is > > discarded. This patch adds the same behavior while reading errors from a > > file. This is done by continue reading from the file in to a temporary > > buffer until end-of-line is encountered. Could any existing general > > purpose buffer with a known size be used instead of allocation a new > > one? > > This code comes from when memory was scarce and error messages were > short. Using a fixed size buffer isn't so nice these days. > > A good strategy could be to use IObuff as it is, and when an error > message is longer then allocate a larger buffer and append to it. > It does require growing (doubling?) the buffer further until a NL is > found. That can be slow, e.g. if the error file has no NL at all > (that's a mistake, but you don't want Vim to hang then). So some upper > limit would still be useful. I would prefer allocating a buffer using BUFSIZ defined in stdio.h and then make it grow exponentially. Instead of using a upper limit I would prefer to continue reading until NL/EOF occurs or realloc fails. > I have seen error messages from a test that say "expected > but got ". Not sure what a useful > upper limit would be. 100 Kbyte perhaps? Reading and displaying the whole line despite its length is a reasonable behavior nowadays, however like marius@ pointed out I would not mind if the lines where truncated since they seldom adds value. > Are you interested in implementing this? Sure! But what's your take on the concerns above? -- :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.
[patch] Fix quickfix handling of long lines
Hi, If a file passed to the 'qf_init_ext' function contains lines longer than 1021 bytes (might be platform specific) the rest of the line is recognized as a separate error without a valid filename and lnum. If a string or list is passed to 'qf_init_ext' the rest of a long line is discarded. This patch adds the same behavior while reading errors from a file. This is done by continue reading from the file in to a temporary buffer until end-of-line is encountered. Could any existing general purpose buffer with a known size be used instead of allocation a new one? -- :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/alloc.h b/src/alloc.h index 90a9878..f1a9bd2 100644 --- a/src/alloc.h +++ b/src/alloc.h @@ -17,5 +17,6 @@ typedef enum { aid_qf_namebuf, aid_qf_errmsg, aid_qf_pattern, + aid_qf_discard, aid_last } alloc_id_T; diff --git a/src/quickfix.c b/src/quickfix.c index 00762bd..739fc89 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -198,6 +198,7 @@ qf_init_ext( char_u *namebuf; char_u *errmsg; char_u *pattern; +char_u *discard; char_u *fmtstr = NULL; intcol = 0; char_u use_viscol = FALSE; @@ -216,6 +217,7 @@ qf_init_ext( char_u *efm; char_u *ptr; char_u *srcptr; +intbuflen; intlen; inti; intround; @@ -252,7 +254,8 @@ qf_init_ext( namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf); errmsg = alloc_id(CMDBUFFSIZE + 1, aid_qf_errmsg); pattern = alloc_id(CMDBUFFSIZE + 1, aid_qf_pattern); -if (namebuf == NULL || errmsg == NULL || pattern == NULL) +discard = alloc_id(CMDBUFFSIZE + 1, aid_qf_discard); +if (namebuf == NULL || errmsg == NULL || pattern == NULL || discard == NULL) goto qf_init_end; if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL) @@ -557,8 +560,31 @@ qf_init_ext( CMDBUFFSIZE - 2); } } - else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL) - break; + else + { + if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL) + break; + + buflen = (int)STRLEN(IObuff); + while (buflen == CMDBUFFSIZE - 2 - 1) + { + /* +* End-of-line not yet reached since the number of read bytes is +* equal to the size of the buffer, excluding null-terminator. +* Continue reading and discard the rest of the line. +*/ + if (fgets((char *)discard, CMDBUFFSIZE - 2, fd) == NULL) + break; + + buflen = (int)STRLEN(discard); + if (discard[buflen - 1] == '\n' +#ifdef USE_CRNL + || discard[buflen - 1] == '\r' +#endif + ) + break; + } + } IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */ #ifdef FEAT_MBYTE @@ -878,6 +904,7 @@ qf_init_end: vim_free(errmsg); vim_free(pattern); vim_free(fmtstr); +vim_free(discard); #ifdef FEAT_WINDOWS qf_update_buffer(qi); diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 8da1b6f..df2c0a0 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -697,3 +697,14 @@ func Test_cgetexpr_works() " this must not crash Vim cgetexpr [$x] endfunc + +func Test_cgetfile_long_lines() + let tmp = tempname() + exe 'new' tmp + normal ifile:1: + normal $2000aa + w | bw + exe 'cgetfile' fnameescape(tmp) + call assert_equal(1, len(getqflist())) + call assert_true(len(getqflist()[0].text) < 2000) +endfunc
[patch] Add missing errorformat to GCC compiler
Hi, I contacted the maintainer of the gcc.vim compiler without any response. I'm currently using the gcc.vim compiler with g:compiler_gcc_ignore_unmatched_lines enabled. A linker error did not get recognized as an error on my machine using GCC 4.2.1 on OpenBSD. Output from GCC: cc -O2 -pipe -pedantic -std=c99 -Wall -Werror -Wextra -o bug bug.c /tmp//cck5iAWg.o: In function `main': bug.c:(.text+0x5): undefined reference to `foo' collect2: ld returned 1 exit status *** Error 1 in /home/a (:85 'bug') Attached is a patch including an attempt to resolve this issue. -- :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/runtime/compiler/gcc.vim b/runtime/compiler/gcc.vim index aee31d9..b3150e8 100644 --- a/runtime/compiler/gcc.vim +++ b/runtime/compiler/gcc.vim @@ -24,6 +24,7 @@ CompilerSet errorformat= \%f:%l:\ %trror:\ %m, \%f:%l:\ %tarning:\ %m, \%f:%l:\ %m, + \%f:\\(%*[^\\)]\\):\ %m, \\"%f\"\\,\ line\ %l%*\\D%c%*[^\ ]\ %m, \%D%*\\a[%*\\d]:\ Entering\ directory\ [`']%f', \%X%*\\a[%*\\d]:\ Leaving\ directory\ [`']%f',
Re: [patch] Add optiontype function
On Sat, Mar 26, 2016 at 04:52:47PM +0100, Bram Moolenaar wrote: > > Anton Lindqvist wrote: > > > > > Hi, > > > > This patch adds a function with the declaration optiontype({option}) > > > > which returns the type of the given option. I'm currently using it to > > > > achieve the following option toggle mapping: > > > > > > > > " :NMapChangeOption[!] {letter} {option} [enable] > > > > " > > > > " Create a normal mode option toggle mapping for {option}. The > > > > mapping key > > > > " sequence will be prefixed with 'co' followed by {letter}. > > > > " > > > > " By default the option will only be changed in the current buffer. > > > > Using [!] > > > > " will change the option globally. > > > > " > > > > " Boolean option example: > > > > " > > > > " :NMapChangeOption s spell > > > > " > > > > " Pressing 'cos' will toggle the spell option on and off. > > > > " > > > > " Non boolean option example: > > > > " > > > > " :NMapChangeOption y syntax ON > > > > " > > > > " The optional [enable] argument can be used for string and comma > > > > separated > > > > " list options. Pressing 'coy' will add/remove 'ON' from the syntax > > > > option. > > > > " > > > > " This functionality is borrowed from Tim Pope's unimpaired.vim > > > > plugin. > > > > command! -bang -complete=option -nargs=+ NMapChangeOption > > > > \ call s:NMapChangeOption(0, ) > > > > func! s:NMapChangeOption(global, letter, option, ...) abort > > > > let set = a:global ? 'set' : 'setlocal' > > > > let type = optiontype(a:option) > > > > if type == 0 " boolean > > > > let rhs = printf(':%s =&%s ? "no" : ""%s', > > > > \ set, a:option, a:option) > > > > elseif type == 2 " comma separated list > > > > let rhs = printf(':%s %s=&%s !~# "%s" ? "+=" : > > > > "-="%s', > > > > \ set, a:option, a:option, a:1, a:1) > > > > elseif type == 4 " string > > > > let rhs = printf(':%s %s=&%s == "%s" ? "&" : "=%s"', > > > > \ set, a:option, a:option, a:1, a:1) > > > > endif > > > > exe 'nnoremap co' . a:letter rhs > > > > endfunc > > > > > > > > NMapChangeOption c colorcolumn +1 > > > > NMapChangeOption! h hlsearch > > > > NMapChangeOption l list > > > > NMapChangeOption! p paste > > > > NMapChangeOption s spell > > > > NMapChangeOption w wrap > > > > NMapChangeOption y syntax ON > > > > > > > > The patch includes tests and docs. > > > > > > I can see how this would be useful. But returning just a number is > > > limited. There are many more properties of an option, such as whether > > > it is window-local, was set or not, can be set from a modeline, etc. > > > Not that we need to add all those properties now, but I'm sure someone > > > will want to add them later. Perhaps using "optionproperties()" and > > > returning a Dictionary? > > > > Great feedback. Attached is a revised patch with you ideas applied. > > For now the 'optionproperties()' function returns a Dictionary with only > > one entry called 'type'. > > Thanks. I wonder if "type" would just return bool/number/string. Then > for a string type there would be a subtype for comma/flaglist. > I suppose it depends on what you want to do if you want to know what > kind of string option it is. Also, if we later add another kind (colon > separate?) that is also a string, it would still be possible to > recognize the string if you don't care about the subtype. It guess it makes sense to assume that in the general use-case one is only interested of the primitive type of a option, therefore bool/number/string is sufficient. The attached patch adds two new entries to the returned dictionary: 'comma' and 'flaglist'. -- :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,
Re: [patch] Add optiontype function
Bram, On Thu, Mar 24, 2016 at 06:44:39PM +0100, Bram Moolenaar wrote: > > Anton Lindqvist wrote: > > > Hi, > > This patch adds a function with the declaration optiontype({option}) > > which returns the type of the given option. I'm currently using it to > > achieve the following option toggle mapping: > > > > " :NMapChangeOption[!] {letter} {option} [enable] > > " > > " Create a normal mode option toggle mapping for {option}. The mapping key > > " sequence will be prefixed with 'co' followed by {letter}. > > " > > " By default the option will only be changed in the current buffer. Using > > [!] > > " will change the option globally. > > " > > " Boolean option example: > > " > > " :NMapChangeOption s spell > > " > > " Pressing 'cos' will toggle the spell option on and off. > > " > > " Non boolean option example: > > " > > " :NMapChangeOption y syntax ON > > " > > " The optional [enable] argument can be used for string and comma > > separated > > " list options. Pressing 'coy' will add/remove 'ON' from the syntax > > option. > > " > > " This functionality is borrowed from Tim Pope's unimpaired.vim plugin. > > command! -bang -complete=option -nargs=+ NMapChangeOption > > \ call s:NMapChangeOption(0, ) > > func! s:NMapChangeOption(global, letter, option, ...) abort > > let set = a:global ? 'set' : 'setlocal' > > let type = optiontype(a:option) > > if type == 0 " boolean > > let rhs = printf(':%s =&%s ? "no" : ""%s', > > \ set, a:option, a:option) > > elseif type == 2 " comma separated list > > let rhs = printf(':%s %s=&%s !~# "%s" ? "+=" : "-="%s', > > \ set, a:option, a:option, a:1, a:1) > > elseif type == 4 " string > > let rhs = printf(':%s %s=&%s == "%s" ? "&" : "=%s"', > > \ set, a:option, a:option, a:1, a:1) > > endif > > exe 'nnoremap co' . a:letter rhs > > endfunc > > > > NMapChangeOption c colorcolumn +1 > > NMapChangeOption! h hlsearch > > NMapChangeOption l list > > NMapChangeOption! p paste > > NMapChangeOption s spell > > NMapChangeOption w wrap > > NMapChangeOption y syntax ON > > > > The patch includes tests and docs. > > I can see how this would be useful. But returning just a number is > limited. There are many more properties of an option, such as whether > it is window-local, was set or not, can be set from a modeline, etc. > Not that we need to add all those properties now, but I'm sure someone > will want to add them later. Perhaps using "optionproperties()" and > returning a Dictionary? Great feedback. Attached is a revised patch with you ideas applied. For now the 'optionproperties()' function returns a Dictionary with only one entry called 'type'. -- :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/runtime/doc/eval.txt b/runtime/doc/eval.txt index 642f0ad..3087938 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2023,6 +2023,7 @@ mode( [expr]) String current editing mode mzeval( {expr})any evaluate |MzScheme| expression nextnonblank( {lnum}) Number line nr of non-blank line >= {lnum} nr2char( {expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr} +optionproperties( {option})Dictproperties of option {option} or( {expr}, {expr})Number bitwise OR pathshorten( {expr}) String shorten directory names in a path perleval( {expr}) any evaluate |Perl| expression @@ -5316,6 +5317,20 @@ nr2char({expr}[, {utf8}]) *nr2char()* characters. nr2char(0) is a real NUL and terminates the string, thus results in an empty string. + *E518* +optionproperties({option}) *optionproperties()* + Ret
[patch] Add optiontype function
Hi, This patch adds a function with the declaration optiontype({option}) which returns the type of the given option. I'm currently using it to achieve the following option toggle mapping: " :NMapChangeOption[!] {letter} {option} [enable] " " Create a normal mode option toggle mapping for {option}. The mapping key " sequence will be prefixed with 'co' followed by {letter}. " " By default the option will only be changed in the current buffer. Using [!] " will change the option globally. " " Boolean option example: " " :NMapChangeOption s spell " " Pressing 'cos' will toggle the spell option on and off. " " Non boolean option example: " " :NMapChangeOption y syntax ON " " The optional [enable] argument can be used for string and comma separated " list options. Pressing 'coy' will add/remove 'ON' from the syntax option. " " This functionality is borrowed from Tim Pope's unimpaired.vim plugin. command! -bang -complete=option -nargs=+ NMapChangeOption \ call s:NMapChangeOption(0, ) func! s:NMapChangeOption(global, letter, option, ...) abort let set = a:global ? 'set' : 'setlocal' let type = optiontype(a:option) if type == 0 " boolean let rhs = printf(':%s =&%s ? "no" : ""%s', \ set, a:option, a:option) elseif type == 2 " comma separated list let rhs = printf(':%s %s=&%s !~# "%s" ? "+=" : "-="%s', \ set, a:option, a:option, a:1, a:1) elseif type == 4 " string let rhs = printf(':%s %s=&%s == "%s" ? "&" : "=%s"', \ set, a:option, a:option, a:1, a:1) endif exe 'nnoremap co' . a:letter rhs endfunc NMapChangeOption c colorcolumn +1 NMapChangeOption! h hlsearch NMapChangeOption l list NMapChangeOption! p paste NMapChangeOption s spell NMapChangeOption w wrap NMapChangeOption y syntax ON The patch includes tests and docs. -- :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/runtime/doc/eval.txt b/runtime/doc/eval.txt index 642f0ad..f411beb 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2023,6 +2023,7 @@ mode( [expr]) String current editing mode mzeval( {expr})any evaluate |MzScheme| expression nextnonblank( {lnum}) Number line nr of non-blank line >= {lnum} nr2char( {expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr} +optiontype( {option}) Number type of option {option} or( {expr}, {expr})Number bitwise OR pathshorten( {expr}) String shorten directory names in a path perleval( {expr}) any evaluate |Perl| expression @@ -5316,6 +5317,15 @@ nr2char({expr}[, {utf8}]) *nr2char()* characters. nr2char(0) is a real NUL and terminates the string, thus results in an empty string. +optiontype({option}) *optiontype()* *E518* + Return the type of {option} as a Number: +Boolean: 0 + Number: 1 + Comma separated list: 2 + Char flag list: 3 + String: 4 + If {option} does not exist, -1 is returned. + or({expr}, {expr}) *or()* Bitwise OR on the two arguments. The arguments are converted to a number. A List, Dict or Float argument causes an error. diff --git a/src/eval.c b/src/eval.c index b233833..38533d8 100644 --- a/src/eval.c +++ b/src/eval.c @@ -682,6 +682,7 @@ static void f_mzeval(typval_T *argvars, typval_T *rettv); static void f_nextnonblank(typval_T *argvars, typval_T *rettv); static void f_nr2char(typval_T *argvars, typval_T *rettv); static void f_or(typval_T *argvars, typval_T *rettv); +static void f_optiontype(typval_T *argvars, typval_T *rettv); static void f_pathshorten(typval_T *argvars, typval_T *rettv); #ifdef FEAT_PERL static void f_perleval(typval_T *argvars, typval_T *rettv); @@ -8327,6 +8328,7 @@ static struct fst {"nextnonblank", 1, 1, f_nextnonblank}, {"nr2char",1, 2, f_nr2char}, {"or", 2, 2, f_or}, +{"optiontype", 1, 1, f_optiontype}, {"pathshorten",1, 1, f_pathshorten}, #ifdef FEAT_PERL {"perleval", 1, 1, f_perleval}, @@ -15901,6 +15903,22 @@ f_or(typval_T *argvars, typval_T *rettv) } /* + * "optiontype(option)" function + */ +static void
Re: [patch] Add Error autocmd event
On Thu, Feb 25, 2016 at 10:17:34PM +0100, Bram Moolenaar wrote: > > Anton Lindqvist wrote: > > > Bram, > > I noticed your comment in todo.txt about the fact that the current > > solution only remembers the code of last error that occurred. Here's a > > first attempt address this issue by using an growarray. Caution: I don't > > know if it's wise to clear the array in the main loop. > > Thanks. However, I still have doubts about how useful this is. > Autocommands are tricky as they are, and this one is more tricky then > others. > > It's not that I don't like your work, I just don't want to make a > promise to users, which means once this is in we'll have to keep it > around forever. Even when we find a better solution eventually. Sounds reasonable and I respect your judgment. -- :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.
Re: [patch] Add Error autocmd event
Bram, I noticed your comment in todo.txt about the fact that the current solution only remembers the code of last error that occurred. Here's a first attempt address this issue by using an growarray. Caution: I don't know if it's wise to clear the array in the main loop. -- :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..aaed5cb 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 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,23 @@ write_eintr(int fd, void *buf, size_t bufsize) return ret; } #endif + +#ifdef FEAT_AUTOCMD +/* + * Get the corresponding pattern for the given error message code. The returned + * value is used for 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; +} +#endif diff --git a/src/globals.h b/src/globals.h index 4c1b41f..cb46510 100644 --- a/src/globals.h +++ b/src/globals.h @@ -184,6 +184,11 @@ 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 garray_T emsg_codes; /* grow array containing the latest + error message codes 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..6edc369 100644 --- a/src/main.c +++ b/src/main.c @@ -1278,6 +1278,22 @@ main_loop( fileinfo(FALSE, TRUE, FALSE); need_fileinfo = FALSE; } +#ifdef FEAT_AUTOCMD + if (emsg_codes.ga_len) { + for (int i = 0; i < emsg_codes.ga_len; ++i) + { + char_u *code = ((char_u
Re: [patch] Add Error autocmd event
Realized I was using my personal preference for cinoptions. Here's a revised patch with correct indentation. -- :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..aaed5cb 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 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,23 @@ write_eintr(int fd, void *buf, size_t bufsize) return ret; } #endif + +#ifdef FEAT_AUTOCMD +/* + * Get the corresponding pattern for the given error message code. The returned + * value is used for 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; +} +#endif 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..43671e9 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,
Re: [patch] Add optional argument to bufwinnr to return all windows
On Sun, Feb 21, 2016 at 03:15:17PM +0100, Bram Moolenaar wrote: > > Anton Lindqvist wrote: > > > Hi, > > This patch adds an optional second argument to the bufwinnr function > > which if present returns all windows associated with the given buffer > > across all tabs. This is useful in order to determine if a buffer is > > present in several windows. I'm currently using this patch in order to > > get backspace to behave accordingly: if the current buffer is present in > > other windows than the current one, close the window, otherwise wipe the > > current buffer. > > > > nnoremap :call BufferClose() > > func BufferClose() > > if len(bufwinnr('%', 1)) > 1 > > wincmd c > > else > > bwipe > > endif > > endfunc > > > > I didn't end up using the FOR_ALL_TAB_WINDOWS macro since I needed to > > reset winnr and increment tabnr in the outer loop. > > Thanks. Seems useful. > > I have been thinking of adding a unique window number. Some plugins > have problems finding the right window after splitting and closing > windows. The current window number changes then, thus it requires > looping over windows to find the right window. Netrw had a bug related > to this. > > getwinid() ID of current winow > getwinnr({id}) window nr of {id} or -1 if not open > gettabnr({id}) tab page nr of {id} or -1 if not open > gotowin({id}) > > I wonder how this bufwinnr() change fits in. Unique window numbers sounds like a great addition. The bufwinnr() function could then return a list unique window numbers instead of a list of dictionaries. If the window number is unique it should be all the data needed in order to interact/manipulate the window using the functions mentioned. -- :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.
[patch] Add optional argument to bufwinnr to return all windows
Hi, This patch adds an optional second argument to the bufwinnr function which if present returns all windows associated with the given buffer across all tabs. This is useful in order to determine if a buffer is present in several windows. I'm currently using this patch in order to get backspace to behave accordingly: if the current buffer is present in other windows than the current one, close the window, otherwise wipe the current buffer. nnoremap :call BufferClose() func BufferClose() if len(bufwinnr('%', 1)) > 1 wincmd c else bwipe endif endfunc I didn't end up using the FOR_ALL_TAB_WINDOWS macro since I needed to reset winnr and increment tabnr in the outer loop. -- :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/runtime/doc/eval.txt b/runtime/doc/eval.txt index 9ec893f..3bcac94 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2436,7 +2436,7 @@ bufnr({expr} [, {create}]) *last_buffer_nr()* Obsolete name for bufnr("$"): last_buffer_nr(). -bufwinnr({expr}) *bufwinnr()* +bufwinnr({expr} [, {all}]) *bufwinnr()* The result is a Number, which is the number of the first window associated with buffer {expr}. For the use of {expr}, see |bufname()| above. If buffer {expr} doesn't exist or @@ -2446,7 +2446,16 @@ bufwinnr({expr}) *bufwinnr()* < The number can be used with |CTRL-W_w| and ":wincmd w" |:wincmd|. - Only deals with the current tab page. + If the {all} argument is present and not zero a list including + all windows associated with buffer {expr} across all tabs is + returned. Each list item is a dictionary with these entries: + tabnr number of the tab the window is associated +with + winnr number of the window associated with buffer +{expr} + + If buffer {expr} doesn't exist or there is no such window, a + empty list is returned. byte2line({byte}) *byte2line()* Return the line number that contains the character at byte diff --git a/src/eval.c b/src/eval.c index 781cd3d..3e330aa 100644 --- a/src/eval.c +++ b/src/eval.c @@ -8115,7 +8115,7 @@ static struct fst {"bufloaded", 1, 1, f_bufloaded}, {"bufname", 1, 1, f_bufname}, {"bufnr", 1, 2, f_bufnr}, -{"bufwinnr", 1, 1, f_bufwinnr}, +{"bufwinnr", 1, 2, f_bufwinnr}, {"byte2line", 1, 1, f_byte2line}, {"byteidx", 2, 2, f_byteidx}, {"byteidxcomp", 2, 2, f_byteidxcomp}, @@ -9666,7 +9666,11 @@ f_bufnr(typval_T *argvars, typval_T *rettv) f_bufwinnr(typval_T *argvars, typval_T *rettv) { #ifdef FEAT_WINDOWS +tabpage_T *tp; win_T *wp; +dict_T *dict; +int error = FALSE; +int tabnr = 0; int winnr = 0; #endif buf_T *buf; @@ -9675,13 +9679,40 @@ f_bufwinnr(typval_T *argvars, typval_T *rettv) ++emsg_off; buf = get_buf_tv([0], TRUE); #ifdef FEAT_WINDOWS -for (wp = firstwin; wp; wp = wp->w_next) +if (argvars[1].v_type != VAR_UNKNOWN + && get_tv_number_chk([1], ) != 0 + && !error) { - ++winnr; - if (wp->w_buffer == buf) - break; + if (rettv_list_alloc(rettv) == FAIL) + return; + for (tp = first_tabpage; tp; tp = tp->tp_next) { + ++tabnr; + winnr = 0; + for (wp = tp == curtab ? firstwin : tp->tp_firstwin; + wp; + wp = wp->w_next) + { + ++winnr; + if (wp->w_buffer == buf) + if ((dict = dict_alloc()) == NULL + || list_append_dict(rettv->vval.v_list, +dict) == FAIL + || dict_add_nr_str(dict, "tabnr", (long)tabnr, +NULL) == FAIL + || dict_add_nr_str(dict, "winnr", (long)winnr, +NULL) == FAIL) + return; + } + } +} else { + for (wp = firstwin; wp; wp = wp->w_next) + { + ++winnr; + if (wp->w_buffer == buf) + break; + } + rettv->vval.v_number = (wp != NULL ? winnr : -1); } -rettv->vval.v_number = (wp != NULL ? winnr : -1); #else rettv->vval.v_number = (curwin->w_buffer == buf ? 1 : -1); #endif
Re: [patch] Add Error autocmd event
Updated patch attached which adds a missing autocmd feature check. -- :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..aaed5cb 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 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,23 @@ write_eintr(int fd, void *buf, size_t bufsize) return ret; } #endif + +#ifdef FEAT_AUTOCMD +/* + * Get the corresponding pattern for the given error message code. The returned + * value is used for 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; +} +#endif 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); + +
Re: [patch] Add Error autocmd event
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 n ToggleWrapScan('n') nnoremap N 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 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 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
Re: [patch] Add Error autocmd event
Bram, On Mon, Feb 08, 2016 at 10:57:37PM +0100, Bram Moolenaar wrote: > > Anton Lindqvist wrote: > > > This is a result of a previous discussion[1] which concluded that a > > more general Error autocmd event would be a better addition than the > > proposed TagNotFound event. > > > > Questions and comments regarding the patch in no particular order: > > > > - Is the addition to the main_loop function at a suitable location? > > > > - The error code (emsg_code) is the actual code including the 'E' prefix. > > Another solution is to use the numerical representation of the error code. > > > > - The get_error_pat function is used to translate error codes into something > > more descriptive. As of writing this only one such mapping is > > present. We could either ensure that all possible error codes has a > > mapping or add them on demand. The function is doing a linear search > > of error_pats. If the error code is represented as an int this could > > be replaced with a constant lookup if the array index is equal to > > the error code: > > > > static const char *error_pat[] = { > > [426] = "tagnotfound", > > } > > > > If mappings of all possible error codes is present the array won't end up > > being that sparse. > > > > The existing solution (representing error codes as string) could also be > > improved by replacing the linear search with a binary search. > > > > - If no mapping of the error code to pattern is found the actual error > > code is used as the amatch argument when triggering the Error event. > > > > [1] https://groups.google.com/d/msg/vim_dev/XzhNNjbtfow/u6BWsne4CwAJ > > I am wondering if this is really a useful solution. > > At least in scripts one can already use try/catch to deal with errors. > Thus this patch is mainly for when typing commands. > > The original reason was to handle an error for a tag lookup. With the > solution the tag lookup will still fail. It can trigger rebuilding the > tags file, but for most users it will be quite unexpected that trying to > jump to the same tag suddenly works a bit later. The creation of the tags file when missing was just an example of a use-case of my own and is of course a opt-in usage of the new event. > Can you think of a command or situation where this patch provides a > nice, useful solution? Other than the examples already provided, here's a couple of ideas: - Opening a new file in a non existing directory and then write triggers a E212 which could be caught and then before writing again try to create the directory (%:h) of the file. - The SpellFileMissing autocmd event could probably be implemented using the Error event instead. However this might not a suitable idea since it would require keeping the old event for backwards compability. -- :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.
Re: [patch] Add TagNotFound autocmd event
Hi, See the new patch[1]. [1] https://groups.google.com/d/msg/vim_dev/3_Mn38Jk3N0/W3TQ0g1WDQAJ On Sat, Feb 06, 2016 at 03:28:37PM +0100, Bram Moolenaar wrote: > > Anton Lindqvist wrote: > > > On Thu, Feb 04, 2016 at 09:36:21PM +0100, Christian Brabandt wrote: > > > While I agree that this is useful, I have been thinking, if a more > > > general approach would not be more useful. Something like an Error > > > autocommand, that triggers on the EXXX numbers? > > > > I really like this idea, especially if would be the actual > > error message since it would allow people to get creative. Having > > limited experience with the Vim codebase: would it be feasible to > > trigger the autocmd event somewhere along the call stack for the emsg > > functions? At first glance it looks like that solution would require > > less changes. Compared to adding a explicit call to apply_autocmds > > prior calling any of the emsg functions. > > Although this sounds like a nice general solution, it will require the > code that gives the error message to be prepared for an autocommand > kicking in. Otherwise, whatever the autocommand does may completely > mess up what the code was doing. We have had many autocommands cause > trouble and still fixing more. > > So the code would explicitly check for an autocommand that handles the > error. And since we need to do that, we might as well use a nicer name > than the error number. That also helps for when there can be multiple > errors. E.g. "tagnotfound" is much nicer than matching a list of error > codes. And more error codes could be added later. > > An alternative would be to match the error code, but not trigger the > autocommand yet. In the main loop we can then check for the matches > and execute the autocommand. That is a lot safer and simpler. > > Nevertheless, you probably want to do something more clever, since after > rebuilding the tags file you would want to search for a match again. > > -- > hundred-and-one symptoms of being an internet addict: > 151. You find yourself engaged to someone you've never actually met, > except through e-mail. > > /// Bram Moolenaar -- b...@moolenaar.net -- http://www.Moolenaar.net \\\ > ///sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ > \\\ an exciting new programming language -- http://www.Zimbu.org/// > \\\help me help AIDS victims -- http://ICCF-Holland.org/// -- :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.
Re: [patch] Add TagNotFound autocmd event
On Thu, Feb 04, 2016 at 10:04:44PM +0100, Christian Brabandt wrote: > On Do, 04 Feb 2016, Anton Lindqvist wrote: > > > On Thu, Feb 04, 2016 at 09:36:21PM +0100, Christian Brabandt wrote: > > > While I agree that this is useful, I have been thinking, if a more > > > general approach would not be more useful. Something like an Error > > > autocommand, that triggers on the EXXX numbers? > > > > I really like this idea, especially if would be the actual > > error message since it would allow people to get creative. Having > > limited experience with the Vim codebase: would it be feasible to > > trigger the autocmd event somewhere along the call stack for the emsg > > functions? At first glance it looks like that solution would require > > less changes. Compared to adding a explicit call to apply_autocmds > > prior calling any of the emsg functions. > > That's what my half working patch did. It is here: > https://github.com/chrisbra/vim-mq-patches/blob/master/error_aucmd > you might want to look into it. Never got around finishing it. Christian, I am able to apply your patch and it works fine. Here's an example of a potential use-case of mine: " Run ctags if the tag file is missing (E433) or the tag was not found (E426) augroup ctags au! Error E4\(26\|33\)* silent exe '!ctags' augroup END Are you aware of any bugs with your patch or other potential gotchas that needs to be resolved? -- :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.
Re: [patch] Add TagNotFound autocmd event
On Thu, Feb 04, 2016 at 10:04:44PM +0100, Christian Brabandt wrote: > That's what my half working patch did. It is here: > https://github.com/chrisbra/vim-mq-patches/blob/master/error_aucmd > you might want to look into it. Never got around finishing it. Thanks, I will try to finish your patch. -- :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.
Re: [patch] Add TagNotFound autocmd event
Christian, On Thu, Feb 04, 2016 at 09:36:21PM +0100, Christian Brabandt wrote: > While I agree that this is useful, I have been thinking, if a more > general approach would not be more useful. Something like an Error > autocommand, that triggers on the EXXX numbers? I really like this idea, especially if would be the actual error message since it would allow people to get creative. Having limited experience with the Vim codebase: would it be feasible to trigger the autocmd event somewhere along the call stack for the emsg functions? At first glance it looks like that solution would require less changes. Compared to adding a explicit call to apply_autocmds prior calling any of the emsg functions. -- :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.
[patch] Add TagNotFound autocmd event
Hi, This patch add a autocmd event called TagNotFound triggered when the requested tag was not found. The motivation for this event is as follows: I usually add the following to my vimrc in order to ensure my tags file is up-to-date: au BufWritePost * if filereadable('tags') | silent exe '!ctags -a %' | endif However this seems wasteful since the majority of my writes don't include new identifiers to be indexed. With this patch the command above could be replaced with: au TagNotFound * if filereadable('tags') | silent exe '!ctags' | endif Thus indexing would only be performed when a missing tag is requested. Another use-case for this new event would be to trigger a psearch when the tag was not found: au TagNotFound * exe 'psearch /' . expand('') . '/' BTW: what's the recommended cinoptions for the Vim codebase? -- -- 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/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 4de5b16..06f1578 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -284,6 +284,7 @@ Name triggered by ~ |SpellFileMissing| a spell file is used but it can't be found |SourcePre| before sourcing a Vim script |SourceCmd| before sourcing a Vim script |Cmd-event| +|TagNotFound| the tag was not found in the tag file(s) |VimResized| after the Vim window size changed |FocusGained| Vim got input focus @@ -879,6 +880,10 @@ TabEnter Just after entering a tab page. |tab-page| TabLeave Just before leaving a tab page. |tab-page| A WinLeave event will have been triggered first. + *TagNotFound* +TagNotFound When the requested tag was not found in the +tag file(s). The pattern is matched against +the tag name. is the tag name. *TermChanged* TermChanged After the value of 'term' has changed. Useful for re-loading the syntax file to update the diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt index 8186678..55d8d97 100644 --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -820,7 +820,8 @@ Note: these are typed literally, they are not special keys! When executing autocommands, is replaced with the match for which this autocommand was executed. It differs from only when the file name isn't used to match with - (for FileType, Syntax and SpellFileMissing events). + (for FileType, Syntax, SpellFileMissing and TagNotFound + events). When executing a ":source" command, is replaced with the file name of the sourced file. *E498* When executing a function, is replaced with: diff --git a/src/Makefile b/src/Makefile index 8fd59fb..1a65333 100644 --- a/src/Makefile +++ b/src/Makefile @@ -565,7 +565,7 @@ CClink = $(CC) # When using -g with some older versions of Linux you might get a # statically linked executable. # When not defined, configure will try to use -O2 -g for gcc and -O for cc. -#CFLAGS = -g +CFLAGS = -g -O0 #CFLAGS = -O # Optimization limits - depends on the compiler. Automatic check in configure @@ -1108,7 +1108,7 @@ INSTALL_DATA_R = cp -r ### Program to run on installed binary. Use the second one to disable strip. #STRIP = strip -[7m#[27mSTRIP = /bin/true +[7m[27mSTRIP = /bin/true ### Permissions for binaries {{{1 BINMOD = 755 diff --git a/src/fileio.c b/src/fileio.c index ecec757..fa2ec72 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -7711,6 +7711,7 @@ static struct event_name {"Syntax", EVENT_SYNTAX}, {"TabEnter", EVENT_TABENTER}, {"TabLeave", EVENT_TABLEAVE}, +{"TagNotFound", EVENT_TAGNOTFOUND}, {"TermChanged", EVENT_TERMCHANGED}, {"TermResponse", EVENT_TERMRESPONSE}, {"TextChanged", EVENT_TEXTCHANGED}, @@ -9357,6 +9358,7 @@ apply_autocmds_group( || event == EVENT_FUNCUNDEFINED || event == EVENT_REMOTEREPLY || event == EVENT_SPELLFILEMISSING + || event == EVENT_TAGNOTFOUND || event == EVENT_QUICKFIXCMDPRE || event == EVENT_COLORSCHEME || event == EVENT_OPTIONSET diff --git a/src/tag.c b/src/tag.c index d2fdee6..b24212e 100644 --- a/src/tag.c +++ b/src/tag.c @@ -569,6 +569,10 @@ do_tag( if (num_matches <= 0) { +#ifdef FEAT_AUTOCMD + apply_autocmds(EVENT_TAGNOTFOUND, name, curbuf->b_fname, + FALSE, curbuf); +#endif if (verbose) EMSG2(_("E426: tag not found: %s"), name); #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) diff --git a/src/vim.h b/src/vim.h index 18610f5..80491d0 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1314,6 +1314,7 @@ enum auto_event EVENT_TEXTCHANGEDI, /* text was modified in Insert
Re: [patch] Add TagNotFound autocmd event
Den onsdag 3 februari 2016 kl. 14:04:46 UTC+1 skrev Anton Lindqvist: > Hi, > This patch add a autocmd event called TagNotFound triggered when the requested > tag was not found. The motivation for this event is as follows: I usually add > the following to my vimrc in order to ensure my tags file is up-to-date: > > au BufWritePost * if filereadable('tags') | silent exe '!ctags -a %' | endif > > However this seems wasteful since the majority of my writes don't include new > identifiers to be indexed. With this patch the command above could be replaced > with: > > au TagNotFound * if filereadable('tags') | silent exe '!ctags' | endif > > Thus indexing would only be performed when a missing tag is requested. > > Another use-case for this new event would be to trigger a psearch when the tag > was not found: > > au TagNotFound * exe 'psearch /' . expand('') . '/' > > BTW: what's the recommended cinoptions for the Vim codebase? A unintentional change to one of the Makefile was present in the patch. See the attached revised patch. -- -- 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/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 4de5b16..06f1578 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -284,6 +284,7 @@ Name triggered by ~ |SpellFileMissing| a spell file is used but it can't be found |SourcePre| before sourcing a Vim script |SourceCmd| before sourcing a Vim script |Cmd-event| +|TagNotFound| the tag was not found in the tag file(s) |VimResized| after the Vim window size changed |FocusGained| Vim got input focus @@ -879,6 +880,10 @@ TabEnter Just after entering a tab page. |tab-page| TabLeave Just before leaving a tab page. |tab-page| A WinLeave event will have been triggered first. + *TagNotFound* +TagNotFound When the requested tag was not found in the +tag file(s). The pattern is matched against +the tag name. is the tag name. *TermChanged* TermChanged After the value of 'term' has changed. Useful for re-loading the syntax file to update the diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt index 8186678..55d8d97 100644 --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -820,7 +820,8 @@ Note: these are typed literally, they are not special keys! When executing autocommands, is replaced with the match for which this autocommand was executed. It differs from only when the file name isn't used to match with - (for FileType, Syntax and SpellFileMissing events). + (for FileType, Syntax, SpellFileMissing and TagNotFound + events). When executing a ":source" command, is replaced with the file name of the sourced file. *E498* When executing a function, is replaced with: diff --git a/src/fileio.c b/src/fileio.c index ecec757..fa2ec72 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -7711,6 +7711,7 @@ static struct event_name {"Syntax", EVENT_SYNTAX}, {"TabEnter", EVENT_TABENTER}, {"TabLeave", EVENT_TABLEAVE}, +{"TagNotFound", EVENT_TAGNOTFOUND}, {"TermChanged", EVENT_TERMCHANGED}, {"TermResponse", EVENT_TERMRESPONSE}, {"TextChanged", EVENT_TEXTCHANGED}, @@ -9357,6 +9358,7 @@ apply_autocmds_group( || event == EVENT_FUNCUNDEFINED || event == EVENT_REMOTEREPLY || event == EVENT_SPELLFILEMISSING + || event == EVENT_TAGNOTFOUND || event == EVENT_QUICKFIXCMDPRE || event == EVENT_COLORSCHEME || event == EVENT_OPTIONSET diff --git a/src/tag.c b/src/tag.c index d2fdee6..b24212e 100644 --- a/src/tag.c +++ b/src/tag.c @@ -569,6 +569,10 @@ do_tag( if (num_matches <= 0) { +#ifdef FEAT_AUTOCMD + apply_autocmds(EVENT_TAGNOTFOUND, name, curbuf->b_fname, + FALSE, curbuf); +#endif if (verbose) EMSG2(_("E426: tag not found: %s"), name); #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) diff --git a/src/vim.h b/src/vim.h index 18610f5..80491d0 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1314,6 +1314,7 @@ enum auto_event EVENT_TEXTCHANGEDI, /* text was modified in Insert mode*/ EVENT_CMDUNDEFINED, /* command undefined */ EVENT_OPTIONSET, /* option was set */ +EVENT_TAGNOTFOUND, /* tag not found */ NUM_EVENTS /* MUST be the last one */ };
[patch] syntax manual bug
Hi, I'm using manual syntax highlighting and discovered a bug when moving between buffers. How to reproduce: 1. Create files: $ cat >vimrc <1.vim <2.vim