patch 9.2.0579: :mksession, :mkview and :mkvimrc emit legacy Vim script

Problem:  :mksession, :mkview and :mkvimrc emit legacy Vim script
Solution: Generate vim9 script for those commands (Miguel Barro).

fixes:  #16549
fixes:  #16688
fixes:  #19005
closes: #20152

Co-authored-by: Christian Brabandt <cb@256bit.org>
Signed-off-by: Miguel Barro <miguel.barro@live.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Miguel Barro
2026-05-31 21:03:12 +00:00
committed by Christian Brabandt
parent 63a9471e22
commit d69cf0dbcf
8 changed files with 439 additions and 117 deletions
+3 -1
View File
@@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.2. Last change: 2026 May 25
*version9.txt* For Vim version 9.2. Last change: 2026 May 31
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -52644,6 +52644,8 @@ Other ~
attribute to handle completion of single arguments with spaces as expected.
- Support %0{} in 'statusline' to insert the expression result verbatim and
not drop leading spaces |stl-%0{|.
- Generated Session and View files are written in Vim9 script, see |:mksession|,
|:mkview| and |:mkvimrc|
Platform specific ~
-----------------
+4 -4
View File
@@ -3548,7 +3548,7 @@ put_folds(FILE *fd, win_T *wp)
{
if (put_line(fd, "silent! normal! zE") == FAIL
|| put_folds_recurse(fd, &wp->w_folds, (linenr_T)0) == FAIL
|| put_line(fd, "let &fdl = &fdl") == FAIL)
|| put_line(fd, "&fdl = &fdl") == FAIL)
return FAIL;
}
@@ -3576,7 +3576,7 @@ put_folds_recurse(FILE *fd, garray_T *gap, linenr_T off)
// Do nested folds first, they will be created closed.
if (put_folds_recurse(fd, &fp->fd_nested, off + fp->fd_top) == FAIL)
return FAIL;
if (fprintf(fd, "sil! %ld,%ldfold", fp->fd_top + off,
if (fprintf(fd, "sil! :%ld,%ldfold", fp->fd_top + off,
fp->fd_top + off + fp->fd_len - 1) < 0
|| put_eol(fd) == FAIL)
return FAIL;
@@ -3610,7 +3610,7 @@ put_foldopen_recurse(
{
// open nested folds while this fold is open
// ignore errors
if (fprintf(fd, "%ld", fp->fd_top + off) < 0
if (fprintf(fd, ":%ld", fp->fd_top + off) < 0
|| put_eol(fd) == FAIL
|| put_line(fd, "sil! normal! zo") == FAIL)
return FAIL;
@@ -3651,7 +3651,7 @@ put_foldopen_recurse(
static int
put_fold_open_close(FILE *fd, fold_T *fp, linenr_T off)
{
if (fprintf(fd, "%ld", fp->fd_top + off) < 0
if (fprintf(fd, ":%ld", fp->fd_top + off) < 0
|| put_eol(fd) == FAIL
|| fprintf(fd, "sil! normal! z%c",
fp->fd_flags == FD_CLOSED ? 'c' : 'o') < 0
+8 -4
View File
@@ -2087,13 +2087,19 @@ makemap(
did_cpo = TRUE;
if (did_cpo)
{
if (fprintf(fd, "let s:cpo_save=&cpo") < 0
if (fprintf(fd, "cpo_save = &cpo") < 0
|| put_eol(fd) < 0
|| fprintf(fd, "set cpo&vim") < 0
|| put_eol(fd) < 0)
return FAIL;
}
}
#ifdef FEAT_EVAL
// If it is not vim9 use legacy
if (mp->m_expr && mp->m_script_ctx.sc_version < SCRIPT_VERSION_VIM9
&& fputs("legacy ", fd) < 0)
return FAIL;
#endif
if (c1 && putc(c1, fd) < 0)
return FAIL;
if (mp->m_noremap != REMAP_YES && fprintf(fd, "nore") < 0)
@@ -2128,9 +2134,7 @@ makemap(
}
if (did_cpo)
if (fprintf(fd, "let &cpo=s:cpo_save") < 0
|| put_eol(fd) < 0
|| fprintf(fd, "unlet s:cpo_save") < 0
if (fprintf(fd, "&cpo = cpo_save") < 0
|| put_eol(fd) < 0)
return FAIL;
return OK;
+101 -55
View File
@@ -105,7 +105,7 @@ ses_arglist(
if (fputs(cmd, fd) < 0 || put_eol(fd) == FAIL)
return FAIL;
if (put_line(fd, "%argdel") == FAIL)
if (put_line(fd, ":%argdel") == FAIL)
return FAIL;
for (i = 0; i < gap->ga_len; ++i)
{
@@ -122,7 +122,7 @@ ses_arglist(
s = buf;
}
}
if (fputs("$argadd ", fd) < 0
if (fputs(":$argadd ", fd) < 0
|| ses_put_fname(fd, s, flagp) == FAIL
|| put_eol(fd) == FAIL)
{
@@ -220,7 +220,7 @@ ses_win_rec(FILE *fd, frame_T *fr)
// Go back to the first window.
if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL
? "%dwincmd k" : "%dwincmd h", count) < 0
? ":%dwincmd k" : ":%dwincmd h", count) < 0
|| put_eol(fd) == FAIL))
return FAIL;
@@ -259,14 +259,14 @@ ses_winsizes(
// restore height when not full height
if (wp->w_height + wp->w_status_height < topframe->fr_height
&& (fprintf(fd,
"exe '%dresize ' . ((&lines * %ld + %ld) / %ld)",
"exe ':%dresize ' .. ((&lines * %ld + %ld) / %ld)",
n, (long)wp->w_height, Rows / 2, Rows) < 0
|| put_eol(fd) == FAIL))
return FAIL;
// restore width when not full width
if (wp->w_width < Columns && (fprintf(fd,
"exe 'vert %dresize ' . ((&columns * %ld + %ld) / %ld)",
"exe 'vert :%dresize ' .. ((&columns * %ld + %ld) / %ld)",
n, (long)wp->w_width, Columns / 2, Columns) < 0
|| put_eol(fd) == FAIL))
return FAIL;
@@ -339,7 +339,7 @@ put_view(
if (wp->w_arg_idx != current_arg_idx && wp->w_arg_idx < WARGCOUNT(wp)
&& flagp == &ssop_flags)
{
if (fprintf(fd, "%ldargu", (long)wp->w_arg_idx + 1) < 0
if (fprintf(fd, ":%ldargu", (long)wp->w_arg_idx + 1) < 0
|| put_eol(fd) == FAIL)
return FAIL;
did_next = TRUE;
@@ -469,29 +469,32 @@ put_view(
// Restore the cursor line in the file and relatively in the
// window. Don't use "G", it changes the jumplist.
if (put_line(fd, "{") == FAIL)
return FAIL;
if (wp->w_height <= 0)
{
if (fprintf(fd, "let s:l = %ld", (long)wp->w_cursor.lnum) < 0)
if (fprintf(fd, " var l: number = %ld", (long)wp->w_cursor.lnum) < 0)
return FAIL;
}
else if (fprintf(fd,
"let s:l = %ld - ((%ld * winheight(0) + %ld) / %ld)",
" var l: number = %ld - ((%ld * winheight(0) + %ld) / %ld)",
(long)wp->w_cursor.lnum,
(long)(wp->w_cursor.lnum - wp->w_topline),
(long)wp->w_height / 2, (long)wp->w_height) < 0)
return FAIL;
if (put_eol(fd) == FAIL
|| put_line(fd, "if s:l < 1 | let s:l = 1 | endif") == FAIL
|| put_line(fd, "keepjumps exe s:l") == FAIL
|| put_line(fd, "normal! zt") == FAIL
|| fprintf(fd, "keepjumps %ld", (long)wp->w_cursor.lnum) < 0
|| put_line(fd, " if l < 1 | l = 1 | endif") == FAIL
|| put_line(fd, " keepjumps exe \":\" .. l") == FAIL
|| put_line(fd, " normal! zt") == FAIL
|| fprintf(fd, " keepjumps :%ld", (long)wp->w_cursor.lnum) < 0
|| put_eol(fd) == FAIL)
return FAIL;
// Restore the cursor column and left offset when not wrapping.
if (wp->w_cursor.col == 0)
{
if (put_line(fd, "normal! 0") == FAIL)
if (put_line(fd, " normal! 0") == FAIL)
return FAIL;
}
else
@@ -499,24 +502,27 @@ put_view(
if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0)
{
if (fprintf(fd,
"let s:c = %ld - ((%ld * winwidth(0) + %ld) / %ld)",
" var c: number = %ld - ((%ld * winwidth(0) + %ld) / %ld)",
(long)wp->w_virtcol + 1,
(long)(wp->w_virtcol - wp->w_leftcol),
(long)wp->w_width / 2, (long)wp->w_width) < 0
|| put_eol(fd) == FAIL
|| put_line(fd, "if s:c > 0") == FAIL
|| put_line(fd, " if c > 0") == FAIL
|| fprintf(fd,
" exe 'normal! ' . s:c . '|zs' . %ld . '|'",
" exe 'normal! ' .. c .. '|zs' .. %ld .. '|'",
(long)wp->w_virtcol + 1) < 0
|| put_eol(fd) == FAIL
|| put_line(fd, "else") == FAIL
|| put_view_curpos(fd, wp, " ") == FAIL
|| put_line(fd, "endif") == FAIL)
|| put_line(fd, " else") == FAIL
|| put_view_curpos(fd, wp, " ") == FAIL
|| put_line(fd, " endif") == FAIL)
return FAIL;
}
else if (put_view_curpos(fd, wp, "") == FAIL)
else if (put_view_curpos(fd, wp, " ") == FAIL)
return FAIL;
}
if (put_line(fd, "}") == FAIL)
return FAIL;
}
// Local directory, if the current flag is not view options or the "curdir"
@@ -566,7 +572,7 @@ store_session_globals(FILE *fd)
*t = 'n';
else if (*t == '\r')
*t = 'r';
if ((fprintf(fd, "let %s = %c%s%c",
if ((fprintf(fd, "g:%s = %c%s%c",
this_var->di_key,
(this_var->di_tv.v_type == VAR_STRING) ? '"'
: ' ',
@@ -591,7 +597,7 @@ store_session_globals(FILE *fd)
f = -f;
sign = '-';
}
if ((fprintf(fd, "let %s = %c%f",
if ((fprintf(fd, "g:%s = %c%f",
this_var->di_key, sign, f) < 0)
|| put_eol(fd) == FAIL)
return FAIL;
@@ -638,12 +644,21 @@ makeopens(
// Begin by setting the this_session variable, and then other
// sessionable variables.
# ifdef FEAT_EVAL
if (put_line(fd, "let v:this_session=expand(\"<sfile>:p\")") == FAIL)
if (put_line(fd, "v:this_session = expand(\"<sfile>:p\")") == FAIL)
goto fail;
if (put_line(fd, "doautoall SessionLoadPre") == FAIL)
goto fail;
if (put_line(fd, "var save_splitbelow: bool") == FAIL
|| put_line(fd, "var save_splitright: bool") == FAIL
|| put_line(fd, "var save_winminheight: number") == FAIL
|| put_line(fd, "var save_winminwidth: number") == FAIL
|| put_line(fd, "var wipebuf: number = -1") == FAIL
|| put_line(fd, "var shortmess_save: string") == FAIL)
goto fail;
if (ssop_flags & SSOP_GLOBALS)
if (store_session_globals(fd) == FAIL)
goto fail;
@@ -659,7 +674,7 @@ makeopens(
// Now a :cd command to the session directory or the current directory
if (ssop_flags & SSOP_SESDIR)
{
if (put_line(fd, "exe \"cd \" . escape(expand(\"<sfile>:p:h\"), ' ')")
if (put_line(fd, "exe \"cd \" .. escape(expand(\"<sfile>:p:h\"), ' ')")
== FAIL)
goto fail;
}
@@ -681,14 +696,14 @@ makeopens(
// Remember the buffer number.
if (put_line(fd, "if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''") == FAIL)
goto fail;
if (put_line(fd, " let s:wipebuf = bufnr('%')") == FAIL)
if (put_line(fd, " wipebuf = bufnr('%')") == FAIL)
goto fail;
if (put_line(fd, "endif") == FAIL)
goto fail;
// Save 'shortmess' if not storing options.
if ((ssop_flags & SSOP_OPTIONS) == 0
&& put_line(fd, "let s:shortmess_save = &shortmess") == FAIL)
&& put_line(fd, "shortmess_save = &shortmess") == FAIL)
goto fail;
// Set 'shortmess' for the following.
@@ -834,16 +849,16 @@ makeopens(
if (tab_topframe->fr_layout != FR_LEAF)
{
// Save current window layout.
if (put_line(fd, "let s:save_splitbelow = &splitbelow") == FAIL
|| put_line(fd, "let s:save_splitright = &splitright")
if (put_line(fd, "save_splitbelow = &splitbelow") == FAIL
|| put_line(fd, "save_splitright = &splitright")
== FAIL)
goto fail;
if (put_line(fd, "set splitbelow splitright") == FAIL)
goto fail;
if (ses_win_rec(fd, tab_topframe) == FAIL)
goto fail;
if (put_line(fd, "let &splitbelow = s:save_splitbelow") == FAIL
|| put_line(fd, "let &splitright = s:save_splitright")
if (put_line(fd, "&splitbelow = save_splitbelow") == FAIL
|| put_line(fd, "&splitright = save_splitright")
== FAIL)
goto fail;
}
@@ -874,8 +889,8 @@ makeopens(
// cursor can be set. This is done again below.
// winminheight and winminwidth need to be set to avoid an error if
// the user has set winheight or winwidth.
if (put_line(fd, "let s:save_winminheight = &winminheight") == FAIL
|| put_line(fd, "let s:save_winminwidth = &winminwidth")
if (put_line(fd, "save_winminheight = &winminheight") == FAIL
|| put_line(fd, "save_winminwidth = &winminwidth")
== FAIL)
goto fail;
if (put_line(fd, "set winminheight=0") == FAIL
@@ -925,7 +940,7 @@ makeopens(
cur_arg_idx = next_arg_idx;
// Restore cursor to the current window if it's not the first one.
if (cnr > 1 && (fprintf(fd, "%dwincmd w", cnr) < 0
if (cnr > 1 && (fprintf(fd, ":%dwincmd w", cnr) < 0
|| put_eol(fd) == FAIL))
goto fail;
@@ -950,15 +965,13 @@ makeopens(
goto fail;
// Wipe out an empty unnamed buffer we started in.
if (put_line(fd, "if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0")
if (put_line(fd, "if wipebuf != -1 && len(win_findbuf(wipebuf)) == 0")
== FAIL)
goto fail;
if (put_line(fd, " silent exe 'bwipe ' . s:wipebuf") == FAIL)
if (put_line(fd, " silent exe 'bwipe ' .. wipebuf") == FAIL)
goto fail;
if (put_line(fd, "endif") == FAIL)
goto fail;
if (put_line(fd, "unlet! s:wipebuf") == FAIL)
goto fail;
// Re-apply 'winheight' and 'winwidth'.
if (fprintf(fd, "set winheight=%ld winwidth=%ld",
@@ -973,22 +986,22 @@ makeopens(
}
else
{
if (put_line(fd, "let &shortmess = s:shortmess_save") == FAIL)
if (put_line(fd, "&shortmess = shortmess_save") == FAIL)
goto fail;
}
if (restore_height_width)
{
// Restore 'winminheight' and 'winminwidth'.
if (put_line(fd, "let &winminheight = s:save_winminheight") == FAIL
|| put_line(fd, "let &winminwidth = s:save_winminwidth") == FAIL)
if (put_line(fd, "&winminheight = save_winminheight") == FAIL
|| put_line(fd, "&winminwidth = save_winminwidth") == FAIL)
goto fail;
}
// Lastly, execute the x.vim file if it exists.
if (put_line(fd, "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"") == FAIL
|| put_line(fd, "if filereadable(s:sx)") == FAIL
|| put_line(fd, " exe \"source \" . fnameescape(s:sx)") == FAIL
if (put_line(fd, "var sx: string = expand(\"<sfile>:p:r\") .. \"x.vim\"") == FAIL
|| put_line(fd, "if filereadable(sx)") == FAIL
|| put_line(fd, " exe \"source \" .. fnameescape(sx)") == FAIL
|| put_line(fd, "endif") == FAIL)
goto fail;
@@ -1137,9 +1150,9 @@ write_session_file(char_u *filename)
fd = open_exfile(filename, TRUE, APPENDBIN);
failed = (fd == NULL
|| put_line(fd, "let v:this_session = Save_VV_this_session")
|| put_line(fd, "v:this_session = g:Save_VV_this_session")
== FAIL
|| put_line(fd, "unlet Save_VV_this_session") == FAIL);
|| put_line(fd, "unlet g:Save_VV_this_session") == FAIL);
if (fd != NULL && fclose(fd) != 0)
failed = TRUE;
@@ -1177,6 +1190,10 @@ ex_mkrc(exarg_T *eap)
char_u *viewFile = NULL;
unsigned *flagp;
#endif
#if defined(FEAT_EVAL)
int sid;
scriptitem_T *si = NULL;
#endif
if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview)
{
@@ -1258,6 +1275,10 @@ ex_mkrc(exarg_T *eap)
mksession_nl = TRUE;
#endif
// Enforce vim9script
if (put_line(fd, "vim9script") == FAIL)
failed = TRUE;
// Write the version command for :mkvimrc
if (eap->cmdidx == CMD_mkvimrc)
(void)put_line(fd, "version 6.0");
@@ -1265,7 +1286,7 @@ ex_mkrc(exarg_T *eap)
#ifdef FEAT_SESSION
if (eap->cmdidx == CMD_mksession)
{
if (put_line(fd, "let SessionLoad = 1") == FAIL)
if (put_line(fd, "g:SessionLoad = 1") == FAIL)
failed = TRUE;
}
@@ -1283,23 +1304,47 @@ ex_mkrc(exarg_T *eap)
#ifdef FEAT_SESSION
if (!view_session
|| (eap->cmdidx == CMD_mksession
&& (*flagp & SSOP_OPTIONS)))
&& (*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS))))
#endif
{
bool do_mappings = true;
int flags = OPT_GLOBAL;
#ifdef FEAT_SESSION
if (eap->cmdidx == CMD_mksession && (*flagp & SSOP_SKIP_RTP))
flags |= OPT_SKIPRTP;
failed |= put_line(fd, "var cpo_save: string") == FAIL;
if (eap->cmdidx == CMD_mksession)
{
if (*flagp & SSOP_SKIP_RTP)
flags |= OPT_SKIPRTP;
// SSOP_LOCALOPTIONS requires only local mappings
do_mappings = *flagp & SSOP_OPTIONS;
}
#endif
failed |= (makemap(fd, NULL) == FAIL
if (do_mappings)
failed |= (makemap(fd, NULL) == FAIL
|| makeset(fd, flags, FALSE) == FAIL);
#if defined(FEAT_EVAL)
// Save delay load import modules.
// Either SSOP_LOCALOPTIONS or SSOP_OPTIONS require them
for (sid = 1; sid <= script_items.ga_len; ++sid)
{
si = SCRIPT_ITEM(sid);
if (si->sn_autoload_prefix &&
(fprintf(fd, "import autoload '%s'", si->sn_name) < 0 ||
put_eol(fd) == FAIL))
failed = TRUE;
}
#endif
}
#ifdef FEAT_SESSION
if (!failed && view_session)
{
if (put_line(fd, "let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1") == FAIL)
if (put_line(fd, "const so_save: number = &g:so | const siso_save: number = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1") == FAIL)
failed = TRUE;
if (eap->cmdidx == CMD_mksession)
{
@@ -1341,11 +1386,11 @@ ex_mkrc(exarg_T *eap)
}
else
{
failed |= put_line(fd, "var cpo_save: string") == FAIL;
failed |= (put_view(fd, curwin, curtab, !using_vdir, flagp, -1,
NULL) == FAIL);
}
if (put_line(fd, "let &g:so = s:so_save | let &g:siso = s:siso_save")
== FAIL)
if (put_line(fd, "&g:so = so_save | &g:siso = siso_save") == FAIL)
failed = TRUE;
# ifdef FEAT_SEARCH_EXTRA
if (no_hlsearch && put_line(fd, "nohlsearch") == FAIL)
@@ -1355,12 +1400,13 @@ ex_mkrc(exarg_T *eap)
failed = TRUE;
if (eap->cmdidx == CMD_mksession)
{
if (put_line(fd, "unlet SessionLoad") == FAIL)
if (put_line(fd, "unlet g:SessionLoad") == FAIL)
failed = TRUE;
}
}
#endif
if (put_line(fd, "\" vim: set ft=vim :") == FAIL)
if (put_line(fd, "# vim: set ft=vim :") == FAIL)
failed = TRUE;
failed |= fclose(fd);
+1 -1
View File
@@ -1199,10 +1199,10 @@ endfunc
" Closing a window might cause an endless loop
" E814 for older Vims
func Test_autocmd_bufwipe_in_SessLoadPost()
set noswapfile
edit Xtest
tabnew
file Xsomething
set noswapfile
mksession!
let content =<< trim [CODE]
+298 -34
View File
@@ -75,9 +75,9 @@ func Test_mksession()
\ ' four leadinG spaces',
\ 'two consecutive tabs',
\ 'two tabs in one line',
\ 'one ä multibyteCharacter',
\ 'aä Ä two multiByte characters',
\ 'Aäöü three mulTibyte characters',
\ 'one ä multibyteCharacter',
\ 'aä Ä two multiByte characters',
\ 'Aäöü three mulTibyte characters',
\ 'short line',
\ ])
let tmpfile = 'Xtemp'
@@ -126,33 +126,33 @@ func Test_mksession()
mksession! Xtest_mks.out
let li = filter(readfile('Xtest_mks.out'), 'v:val =~# "\\(^ *normal! [0$]\\|^ *exe ''normal!\\)"')
let expected = [
\ 'normal! 016|',
\ 'normal! 016|',
\ 'normal! 016|',
\ 'normal! 08|',
\ 'normal! 08|',
\ 'normal! 016|',
\ 'normal! 016|',
\ 'normal! 016|',
\ 'normal! $',
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
\ " normal! 016|",
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
\ " normal! 016|",
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
\ " normal! 016|",
\ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
\ " normal! 08|",
\ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
\ " normal! 08|",
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
\ " normal! 016|",
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
\ " normal! 016|",
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
\ " normal! 016|",
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
\ " normal! 016|"
\ ' normal! 016|',
\ ' normal! 016|',
\ ' normal! 016|',
\ ' normal! 08|',
\ ' normal! 08|',
\ ' normal! 016|',
\ ' normal! 016|',
\ ' normal! 016|',
\ ' normal! $',
\ " exe 'normal! ' .. c .. '|zs' .. 16 .. '|'",
\ " normal! 016|",
\ " exe 'normal! ' .. c .. '|zs' .. 16 .. '|'",
\ " normal! 016|",
\ " exe 'normal! ' .. c .. '|zs' .. 16 .. '|'",
\ " normal! 016|",
\ " exe 'normal! ' .. c .. '|zs' .. 8 .. '|'",
\ " normal! 08|",
\ " exe 'normal! ' .. c .. '|zs' .. 8 .. '|'",
\ " normal! 08|",
\ " exe 'normal! ' .. c .. '|zs' .. 16 .. '|'",
\ " normal! 016|",
\ " exe 'normal! ' .. c .. '|zs' .. 16 .. '|'",
\ " normal! 016|",
\ " exe 'normal! ' .. c .. '|zs' .. 16 .. '|'",
\ " normal! 016|",
\ " exe 'normal! ' .. c .. '|zs' .. 16 .. '|'",
\ " normal! 016|"
\ ]
call assert_equal(expected, li)
tabclose!
@@ -1066,7 +1066,7 @@ func Test_mksession_winminheight()
let found_restore = 0
let lines = readfile('Xtest_mks.out')
for line in lines
if line =~ '= s:save_winmin\(width\|height\)'
if line =~ '= save_winmin\(width\|height\)'
let found_restore += 1
endif
endfor
@@ -1088,11 +1088,11 @@ func Test_mksession_shortmess()
for line in lines
let line = trim(line)
if line ==# 'let s:shortmess_save = &shortmess'
if line ==# 'shortmess_save = &shortmess'
let found_save += 1
endif
if found_save !=# 0 && line ==# 'let &shortmess = s:shortmess_save'
if found_save !=# 0 && line ==# '&shortmess = shortmess_save'
let found_restore += 1
endif
endfor
@@ -1109,7 +1109,7 @@ func Test_mksession_shortmess()
let found_restore = 0
let lines = readfile('Xtest_mks.out')
for line in lines
if line =~# 's:shortmess_save'
if line =~# '\(var \)\@<!shortmess_save'
let found_restore += 1
endif
endfor
@@ -1331,4 +1331,268 @@ func Test_mkview_default_home()
endif
endfunc
" Test vim9 expression mappings
func Test_mksession_vim9_expr_mappings()
CheckFeature packages
" Create a dummy vim9 plugin
const base = getcwd() . '/rtdir'
const root = base . '/pack/test/opt/dummy9'
call mkdir(root . '/plugin', 'p')
let plugin_sources =<< trim END
vim9script
import autoload 'dummy9.vim'
nnoremap <expr> dummy-test dummy9.Test() .. "<CR>"
END
call writefile(plugin_sources, root . '/plugin/dummy9.vim')
call mkdir(root . '/autoload', 'p')
let auto_sources =<< trim END
vim9script
const ref_txt = 'Hello from vim9 dummy plugin!'
export def Test(): string
writefile([ref_txt], 'XDummyOutput')
return has("gui_running") ? '' : $':echomsg "{ref_txt}"'
enddef
END
call writefile(auto_sources, root . '/autoload/dummy9.vim')
" clean up later
defer delete(base, 'rf')
" Load and check the plugin
const ref_txt = 'Hello from vim9 dummy plugin!'
let &packpath .= ',' . base
packadd dummy9
messages clear
normal dummy-test
if !has('gui_running')
call assert_match(ref_txt, execute('messages'), 'No vim9 plugin dummy.Test() execution')
endif
call assert_true(filereadable('XDummyOutput'), 'Output file was not created by Vim9 plugin')
call assert_equal([ref_txt], readfile('XDummyOutput'))
call delete('XDummyOutput')
" Create a session file
mksession! XDummySession.vim
defer delete('XDummySession.vim')
call assert_true(filereadable('XDummySession.vim'), 'Session file was not created')
" Check the session file mappings are operational
let test_sources =<< trim END
" load session
source XDummySession.vim
" execute vim9 expression mapping
normal dummy-test
" on my way
cq
END
call writefile(test_sources, 'XTest.vim', 'D')
" spawn a new Vim instance to load the session and execute the mapping
call system(GetVimCommand('XTest.vim'))
defer delete('XDummyOutput')
call assert_true(filereadable('XDummyOutput'),
\ 'Expected output file was not created by Vim9 plugin')
call assert_equal([ref_txt], readfile('XDummyOutput'))
endfunc
" Test legacy vimscript expression mappings
func Test_mksession_legacy_expr_mappings()
CheckFeature packages
" Create a dummy vim9 plugin
const base = getcwd() . '/rtdir'
const root = base . '/pack/test/opt/dummy'
call mkdir(root . '/plugin', 'p')
" clean up later
defer delete(base, 'rf')
let plugin_sources =<< trim END
nnoremap <expr> dummy-test dummy#Test() . "<CR>"
END
call writefile(plugin_sources, root . '/plugin/dummy.vim')
call mkdir(root . '/autoload', 'p')
let auto_sources =<< trim END
const s:ref_txt = 'Hello from good old dummy plugin!'
func dummy#Test()
call writefile([s:ref_txt], 'XDummyOutput')
return has("gui_running") ? '' : $':echomsg "{s:ref_txt}"'
endfunc
END
call writefile(auto_sources, root . '/autoload/dummy.vim')
" Load and check the plugin
const ref_txt = 'Hello from good old dummy plugin!'
let &packpath .= ',' . base
packadd dummy
messages clear
normal dummy-test
if !has("gui_running")
call assert_match(ref_txt, execute('messages'), 'No vim9 plugin dummy.Test() execution')
endif
call assert_true(filereadable('XDummyOutput'), 'Output file was not created by legacy plugin')
call assert_equal([ref_txt], readfile('XDummyOutput'))
call delete('XDummyOutput')
" Create a session file
mksession! XDummySession.vim
defer delete('XDummySession.vim')
call assert_true(filereadable('XDummySession.vim'), 'Session file was not created')
" Check the session file mappings are operational
let test_sources =<< trim END
" load session
source XDummySession.vim
" execute legacy vimscript expression mapping
normal dummy-test
" on my way
cq
END
call writefile(test_sources, 'XTest.vim', 'D')
" spawn a new Vim instance to load the session and execute the mapping
call system(GetVimCommand('XTest.vim'))
defer delete('XDummyOutput')
call assert_true(filereadable('XDummyOutput'),
\ 'Expected output file was not created by legacy vim plugin')
call assert_equal([ref_txt], readfile('XDummyOutput'))
endfunc
" Test sessions cursor position management
func Test_mksession_cursor_position()
" Set windows test scenario
let files = []
for i in range(10)
let file = $'Xfile{i}'
exe $"{i ? 'split' : 'edit'} {file}"
call append(0, $"Session file cursor position testing {i}")
" Force cursor position restoring commands
setlocal nowrap
normal dd29zl
" Check expected position
call assert_equal([0, 1, 30, 0], getpos('.'), $"Fail to set cursor position for {file}")
write!
let files += [file]
endfor
" Save session
mksession! Xtest_curpos
" Test restoring session
%bwipe!
try
source Xtest_curpos
catch
call assert_report("Failure sourcing session file")
endtry
" Check cursor position
for file in files
exe $"drop {file}"
call assert_equal([0, 1, 30, 0], getpos('.'), $"Cursor position not restored correctly for {file}")
endfor
" Clean up
call delete('Xtest_curpos')
for file in files
call delete(file)
endfor
endfunc
" Test sessions global and local mappings
func Test_mksession_localmappings()
" Create sessions. Mapping execution is tested running a file
let valid_sessions = [] " keep map info
let invalid_sessions = [] " do not keep map info
" localoptions requires a buffer
setlocal noswapfile
silent write XDummy
defer delete('XDummy')
for option in ["&", "=options", "=localoptions"]
for global in [0, 1]
" select options
exe "set sessionoptions" .. option
" mapping
exe "nnoremap" . (global ? " " : " <buffer> ")
\ . "dummy-test <Cmd>silent write XDummyOutput<CR>"
let case = $"mapping_{global ? "global" : "local"}_{option}"
" test mapping
normal dummy-test
call assert_true(filereadable("XDummyOutput"), $"Output file was not created by {case}")
call delete("XDummyOutput")
" session
let sessionfile = "XSession_" . case
exe $"mksession {sessionfile}"
if global && option =~ "localoptions"
let invalid_sessions += [sessionfile]
else
let valid_sessions += [sessionfile]
endif
" clear mappings
nmapclear
nmapclear <buffer>
endfor
endfor
" Check the session files are operational
for session in valid_sessions
let test_sources =<< trim eval END
" load session
silent source {session}
" execute legacy vimscript expression mapping
normal dummy-test
" on my way
cq
END
call writefile(test_sources, 'XTest.vim')
call system(GetVimCommand('XTest.vim'))
call assert_true(filereadable('XDummyOutput'),
\ $"Expected map not defined in session file {session}")
call delete('XDummyOutput')
call delete(session)
endfor
for session in invalid_sessions
let test_sources =<< trim eval END
" load session
silent source {session}
" execute legacy vimscript expression mapping
normal dummy-test
" on my way
cq
END
call writefile(test_sources, 'XTest.vim')
call system(GetVimCommand('XTest.vim'))
call assert_false(filereadable('XDummyOutput'),
\ $"Unexpected map defined in session file {session}")
if filereadable('XDummyOutput')
call delete('XDummyOutput')
endif
call delete(session)
endfor
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+22 -18
View File
@@ -64,34 +64,38 @@ func Test_mksession_utf8()
mksession! test_mks.out
let li = filter(readfile('test_mks.out'), 'v:val =~# "\\(^ *normal! 0\\|^ *exe ''normal!\\)"')
let expected =<< trim [DATA]
normal! 016|
normal! 016|
normal! 016|
normal! 08|
normal! 08|
normal! 016|
normal! 016|
normal! 016|
exe 'normal! ' . s:c . '|zs' . 16 . '|'
|
normal! 016|
exe 'normal! ' . s:c . '|zs' . 16 . '|'
normal! 016|
exe 'normal! ' . s:c . '|zs' . 16 . '|'
normal! 016|
exe 'normal! ' . s:c . '|zs' . 8 . '|'
normal! 08|
exe 'normal! ' . s:c . '|zs' . 8 . '|'
normal! 08|
exe 'normal! ' . s:c . '|zs' . 16 . '|'
normal! 016|
exe 'normal! ' . s:c . '|zs' . 16 . '|'
normal! 016|
exe 'normal! ' . s:c . '|zs' . 16 . '|'
normal! 016|
exe 'normal! ' . s:c . '|zs' . 16 . '|'
normal! 016|
exe 'normal! ' .. c .. '|zs' .. 16 .. '|'
normal! 016|
exe 'normal! ' .. c .. '|zs' .. 16 .. '|'
normal! 016|
exe 'normal! ' .. c .. '|zs' .. 16 .. '|'
normal! 016|
exe 'normal! ' .. c .. '|zs' .. 8 .. '|'
normal! 08|
exe 'normal! ' .. c .. '|zs' .. 8 .. '|'
normal! 08|
exe 'normal! ' .. c .. '|zs' .. 16 .. '|'
normal! 016|
exe 'normal! ' .. c .. '|zs' .. 16 .. '|'
normal! 016|
exe 'normal! ' .. c .. '|zs' .. 16 .. '|'
normal! 016|
exe 'normal! ' .. c .. '|zs' .. 16 .. '|'
normal! 016|
[DATA]
" remove indent marker
call remove(expected, 0)
call assert_equal(expected, li)
tabclose!
+2
View File
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
579,
/**/
578,
/**/