Merge pull request #17950 from zeertzjq/vim-8.2.4029

vim-patch:8.2.{4029,4093,4100,4501,4882}: breakindent patches
This commit is contained in:
zeertzjq
2022-11-05 19:57:15 +08:00
committed by GitHub
9 changed files with 312 additions and 51 deletions

View File

@@ -1053,19 +1053,26 @@ A jump table for the options with a short description can be found at |Q_op|.
text should normally be narrower. This prevents text should normally be narrower. This prevents
text indented almost to the right window border text indented almost to the right window border
occupying lot of vertical space when broken. occupying lot of vertical space when broken.
(default: 20)
shift:{n} After applying 'breakindent', the wrapped line's shift:{n} After applying 'breakindent', the wrapped line's
beginning will be shifted by the given number of beginning will be shifted by the given number of
characters. It permits dynamic French paragraph characters. It permits dynamic French paragraph
indentation (negative) or emphasizing the line indentation (negative) or emphasizing the line
continuation (positive). continuation (positive).
(default: 0)
sbr Display the 'showbreak' value before applying the sbr Display the 'showbreak' value before applying the
additional indent. additional indent.
(default: off)
list:{n} Adds an additional indent for lines that match a list:{n} Adds an additional indent for lines that match a
numbered or bulleted list (using the numbered or bulleted list (using the
'formatlistpat' setting). 'formatlistpat' setting).
list:-1 Uses the length of a match with 'formatlistpat' list:-1 Uses the length of a match with 'formatlistpat'
for indentation. for indentation.
The default value for min is 20, shift and list is 0. (default: 0)
column:{n} Indent at column {n}. Will overrule the other
sub-options. Note: an additional indent may be
added for the 'showbreak' setting.
(default: off)
*'browsedir'* *'bsdir'* *'browsedir'* *'bsdir'*
'browsedir' 'bsdir' string (default: "last") 'browsedir' 'bsdir' string (default: "last")

View File

