diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-06-28 15:51:16 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-06-28 15:51:16 +0200 |
commit | d5053d015a957b343ad9c9e45e0abd2978f10cf0 (patch) | |
tree | 4154d4cd881536a310adec7425bcb9e1c05da85d /src/ex_docmd.c | |
parent | 06cf97e714fd8bf9b35ff5f8a6f2302c79acdd03 (diff) | |
download | vim-git-d5053d015a957b343ad9c9e45e0abd2978f10cf0.tar.gz |
patch 8.2.1079: Vim9: no line break allowed in a while loopv8.2.1079
Problem: Vim9: no line break allowed in a while loop.
Solution: Update stored loop lines when finding line breaks.
Diffstat (limited to 'src/ex_docmd.c')
-rw-r--r-- | src/ex_docmd.c | 98 |
1 files changed, 68 insertions, 30 deletions
diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 2469df341..0ec63e24e 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -629,6 +629,7 @@ do_cmdline( cstack_T cstack; // conditional stack garray_T lines_ga; // keep lines for ":while"/":for" int current_line = 0; // active line in lines_ga + int current_line_before = 0; char_u *fname = NULL; // function or script name linenr_T *breakpoint = NULL; // ptr to breakpoint field in cookie int *dbg_tick = NULL; // ptr to dbg_tick field in cookie @@ -851,27 +852,6 @@ do_cmdline( } # endif } - - if (cstack.cs_looplevel > 0) - { - // Inside a while/for loop we need to store the lines and use them - // again. Pass a different "fgetline" function to do_one_cmd() - // below, so that it stores lines in or reads them from - // "lines_ga". Makes it possible to define a function inside a - // while/for loop. - cmd_getline = get_loop_line; - cmd_cookie = (void *)&cmd_loop_cookie; - cmd_loop_cookie.lines_gap = &lines_ga; - cmd_loop_cookie.current_line = current_line; - cmd_loop_cookie.getline = fgetline; - cmd_loop_cookie.cookie = cookie; - cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); - } - else - { - cmd_getline = fgetline; - cmd_cookie = cookie; - } #endif // 2. If no line given, get an allocated line with fgetline(). @@ -929,21 +909,44 @@ do_cmdline( #ifdef FEAT_EVAL /* - * Save the current line when inside a ":while" or ":for", and when - * the command looks like a ":while" or ":for", because we may need it - * later. When there is a '|' and another command, it is stored - * separately, because we need to be able to jump back to it from an + * Inside a while/for loop, and when the command looks like a ":while" + * or ":for", the line is stored, because we may need it later when + * looping. + * + * When there is a '|' and another command, it is stored separately, + * because we need to be able to jump back to it from an * :endwhile/:endfor. + * + * Pass a different "fgetline" function to do_one_cmd() below, + * that it stores lines in or reads them from "lines_ga". Makes it + * possible to define a function inside a while/for loop and handles + * line continuation. */ - if (current_line == lines_ga.ga_len - && (cstack.cs_looplevel || has_loop_cmd(next_cmdline))) + if ((cstack.cs_looplevel > 0 || has_loop_cmd(next_cmdline))) { - if (store_loop_line(&lines_ga, next_cmdline) == FAIL) + cmd_getline = get_loop_line; + cmd_cookie = (void *)&cmd_loop_cookie; + cmd_loop_cookie.lines_gap = &lines_ga; + cmd_loop_cookie.current_line = current_line; + cmd_loop_cookie.getline = fgetline; + cmd_loop_cookie.cookie = cookie; + cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); + + // Save the current line when encountering it the first time. + if (current_line == lines_ga.ga_len + && store_loop_line(&lines_ga, next_cmdline) == FAIL) { retval = FAIL; break; } + current_line_before = current_line; + } + else + { + cmd_getline = fgetline; + cmd_cookie = cookie; } + did_endif = FALSE; #endif @@ -1078,7 +1081,7 @@ do_cmdline( else if (cstack.cs_lflags & CSL_HAD_LOOP) { cstack.cs_lflags &= ~CSL_HAD_LOOP; - cstack.cs_line[cstack.cs_idx] = current_line - 1; + cstack.cs_line[cstack.cs_idx] = current_line_before; } } @@ -1515,7 +1518,7 @@ getline_cookie( { #ifdef FEAT_EVAL char_u *(*gp)(int, void *, int, int); - struct loop_cookie *cp; + struct loop_cookie *cp; // When "fgetline" is "get_loop_line()" use the "cookie" to find the // cookie that's originally used to obtain the lines. This may be nested @@ -1533,6 +1536,41 @@ getline_cookie( #endif } +#if defined(FEAT_EVAL) || defined(PROT) +/* + * Get the next line source line without advancing. + */ + char_u * +getline_peek( + char_u *(*fgetline)(int, void *, int, int) UNUSED, + void *cookie) // argument for fgetline() +{ + char_u *(*gp)(int, void *, int, int); + struct loop_cookie *cp; + wcmd_T *wp; + + // When "fgetline" is "get_loop_line()" use the "cookie" to find the + // cookie that's originally used to obtain the lines. This may be nested + // several levels. + gp = fgetline; + cp = (struct loop_cookie *)cookie; + while (gp == get_loop_line) + { + if (cp->current_line + 1 < cp->lines_gap->ga_len) + { + // executing lines a second time, use the stored copy + wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line + 1; + return wp->line; + } + gp = cp->getline; + cp = cp->cookie; + } + if (gp == getsourceline) + return source_nextline(cp); + return NULL; +} +#endif + /* * Helper function to apply an offset for buffer commands, i.e. ":bdelete", |