Problem: Vim9: allowing both quoted and # comments is confusing.
Solution: Only support # comments in Vim9 script.
-*vim9.txt* For Vim version 8.2. Last change: 2020 Jul 10
+*vim9.txt* For Vim version 8.2. Last change: 2020 Jul 17
VIM REFERENCE MANUAL by Bram Moolenaar
Comments starting with # ~
-In Vim script comments start with double quote. That can also be the start of
-a string, thus in many places it cannot be used. In Vim9 script a comment
-normally starts with #. In Vi this is a command to list text with numbers,
-but you can also use `:number` for that. >
+In legacy Vim script comments start with double quote. In Vim9 script
+comments start with #. >
+ # declarations
let count = 0 # number of occurrences
-To improve readability there must be a space between the command and the #
+The reason is that a double quote can also be the start of a string. In many
+places, especially halfway an expression with a line break, it's hard to tell
+what the meaning is. To avoid confusion only # comments are recognized.
+This is the same as in shell scripts and Python programs.
+
+In Vi # is a command to list text with numbers. In Vim9 script you can use
+`:number` for that. >
+ 101number
+
+To improve readability there must be a space between a command and the #
that starts a comment. Note that #{ is the start of a dictionary, therefore
it cannot start a comment.
-Since Vim9 script allows for line breaks in many places, the double quoted
-comment also cannot be used at the start of a line after an expression. To
-avoid confusion it is best to only use # comments.
-
Vim9 functions ~
0 || '' == ''
8 && 2 == 2
0 && 2 == 0
+ 2 && 0 == 0
[] && 2 == []
When using `..` for string concatenation the arguments are always converted to
Ex command ranges need to be prefixed with a colon. >
-> " legacy Vim: shifts the previous line to the right
- ->func() " Vim9: method call
+ ->func() " Vim9: method call in continuation line
:-> " Vim9: shifts the previous line to the right
%s/a/b " legacy Vim: substitute on all lines
x = alongname
% another " Vim9: line continuation without a backslash
:%s/a/b " Vim9: substitute on all lines
+ 'text'->func() " Vim9: method call
+ :'t " legacy Vim: jump to mark m
Functions defined with `:def` compile the whole function. Legacy functions
can bail out, and the following lines are not parsed: >
return nr;
}
+ int
+comment_start(char_u *p, int starts_with_colon UNUSED)
+{
+#ifdef FEAT_EVAL
+ if (in_vim9script())
+ return p[0] == '#' && p[1] != '{' && !starts_with_colon;
+#endif
+ return *p == '"';
+}
+
# define CURRENT_WIN_NR current_win_nr(curwin)
# define LAST_WIN_NR current_win_nr(NULL)
# define CURRENT_TAB_NR current_tab_nr(curtab)
* If we got a line, but no command, then go to the line.
* If we find a '|' or '\n' we set ea.nextcmd.
*/
- if (*ea.cmd == NUL || *ea.cmd == '"'
-#ifdef FEAT_EVAL
- || (*ea.cmd == '#' && ea.cmd[1] != '{'
- && !starts_with_colon && vim9script)
-#endif
- || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL)
+ if (*ea.cmd == NUL || comment_start(ea.cmd, starts_with_colon)
+ || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL)
{
/*
* strange vi behaviour:
ea.do_ecmd_cmd = getargcmd(&ea.arg);
/*
- * Check for '|' to separate commands and '"' to start comments.
+ * Check for '|' to separate commands and '"' or '#' to start comments.
* Don't do this for ":read !cmd" and ":write !cmd".
*/
if ((ea.argt & EX_TRLBAR) && !ea.usefilter)
int
parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only)
{
- char_u *p;
+ char_u *p;
+ int starts_with_colon = FALSE;
CLEAR_FIELD(cmdmod);
eap->verbose_save = -1;
for (;;)
{
while (*eap->cmd == ' ' || *eap->cmd == '\t' || *eap->cmd == ':')
+ {
+ if (*eap->cmd == ':')
+ starts_with_colon = TRUE;
++eap->cmd;
+ }
// in ex mode, an empty line works like :+
if (*eap->cmd == NUL && exmode_active
}
// ignore comment and empty lines
- if (*eap->cmd == '"')
+ if (comment_start(eap->cmd, starts_with_colon))
return FAIL;
if (*eap->cmd == NUL)
{
// Check for '"': start of comment or '|': next command
// :@" and :*" do not start a comment!
// :redir @" doesn't either.
- else if ((*p == '"' && !(eap->argt & EX_NOTRLCOM)
+ else if ((*p == '"'
+#ifdef FEAT_EVAL
+ && !in_vim9script()
+#endif
+ && !(eap->argt & EX_NOTRLCOM)
&& ((eap->cmdidx != CMD_at && eap->cmdidx != CMD_star)
- || p != eap->arg)
+ || p != eap->arg)
&& (eap->cmdidx != CMD_redir
- || p != eap->arg + 1 || p[-1] != '@'))
+ || p != eap->arg + 1 || p[-1] != '@'))
#ifdef FEAT_EVAL
- || (*p == '#' && in_vim9script()
- && p[1] != '{' && p > eap->cmd && VIM_ISWHITE(p[-1]))
+ || (*p == '#'
+ && in_vim9script()
+ && p[1] != '{'
+ && p > eap->cmd && VIM_ISWHITE(p[-1]))
#endif
|| *p == '|' || *p == '\n')
{
int
ends_excmd(int c)
{
+ int comment_char = '"';
+
#ifdef FEAT_EVAL
- if (c == '#')
- return in_vim9script();
+ if (in_vim9script())
+ comment_char = '#';
#endif
- return (c == NUL || c == '|' || c == '"' || c == '\n');
+ return (c == NUL || c == '|' || c == comment_char || c == '\n');
}
/*
{
int c = *cmd;
+ if (c == NUL || c == '|' || c == '\n')
+ return TRUE;
#ifdef FEAT_EVAL
- if (c == '#' && cmd[1] != '{' && (cmd == cmd_start || VIM_ISWHITE(cmd[-1])))
- return in_vim9script();
+ if (in_vim9script())
+ return c == '#' && cmd[1] != '{'
+ && (cmd == cmd_start || VIM_ISWHITE(cmd[-1]));
#endif
- return (c == NUL || c == '|' || c == '"' || c == '\n');
+ return c == '"';
}
#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) || defined(FEAT_EVAL) \
eap->nextcmd = check_nextcmd(p);
p = skipwhite(p);
- if (*p != NUL && *p != '"' && eap->nextcmd == NULL)
+ if (*p != NUL && *p != (
+#ifdef FEAT_EVAL
+ in_vim9script() ? '#' :
+#endif
+ '"')
+ && eap->nextcmd == NULL)
emsg(_(e_invarg));
else if (!eap->skip)
{
int getline_equal(char_u *(*fgetline)(int, void *, int, int), void *cookie, char_u *(*func)(int, void *, int, int));
void *getline_cookie(char_u *(*fgetline)(int, void *, int, int), void *cookie);
char_u *getline_peek(char_u *(*fgetline)(int, void *, int, int), void *cookie);
+int comment_start(char_u *p, int starts_with_colon);
int parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only);
void undo_cmdmod(exarg_T *eap, int save_msg_scroll);
int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
'\d RETURN',
res)
- " Calling the function will change UCALL into the faster DCALL
+ # Calling the function will change UCALL into the faster DCALL
assert_equal('yes', FuncWithForwardCall())
res = execute('disass s:FuncWithForwardCall')
let nr = 1
for case in cases
- " declare local variables to get a non-constant with the right type
+ # declare local variables to get a non-constant with the right type
writefile(['def TestCase' .. nr .. '()',
' let isFalse = false',
' let isNull = v:null',
source Xdisassemble
let instr = execute('disassemble TestCase' .. nr)
if case[1]
- " condition true, "echo 42" executed
+ # condition true, "echo 42" executed
assert_match('TestCase' .. nr .. '.*' ..
'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' ..
'\d PUSHNR 42.*' ..
'\d RETURN.*',
instr)
else
- " condition false, function just returns
+ # condition false, function just returns
assert_match('TestCase' .. nr .. '.*' ..
'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '[ \n]*' ..
'echo 42[ \n]*' ..
writefile(lines, 'Xdisassemble')
source Xdisassemble
- " check that the first function calls the second with DCALL
+ # check that the first function calls the second with DCALL
assert_match('\<SNR>\d*_FuncOne\_s*' ..
'return FuncTwo()\_s*' ..
'\d DCALL <SNR>\d\+_FuncTwo(argc 0)\_s*' ..
enddef
def Test_expr1_vimscript()
- " only checks line continuation
+ # only checks line continuation
let lines =<< trim END
vim9script
let var = 1
enddef
def Test_expr2_vimscript()
- " check line continuation
+ # check line continuation
let lines =<< trim END
vim9script
let var = 0
END
CheckScriptSuccess(lines)
- " check keeping the value
+ # check keeping the value
lines =<< trim END
vim9script
assert_equal(2, 2 || 0)
enddef
def Test_expr3_vimscript()
- " check line continuation
+ # check line continuation
let lines =<< trim END
vim9script
let var = 0
END
CheckScriptSuccess(lines)
- " check keeping the value
+ # check keeping the value
lines =<< trim END
vim9script
assert_equal(0, 2 && 0)
enddef
def Test_expr4_vimscript()
- " check line continuation
+ # check line continuation
let lines =<< trim END
vim9script
let var = 0
END
CheckScriptSuccess(lines)
- " spot check mismatching types
+ # spot check mismatching types
lines =<< trim END
vim9script
echo '' == 0
enddef
def Test_expr5_vim9script()
- " only checks line continuation
+ # only checks line continuation
let lines =<< trim END
vim9script
let var = 11
enddef
def Test_expr6_vim9script()
- " only checks line continuation
+ # only checks line continuation
let lines =<< trim END
vim9script
let var = 11
" test low level expression
def Test_expr7_number()
- " number constant
+ # number constant
assert_equal(0, 0)
assert_equal(654, 0654)
enddef
def Test_expr7_float()
- " float constant
+ # float constant
if !has('float')
MissingFeature 'float'
else
enddef
def Test_expr7_blob()
- " blob constant
+ # blob constant
assert_equal(g:blob_empty, 0z)
assert_equal(g:blob_one, 0z01)
assert_equal(g:blob_long, 0z0102.0304)
enddef
def Test_expr7_string()
- " string constant
+ # string constant
assert_equal(g:string_empty, '')
assert_equal(g:string_empty, "")
assert_equal(g:string_short, 'x')
enddef
def Test_expr7_special()
- " special constant
+ # special constant
assert_equal(g:special_true, true)
assert_equal(g:special_false, false)
assert_equal(g:special_true, v:true)
enddef
def Test_expr7_list()
- " list
+ # list
assert_equal(g:list_empty, [])
assert_equal(g:list_empty, [ ])
assert_equal(g:list_mixed, [1, 'b', false,])
assert_equal('result', La())
assert_equal([1, 3, 5], [1, 2, 3]->map({key, val -> key + val}))
- " line continuation inside lambda with "cond ? expr : expr" works
+ # line continuation inside lambda with "cond ? expr : expr" works
let ll = range(3)
map(ll, {k, v -> v % 2 ? {
'111': 111 } : {}
enddef
def Test_expr7_dict()
- " dictionary
+ # dictionary
assert_equal(g:dict_empty, {})
assert_equal(g:dict_empty, { })
assert_equal(g:dict_one, {'one': 1})
enddef
def Test_expr7_option()
- " option
+ # option
set ts=11
assert_equal(11, &ts)
&ts = 9
enddef
def Test_expr7_environment()
- " environment variable
+ # environment variable
assert_equal('testvar', $TESTVAR)
assert_equal('', $ASDF_ASD_XXX)
enddef
def Test_expr7_parens()
- " (expr)
+ # (expr)
assert_equal(4, (6 * 4) / 6)
assert_equal(0, 6 * ( 4 / 6 ))
endfunc
def Test_expr7_trailing()
- " user function call
+ # user function call
assert_equal(123, g:CallMe(123))
assert_equal(123, g:CallMe( 123))
assert_equal(123, g:CallMe(123 ))
assert_equal('yesno', g:CallMe2( 'yes', 'no' ))
assert_equal('nothing', g:CallMe('nothing'))
- " partial call
+ # partial call
let Part = function('g:CallMe')
assert_equal('yes', Part('yes'))
- " funcref call, using list index
+ # funcref call, using list index
let l = []
g:Funcrefs[0](l, 2)
assert_equal([2], l)
- " method call
+ # method call
l = [2, 5, 6]
l->map({k, v -> k + v})
assert_equal([2, 6, 8], l)
- " lambda method call
+ # lambda method call
l = [2, 5]
l->{l -> add(l, 8)}()
assert_equal([2, 5, 8], l)
- " dict member
+ # dict member
let d = #{key: 123}
assert_equal(123, d.key)
enddef
Increment()
Increment()
Increment()
- " works with and without :call
+ # works with and without :call
assert_equal(4, g:counter)
call assert_equal(4, g:counter)
unlet g:counter
enddef
def Test_assign_to_argument()
- " works for dict and list
+ # works for dict and list
let d: dict<string> = {}
DictArg(d)
assert_equal('value', d['key'])
let NotAFunc = 'text'
def CombineFuncrefTypes()
- " same arguments, different return type
+ # same arguments, different return type
let Ref1: func(bool): string
let Ref2: func(bool): number
let Ref3: func(bool): any
Ref3 = g:cond ? Ref1 : Ref2
- " different number of arguments
+ # different number of arguments
let Refa1: func(bool): number
let Refa2: func(bool, number): number
let Refa3: func: number
Refa3 = g:cond ? Refa1 : Refa2
- " different argument types
+ # different argument types
let Refb1: func(bool, string): number
let Refb2: func(string, number): number
let Refb3: func(any, any): number
enddef
def Test_error_in_nested_function()
- " Error in called function requires unwinding the call stack.
+ # Error in called function requires unwinding the call stack.
assert_fails('call FuncWithForwardCall()', 'E1096')
enddef
let lines =<< trim END
vim9script
- " single character variable declarations work
+ # single character variable declarations work
let a: string
let b: number
let l: list<any>
let v: number
let w: number
- " script-local variables can be used without s: prefix
+ # script-local variables can be used without s: prefix
a = 'script-a'
b = 111
l = [1, 2, 3]
let dict4: dict<any> = #{one: 1, two: '2'}
let dict5: dict<blob> = #{one: 0z01, two: 0z02}
- " overwrite
+ # overwrite
dict3['key'] = 'another'
call CheckDefExecFailure(['let dd = {}', 'dd[""] = 6'], 'E713:')
enddef
def Test_assignment_local()
- " Test in a separated file in order not to the current buffer/window/tab is
- " changed.
+ # Test in a separated file in order not to the current buffer/window/tab is
+ # changed.
let script_lines: list<string> =<< trim END
let b:existing = 'yes'
let w:existing = 'yes'
assert_equal(test_null_channel(), thechannel)
if has('unix') && executable('cat')
- " check with non-null job and channel, types must match
+ # check with non-null job and channel, types must match
thejob = job_start("cat ", #{})
thechannel = job_getchannel(thejob)
job_stop(thejob, 'kill')
enddef
def Test_delfunction()
- " Check function is defined in script namespace
+ # Check function is defined in script namespace
CheckScriptSuccess([
'vim9script',
'func CheckMe()',
'assert_equal(123, s:CheckMe())',
])
- " Check function in script namespace cannot be deleted
+ # Check function in script namespace cannot be deleted
CheckScriptFailure([
'vim9script',
'func DeleteMe1()',
enddef
def Test_throw_vimscript()
- " only checks line continuation
+ # only checks line continuation
let lines =<< trim END
vim9script
try
enddef
def Test_cexpr_vimscript()
- " only checks line continuation
+ # only checks line continuation
set errorformat=File\ %f\ line\ %l
let lines =<< trim END
vim9script
END
writefile(import_in_def_lines, 'Ximport2.vim')
source Ximport2.vim
- " TODO: this should be 9879
+ # TODO: this should be 9879
assert_equal(9876, g:imported)
assert_equal(9883, g:imported_added)
unlet g:imported
writefile(import_star_lines, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1045:')
- " try to import something that exists but is not exported
+ # try to import something that exists but is not exported
let import_not_exported_lines =<< trim END
vim9script
import name from './Xexport.vim'
writefile(import_not_exported_lines, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1049:')
- " try to import something that is already defined
+ # try to import something that is already defined
let import_already_defined =<< trim END
vim9script
let exported = 'something'
writefile(import_already_defined, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1073:')
- " try to import something that is already defined
+ # try to import something that is already defined
import_already_defined =<< trim END
vim9script
let exported = 'something'
writefile(import_already_defined, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1073:')
- " try to import something that is already defined
+ # try to import something that is already defined
import_already_defined =<< trim END
vim9script
let exported = 'something'
writefile(import_already_defined, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1073:')
- " import a very long name, requires making a copy
+ # import a very long name, requires making a copy
let import_long_name_lines =<< trim END
vim9script
import name012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 from './Xexport.vim'
delete('Ximport3.vim')
delete('Xexport.vim')
- " Check that in a Vim9 script 'cpo' is set to the Vim default.
+ # Check that in a Vim9 script 'cpo' is set to the Vim default.
set cpo&vi
let cpo_before = &cpo
let lines =<< trim END
writefile(testlines, 'Ximport.vim')
source Ximport.vim
- " Test that when not using "morelines" GetValtwo() and valtwo are still
- " defined, because import doesn't reload a script.
+ # Test that when not using "morelines" GetValtwo() and valtwo are still
+ # defined, because import doesn't reload a script.
writefile(lines, 'Xreload.vim')
source Ximport.vim
- " cannot declare a var twice
+ # cannot declare a var twice
lines =<< trim END
vim9script
let valone = 1234
try
source Ximport.vim
catch /E1001/
- " Error should be fore the Xexported.vim file.
+ # Error should be fore the Xexported.vim file.
assert_match('E1001: variable not found: notDefined', v:exception)
assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint)
endtry
enddef
def Test_fixed_size_list()
- " will be allocated as one piece of memory, check that changes work
+ # will be allocated as one piece of memory, check that changes work
let l = [1, 2, 3, 4]
l->remove(0)
l->add(5)
let x: number = 0
if i % 2
if 1
- " comment
+ # comment
else
- " comment
+ # comment
endif
x += 1
else
enddef
def Test_execute_cmd_vimscript()
- " only checks line continuation
+ # only checks line continuation
let lines =<< trim END
vim9script
execute 'g:someVar'
enddef
def Test_echomsg_cmd_vimscript()
- " only checks line continuation
+ # only checks line continuation
let lines =<< trim END
vim9script
echomsg 'here'
enddef
def Test_echoerr_cmd_vimscript()
- " only checks line continuation
+ # only checks line continuation
let lines =<< trim END
vim9script
try
'one',
'two',
'three',
- ] " comment
+ ] # comment
assert_equal(['one', 'two', 'three'], mylist)
let mydict = {
'two': 2,
'three':
3,
- } " comment
+ } # comment
assert_equal({'one': 1, 'two': 2, 'three': 3}, mydict)
mydict = #{
one: 1, # comment
'hi clear This # comment',
'hi clear # comment',
])
- " not tested, because it doesn't give an error but a warning:
- " hi clear This# comment',
+ # not tested, because it doesn't give an error but a warning:
+ # hi clear This# comment',
CheckScriptFailure([
'vim9script',
'hi clear# comment',
'bwipe!',
])
-" CheckScriptFailure([
-" 'vim9script',
-" 'new'
-" 'call setline(1, ["# define pat", "last"])',
-" ':$',
-" 'dsearch /pat/#comment',
-" 'bwipe!',
-" ], 'E488:')
-"
-" CheckScriptFailure([
-" 'vim9script',
-" 'func! SomeFunc()',
-" ], 'E477:')
+ CheckScriptFailure([
+ 'vim9script',
+ 'new'
+ 'call setline(1, ["# define pat", "last"])',
+ ':$',
+ 'dsearch /pat/#comment',
+ 'bwipe!',
+ ], 'E488:')
+
+ CheckScriptFailure([
+ 'vim9script',
+ 'func! SomeFunc()',
+ ], 'E477:')
enddef
def Test_finish()
return 'this'
endfunc
let val: string = GetValue()
- " env var is always a string
+ # env var is always a string
let env = $TERM
END
writefile(lines, 'Xfinished')
source Xfinished
- " GetValue() is not called during discovery phase
+ # GetValue() is not called during discovery phase
assert_equal(1, g:count)
unlet g:count
g:var_uninit = var
var = 'text'
g:var_test = var
- " prefixing s: is optional
+ # prefixing s: is optional
s:var = 'prefixed'
g:var_prefixed = s:var
source Xlegacy_script.vim
assert_equal('global', g:global)
-" unlet g:global
+ unlet g:global
delete('Xlegacy_script.vim')
delete('Xvim9_script.vim')
assert_equal('otherthing', getline(1))
bwipe!
- " also when the context is Vim9 script
+ # also when the context is Vim9 script
let lines =<< trim END
vim9script
new
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1227,
/**/
1226,
/**/
* Return TRUE if "p" points at a "#" but not at "#{".
*/
static int
-comment_start(char_u *p)
+vim9_comment_start(char_u *p)
{
return p[0] == '#' && p[1] != '{';
}
if (line == NULL)
break;
p = skipwhite(line);
- if (*p != NUL && !comment_start(p))
+ if (*p != NUL && !vim9_comment_start(p))
return p;
}
return NULL;
char_u *p = skipwhite(arg);
*nextp = NULL;
- if (*p == NUL || (VIM_ISWHITE(*arg) && comment_start(p)))
+ if (*p == NUL || (VIM_ISWHITE(*arg) && vim9_comment_start(p)))
{
*nextp = peek_next_line_from_context(cctx);
if (*nextp != NULL)
cctx->ctx_line_start = line;
SOURCING_LNUM = cctx->ctx_lnum + 1;
} while (line == NULL || *skipwhite(line) == NUL
- || (skip_comment && comment_start(skipwhite(line))));
+ || (skip_comment && vim9_comment_start(skipwhite(line))));
return line;
}
static int
may_get_next_line(char_u *whitep, char_u **arg, cctx_T *cctx)
{
- if (**arg == NUL || (VIM_ISWHITE(*whitep) && comment_start(*arg)))
+ if (**arg == NUL || (VIM_ISWHITE(*whitep) && vim9_comment_start(*arg)))
{
char_u *next = next_line_from_context(cctx, TRUE);
{
++p;
// Allow for following comment, after at least one space.
- if (VIM_ISWHITE(*p) && *skipwhite(p) == '"')
+ if (VIM_ISWHITE(*p) && *skipwhite(p) == '#')
p += STRLEN(p);
break;
}
if (ufunc->uf_def_status == UF_COMPILED)
return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx);
+
+ func_ptr_unref(ufunc);
return FAIL;
}
// call the compiled function
ret = generate_CALL(cctx, ufunc, argcount);
+ if (ret == FAIL)
+ func_ptr_unref(ufunc);
return ret;
}
// Allow for following comment, after at least one space.
p = skipwhite(*arg);
- if (VIM_ISWHITE(**arg) && (*p == '"' || comment_start(p)))
+ if (VIM_ISWHITE(**arg) && vim9_comment_start(p))
*arg += STRLEN(*arg);
dict_unref(d);
{
char_u *p = skipwhite(*arg);
- if (*p == NUL || (VIM_ISWHITE(**arg) && comment_start(p)))
+ if (*p == NUL || (VIM_ISWHITE(**arg) && vim9_comment_start(p)))
{
char_u *next = peek_next_line_from_context(cctx);