@@ -963,7 +963,8 @@ struct frame_S {
// for first // for first
// fr_child and fr_win are mutually exclusive // fr_child and fr_win are mutually exclusive
frame_T *fr_child; // first contained frame frame_T *fr_child; // first contained frame
win_T *fr_win; // window that fills this frame win_T *fr_win; // window that fills this frame; for a snapshot
// set to the current window
}; };
#define FR_LEAF 0 // frame is a leaf #define FR_LEAF 0 // frame is a leaf
@@ -1340,6 +1341,7 @@ struct window_S {
int w_briopt_shift; // additional shift for breakindent int w_briopt_shift; // additional shift for breakindent
bool w_briopt_sbr; // sbr in 'briopt' bool w_briopt_sbr; // sbr in 'briopt'
int w_briopt_list; // additional indent for lists int w_briopt_list; // additional indent for lists
int w_briopt_vcol; // indent for specific column
// transform a pointer to a "onebuf" option into a "allbuf" option // transform a pointer to a "onebuf" option into a "allbuf" option
#define GLOBAL_WO(p) ((char *)(p) + sizeof(winopt_T)) #define GLOBAL_WO(p) ((char *)(p) + sizeof(winopt_T))

View File

@@ -743,6 +743,7 @@ bool briopt_check(win_T *wp)
int bri_min = 20; int bri_min = 20;
bool bri_sbr = false; bool bri_sbr = false;
int bri_list = 0; int bri_list = 0;
int bri_vcol = 0;
char *p = wp->w_p_briopt; char *p = wp->w_p_briopt;
while (*p != NUL) { while (*p != NUL) {
@@ -759,6 +760,9 @@ bool briopt_check(win_T *wp)
} else if (STRNCMP(p, "list:", 5) == 0) { } else if (STRNCMP(p, "list:", 5) == 0) {
p += 5; p += 5;
bri_list = (int)getdigits(&p, false, 0); bri_list = (int)getdigits(&p, false, 0);
} else if (STRNCMP(p, "column:", 7) == 0) {
p += 7;
bri_vcol = (int)getdigits(&p, false, 0);
} }
if (*p != ',' && *p != NUL) { if (*p != ',' && *p != NUL) {
return false; return false;
@@ -772,6 +776,7 @@ bool briopt_check(win_T *wp)
wp->w_briopt_min = bri_min; wp->w_briopt_min = bri_min;
wp->w_briopt_sbr = bri_sbr; wp->w_briopt_sbr = bri_sbr;
wp->w_briopt_list = bri_list; wp->w_briopt_list = bri_list;
wp->w_briopt_vcol = bri_vcol;
return true; return true;
} }
@@ -783,51 +788,78 @@ int get_breakindent_win(win_T *wp, char_u *line)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
static int prev_indent = 0; // Cached indent value. static int prev_indent = 0; // Cached indent value.
static long prev_ts = 0; // Cached tabstop value. static long prev_ts = 0L; // Cached tabstop value.
static const char_u *prev_line = NULL; // cached pointer to line. static const char_u *prev_line = NULL; // cached pointer to line.
static varnumber_T prev_tick = 0; // Changedtick of cached value. static varnumber_T prev_tick = 0; // Changedtick of cached value.
static long *prev_vts = NULL; // Cached vartabs values. static long *prev_vts = NULL; // Cached vartabs values.
static int prev_list = 0; // cached list value
static int prev_listopt = 0; // cached w_p_briopt_list value
static char *prev_flp = NULL; // cached formatlistpat value
int bri = 0; int bri = 0;
// window width minus window margin space, i.e. what rests for text // window width minus window margin space, i.e. what rests for text
const int eff_wwidth = wp->w_width_inner - const int eff_wwidth = wp->w_width_inner -
((wp->w_p_nu || wp->w_p_rnu) ((wp->w_p_nu || wp->w_p_rnu)
&& (vim_strchr(p_cpo, CPO_NUMCOL) == NULL) ? number_width(wp) + 1 : 0); && (vim_strchr(p_cpo, CPO_NUMCOL) == NULL) ? number_width(wp) + 1 : 0);
// used cached indent, unless pointer or 'tabstop' changed // used cached indent, unless
// - line pointer changed
// - 'tabstop' changed
// - 'briopt_list changed' changed or
// - 'formatlistpattern' changed
if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts
|| prev_tick != buf_get_changedtick(wp->w_buffer) || prev_tick != buf_get_changedtick(wp->w_buffer)
|| prev_listopt != wp->w_briopt_list
|| (prev_flp == NULL || (strcmp(prev_flp, get_flp_value(wp->w_buffer)) != 0))
|| prev_vts != wp->w_buffer->b_p_vts_array) { || prev_vts != wp->w_buffer->b_p_vts_array) {
prev_line = line; prev_line = line;
prev_ts = wp->w_buffer->b_p_ts; prev_ts = wp->w_buffer->b_p_ts;
prev_tick = buf_get_changedtick(wp->w_buffer); prev_tick = buf_get_changedtick(wp->w_buffer);
prev_vts = wp->w_buffer->b_p_vts_array; prev_vts = wp->w_buffer->b_p_vts_array;
if (wp->w_briopt_vcol == 0) {
prev_indent = get_indent_str_vtab((char *)line, prev_indent = get_indent_str_vtab((char *)line,
wp->w_buffer->b_p_ts, wp->w_buffer->b_p_ts,
wp->w_buffer->b_p_vts_array, wp->w_buffer->b_p_vts_array,
wp->w_p_list); wp->w_p_list);
} }
prev_listopt = wp->w_briopt_list;
prev_list = 0;
xfree(prev_flp);
prev_flp = xstrdup(get_flp_value(wp->w_buffer));
// add additional indent for numbered lists
if (wp->w_briopt_list != 0 && wp->w_briopt_vcol == 0) {
regmatch_T regmatch = {
.regprog = vim_regcomp(prev_flp, RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT),
};
if (regmatch.regprog != NULL) {
regmatch.rm_ic = false;
if (vim_regexec(&regmatch, (char *)line, 0)) {
if (wp->w_briopt_list > 0) {
prev_list += wp->w_briopt_list;
} else {
prev_list = (int)(*regmatch.endp - *regmatch.startp);
}
}
vim_regfree(regmatch.regprog);
}
}
}
if (wp->w_briopt_vcol != 0) {
// column value has priority
bri = wp->w_briopt_vcol;
prev_list = 0;
} else {
bri = prev_indent + wp->w_briopt_shift; bri = prev_indent + wp->w_briopt_shift;
}
// Add offset for number column, if 'n' is in 'cpoptions' // Add offset for number column, if 'n' is in 'cpoptions'
bri += win_col_off2(wp); bri += win_col_off2(wp);
// add additional indent for numbered lists // add additional indent for numbered lists
if (wp->w_briopt_list != 0) { if (wp->w_briopt_list != 0) {
regmatch_T regmatch = {
.regprog = vim_regcomp(curbuf->b_p_flp,
RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT),
};
if (regmatch.regprog != NULL) {
regmatch.rm_ic = false;
if (vim_regexec(&regmatch, (char *)line, 0)) {
if (wp->w_briopt_list > 0) { if (wp->w_briopt_list > 0) {
bri += wp->w_briopt_list; bri += prev_list;
} else { } else {
bri = (int)(*regmatch.endp - *regmatch.startp); bri = prev_list;
}
}
vim_regfree(regmatch.regprog);
} }
} }

