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

Commit: 
https://github.com/vim/vim/commit/d69cf0dbcfdd721d94189ffa1558660c96129627
Author: Miguel Barro <[email protected]>
Date:   Sun May 31 21:03:12 2026 +0000

    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 <[email protected]>
    Signed-off-by: Miguel Barro <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 29882b4d5..2496d1b69 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -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 ~
 -----------------
diff --git a/src/fold.c b/src/fold.c
index b9b54d8fc..19c444c14 100644
--- a/src/fold.c
+++ b/src/fold.c
@@ -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
diff --git a/src/map.c b/src/map.c
index 1c0d0ac7f..34e465ec3 100644
--- a/src/map.c
+++ b/src/map.c
@@ -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;
diff --git a/src/session.c b/src/session.c
index eed03269a..090448937 100644
--- a/src/session.c
+++ b/src/session.c
@@ -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 == '
')
                        *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);
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index ecd5791c9..a1f282e06 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -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]
diff --git a/src/testdir/test_mksession.vim b/src/testdir/test_mksession.vim
index 9dbd0094e..9bf1b47ff 100644
--- a/src/testdir/test_mksession.vim
+++ b/src/testdir/test_mksession.vim
@@ -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
diff --git a/src/testdir/test_mksession_utf8.vim 
b/src/testdir/test_mksession_utf8.vim
index d467dc20c..90695f0c8 100644
--- a/src/testdir/test_mksession_utf8.vim
+++ b/src/testdir/test_mksession_utf8.vim
@@ -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!
 
diff --git a/src/version.c b/src/version.c
index 80020f59f..95107bb28 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    579,
 /**/
     578,
 /**/

-- 
-- 
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 [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1wTnUv-00GaQL-Hz%40256bit.org.

Raspunde prin e-mail lui