View File

@@ -5220,6 +5220,17 @@ unsigned int get_bkc_value(buf_T *buf)
return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags; return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags;
} }
/// Get the local or global value of 'formatlistpat'.
///
/// @param buf The buffer.
char *get_flp_value(buf_T *buf)
{
if (buf->b_p_flp == NULL || *buf->b_p_flp == NUL) {
return p_flp;
}
return buf->b_p_flp;
}
/// Get the local or global value of the 'virtualedit' flags. /// Get the local or global value of the 'virtualedit' flags.
unsigned int get_ve_flags(void) unsigned int get_ve_flags(void)
{ {

View File

@@ -697,6 +697,10 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
if (briopt_check(curwin) == FAIL) { if (briopt_check(curwin) == FAIL) {
errmsg = e_invarg; errmsg = e_invarg;
} }
// list setting requires a redraw
if (curwin->w_briopt_list) {
redraw_all_later(UPD_NOT_VALID);
}
} else if (varp == &p_isi } else if (varp == &p_isi
|| varp == &(curbuf->b_p_isk) || varp == &(curbuf->b_p_isk)
|| varp == &p_isp || varp == &p_isp
@@ -1601,6 +1605,12 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
setmouse(); // in case 'mouse' changed setmouse(); // in case 'mouse' changed
} }
// Changing Formatlistpattern when briopt includes the list setting:
// redraw
if ((varp == &p_flp || varp == &(curbuf->b_p_flp)) && curwin->w_briopt_list) {
redraw_all_later(UPD_NOT_VALID);
}
if (curwin->w_curswant != MAXCOL if (curwin->w_curswant != MAXCOL
&& (opt->flags & (P_CURSWANT | P_RALL)) != 0) { && (opt->flags & (P_CURSWANT | P_RALL)) != 0) {
curwin->w_set_curswant = true; curwin->w_set_curswant = true;

View File

@@ -444,9 +444,9 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
// May have to add something for 'breakindent' and/or 'showbreak' // May have to add something for 'breakindent' and/or 'showbreak'
// string at start of line. // string at start of line.
// Set *headp to the size of what we add. // Set *headp to the size of what we add.
// Do not use 'showbreak' at the NUL after the text.
added = 0; added = 0;
char *const sbr = c == NUL ? empty_option : (char *)get_showbreak_value(wp);
char *const sbr = (char *)get_showbreak_value(wp);
if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0) { if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0) {
colnr_T sbrlen = 0; colnr_T sbrlen = 0;
int numberwidth = win_col_off(wp); int numberwidth = win_col_off(wp);

View File

@@ -3370,8 +3370,8 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent)
int last = indent->ga_len - 3; int last = indent->ga_len - 3;
char_u save[2]; char_u save[2];
STRNCPY(save, &p[last], 2); STRNCPY(save, &p[last], 2); // NOLINT(runtime/printf)
STRNCPY(&p[last], "+-", 2); memcpy(&p[last], "+-", 2);
fprintf(debugf, " %s", p); fprintf(debugf, " %s", p);
STRNCPY(&p[last], save, 2); // NOLINT(runtime/printf) STRNCPY(&p[last], save, 2); // NOLINT(runtime/printf)
} else { } else {
@@ -4635,6 +4635,20 @@ static bool sub_equal(regsub_T *sub1, regsub_T *sub2)
} }
#ifdef REGEXP_DEBUG #ifdef REGEXP_DEBUG
static void open_debug_log(TriState result)
{
log_fd = fopen(NFA_REGEXP_RUN_LOG, "a");
if (log_fd == NULL) {
emsg(_(e_log_open_failed));
log_fd = stderr;
}
fprintf(log_fd, "****************************\n");
fprintf(log_fd, "FINISHED RUNNING nfa_regmatch() recursively\n");
fprintf(log_fd, "MATCH = %s\n", result == kTrue ? "OK" : result == kNone ? "MAYBE" : "FALSE");
fprintf(log_fd, "****************************\n");
}
static void report_state(char *action, regsub_T *sub, nfa_state_T *state, int lid, nfa_pim_T *pim) static void report_state(char *action, regsub_T *sub, nfa_state_T *state, int lid, nfa_pim_T *pim)
{ {
int col; int col;
@@ -4647,6 +4661,9 @@ static void report_state(char *action, regsub_T *sub, nfa_state_T *state, int li
col = (int)(sub->list.line[0].start - rex.line); col = (int)(sub->list.line[0].start - rex.line);
} }
nfa_set_code(state->c); nfa_set_code(state->c);
if (log_fd == NULL) {
open_debug_log(kNone);
}
fprintf(log_fd, "> %s state %d to list %d. char %d: %s (start col %d)%s\n", fprintf(log_fd, "> %s state %d to list %d. char %d: %s (start col %d)%s\n",
action, abs(state->id), lid, state->c, code, col, action, abs(state->id), lid, state->c, code, col,
pim_info(pim)); pim_info(pim));
@@ -5668,16 +5685,7 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T
nfa_endp = save_nfa_endp; nfa_endp = save_nfa_endp;
#ifdef REGEXP_DEBUG #ifdef REGEXP_DEBUG
log_fd = fopen(NFA_REGEXP_RUN_LOG, "a"); open_debug_log(result);
if (log_fd != NULL) {
fprintf(log_fd, "****************************\n");
fprintf(log_fd, "FINISHED RUNNING nfa_regmatch() recursively\n");
fprintf(log_fd, "MATCH = %s\n", !result ? "false" : "OK");
fprintf(log_fd, "****************************\n");
} else {
emsg(_(e_log_open_failed));
log_fd = stderr;
}
#endif #endif
return result; return result;
@@ -5983,16 +5991,15 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
#ifdef REGEXP_DEBUG #ifdef REGEXP_DEBUG
log_fd = fopen(NFA_REGEXP_RUN_LOG, "a"); log_fd = fopen(NFA_REGEXP_RUN_LOG, "a");
if (log_fd != NULL) { if (log_fd == NULL) {
emsg(_(e_log_open_failed));
log_fd = stderr;
}
fprintf(log_fd, "**********************************\n"); fprintf(log_fd, "**********************************\n");
nfa_set_code(start->c); nfa_set_code(start->c);
fprintf(log_fd, " RUNNING nfa_regmatch() starting with state %d, code %s\n", fprintf(log_fd, " RUNNING nfa_regmatch() starting with state %d, code %s\n",
abs(start->id), code); abs(start->id), code);
fprintf(log_fd, "**********************************\n"); fprintf(log_fd, "**********************************\n");
} else {
emsg(_(e_log_open_failed));
log_fd = stderr;
}
#endif #endif
thislist = &list[0]; thislist = &list[0];

View File

@@ -8,6 +8,7 @@ source check.vim
CheckOption breakindent CheckOption breakindent
source view_util.vim source view_util.vim
source screendump.vim
let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP" let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
@@ -876,17 +877,164 @@ endfunc
func Test_window_resize_with_linebreak() func Test_window_resize_with_linebreak()
new new
53vnew 53vnew
set linebreak setl linebreak
set showbreak=>> setl showbreak=>>
set breakindent setl breakindent
set breakindentopt=shift:4 setl breakindentopt=shift:4
call setline(1, "\naaaaaaaaa\n\na\naaaaa\n¯aaaaaaaaaa\naaaaaaaaaaaa\naaa\n\"a:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - aaaaaaaa\"\naaaaaaaa\n\"a") call setline(1, "\naaaaaaaaa\n\na\naaaaa\n¯aaaaaaaaaa\naaaaaaaaaaaa\naaa\n\"a:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - aaaaaaaa\"\naaaaaaaa\n\"a")
redraw! redraw!
call assert_equal([" >>aa^@\"a: "], ScreenLines(2, 14)) call assert_equal([" >>aa^@\"a: "], ScreenLines(2, 14))
vertical resize 52 vertical resize 52
redraw! redraw!
call assert_equal([" >>aaa^@\"a:"], ScreenLines(2, 14)) call assert_equal([" >>aaa^@\"a:"], ScreenLines(2, 14))
set linebreak& showbreak& breakindent& breakindentopt&
%bw! %bw!
endfunc endfunc
func Test_cursor_position_with_showbreak()
CheckScreendump
let lines =<< trim END
vim9script
&signcolumn = 'yes'
&showbreak = '+ '
var leftcol: number = win_getid()->getwininfo()->get(0, {})->get('textoff')
repeat('x', &columns - leftcol - 1)->setline(1)
'second line'->setline(2)
END
call writefile(lines, 'XscriptShowbreak')
let buf = RunVimInTerminal('-S XscriptShowbreak', #{rows: 6})
call term_sendkeys(buf, "AX")
call VerifyScreenDump(buf, 'Test_cursor_position_with_showbreak', {})
call StopVimInTerminal(buf)
call delete('XscriptShowbreak')
endfunc
func Test_no_spurious_match()
let s:input = printf('- y %s y %s', repeat('x', 50), repeat('x', 50))
call s:test_windows('setl breakindent breakindentopt=list:-1 formatlistpat=^- hls')
let @/ = '\%>3v[y]'
redraw!
call searchcount().total->assert_equal(1)
" cleanup
set hls&vim
let s:input = "\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
bwipeout!
endfunc
func Test_no_extra_indent()
call s:test_windows('setl breakindent breakindentopt=list:-1,min:10')
%d
let &l:formatlistpat='^\s*\d\+\.\s\+'
let text = 'word '
let len = text->strcharlen()
let line1 = text->repeat((winwidth(0) / len) * 2)
let line2 = repeat(' ', 2) .. '1. ' .. line1
call setline(1, [line2])
redraw!
" 1) matches formatlist pattern, so indent
let expect = [
\ " 1. word word word ",
\ " word word word ",
\ " word word ",
\ "~ ",
\ ]
let lines = s:screen_lines2(1, 4, 20)
call s:compare_lines(expect, lines)
" 2) change formatlist pattern
" -> indent adjusted
let &l:formatlistpat='^\s*\d\+\.'
let expect = [
\ " 1. word word word ",
\ " word word word ",
\ " word word ",
\ "~ ",
\ ]
let lines = s:screen_lines2(1, 4, 20)
" 3) no local formatlist pattern,
" so use global one -> indent
let g_flp = &g:flp
let &g:formatlistpat='^\s*\d\+\.\s\+'
let &l:formatlistpat=''
let expect = [
\ " 1. word word word ",
\ " word word word ",
\ " word word ",
\ "~ ",
\ ]
let lines = s:screen_lines2(1, 4, 20)
call s:compare_lines(expect, lines)
let &g:flp = g_flp
let &l:formatlistpat='^\s*\d\+\.'
" 4) add something in front, no additional indent
norm! gg0
exe ":norm! 5iword \<esc>"
redraw!
let expect = [
\ "word word word word ",
\ "word 1. word word ",
\ "word word word word ",
\ "word word ",
\ "~ ",
\ ]
let lines = s:screen_lines2(1, 5, 20)
call s:compare_lines(expect, lines)
bwipeout!
endfunc
func Test_breakindent_column()
" restore original
let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
call s:test_windows('setl breakindent breakindentopt=column:10')
redraw!
" 1) default: does not indent, too wide :(
let expect = [
\ " ",
\ " abcdefghijklmnop",
\ "qrstuvwxyzABCDEFGHIJ",
\ "KLMNOP "
\ ]
let lines = s:screen_lines2(1, 4, 20)
call s:compare_lines(expect, lines)
" 2) lower min value, so that breakindent works
setl breakindentopt+=min:5
redraw!
let expect = [
\ " ",
\ " abcdefghijklmnop",
\ " qrstuvwxyz",
\ " ABCDEFGHIJ",
\ " KLMNOP "
\ ]
let lines = s:screen_lines2(1, 5, 20)
" 3) set shift option -> no influence
setl breakindentopt+=shift:5
redraw!
let expect = [
\ " ",
\ " abcdefghijklmnop",
\ " qrstuvwxyz",
\ " ABCDEFGHIJ",
\ " KLMNOP "
\ ]
let lines = s:screen_lines2(1, 5, 20)
call s:compare_lines(expect, lines)
" 4) add showbreak value
setl showbreak=++
redraw!
let expect = [
\ " ",
\ " abcdefghijklmnop",
\ " ++qrstuvwx",
\ " ++yzABCDEF",
\ " ++GHIJKLMN",
\ " ++OP "
\ ]
let lines = s:screen_lines2(1, 6, 20)
call s:compare_lines(expect, lines)
bwipeout!
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -0,0 +1,44 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local exec = helpers.exec
local feed = helpers.feed
before_each(clear)
describe('breakindent', function()
-- oldtest: Test_cursor_position_with_showbreak()
it('cursor shown at correct position with showbreak', function()
local screen = Screen.new(75, 6)
screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
[1] = {background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue}, -- SignColumn
[2] = {bold = true}, -- ModeMsg
})
screen:attach()
exec([[
let &signcolumn = 'yes'
let &showbreak = '+'
let leftcol = win_getid()->getwininfo()->get(0, {})->get('textoff')
eval repeat('x', &columns - leftcol - 1)->setline(1)
eval 'second line'->setline(2)
]])
screen:expect([[
{1: }^xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
{1: }second line |
{0:~ }|
{0:~ }|
{0:~ }|
|
]])
feed('AX')
screen:expect([[
{1: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxX|
{1: }^second line |
{0:~ }|
{0:~ }|
{0:~ }|
{2:-- INSERT --} |
]])
end)
end)