changeset 34940:2d7721a4d213 v9.1.0327

patch 9.1.0327: No support for using $XDG_CONFIG_HOME Commit: https://github.com/vim/vim/commit/c9df1fb35a1866901c32df37dd39c8b39dbdb64a Author: Luca Saccarola <github.e41mv@aleeas.com> Date: Sun Apr 14 22:53:22 2024 +0200 patch 9.1.0327: No support for using $XDG_CONFIG_HOME Problem: No support for using $XDG_CONFIG_HOME Solution: optionally source $XDG_CONFIG_HOME/vim/vimrc (Luca Saccarola) fixes: #2034 closes: #14182 Signed-off-by: Luca Saccarola <github.e41mv@aleeas.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Sun, 14 Apr 2024 23:00:03 +0200
parents 2418c55e3ba6
children 47de9a5e08d1
files runtime/doc/starting.txt runtime/doc/tags runtime/doc/version9.txt src/main.c src/option.c src/os_unix.h src/testdir/Make_all.mak src/testdir/dumps/Test_xdg_1.dump src/testdir/dumps/Test_xdg_2.dump src/testdir/dumps/Test_xdg_3.dump src/testdir/dumps/Test_xdg_4.dump src/testdir/test_xdg.vim src/version.c
diffstat 13 files changed, 359 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -1,4 +1,4 @@
-*starting.txt*  For Vim version 9.1.  Last change: 2024 Mar 13
+*starting.txt*  For Vim version 9.1.  Last change: 2024 Apr 14
 
 
 		  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -811,7 +811,8 @@ 3. Execute Ex commands, from environment
 	name.  Also see |vimrc-intro|.
 
 	Places for your personal initializations:
-		Unix		$HOME/.vimrc or $HOME/.vim/vimrc
+		Unix		$HOME/.vimrc, $HOME/.vim/vimrc
+                                or $XDG_CONFIG_HOME/vim/vimrc
 		MS-Windows	$HOME/_vimrc, $HOME/vimfiles/vimrc
 				or $VIM/_vimrc
 		Amiga		s:.vimrc, home:.vimrc, home:vimfiles:vimrc
@@ -853,15 +854,16 @@ 3. Execute Ex commands, from environment
 	I   The environment variable VIMINIT (see also |compatible-default|) (*)
 	    The value of $VIMINIT is used as an Ex command line.
 	II  The user vimrc file(s):
-		    "$HOME/.vimrc"	   (for Unix) (*)
-		    "$HOME/.vim/vimrc"	   (for Unix) (*)
-		    "s:.vimrc"		   (for Amiga) (*)
-		    "home:.vimrc"	   (for Amiga) (*)
-		    "home:vimfiles:vimrc"  (for Amiga) (*)
-		    "$VIM/.vimrc"	   (for Amiga) (*)
-		    "$HOME/_vimrc"	   (for Win32) (*)
-		    "$HOME/vimfiles/vimrc" (for Win32) (*)
-		    "$VIM/_vimrc"	   (for Win32) (*)
+		    "$HOME/.vimrc"		(for Unix) (*)
+		    "$HOME/.vim/vimrc"		(for Unix) (*)
+		    "$HOME/.config/vim/vimrc"	(for Unix) (*)
+		    "s:.vimrc"			(for Amiga) (*)
+		    "home:.vimrc"		(for Amiga) (*)
+		    "home:vimfiles:vimrc"	(for Amiga) (*)
+		    "$VIM/.vimrc"		(for Amiga) (*)
+		    "$HOME/_vimrc"		(for Win32) (*)
+		    "$HOME/vimfiles/vimrc"	(for Win32) (*)
+		    "$VIM/_vimrc"		(for Win32) (*)
 		    "$HOME/config/settings/vim/vimrc"	(for Haiku) (*)
 
 		Note: For Unix and Amiga, when ".vimrc" does not exist,
@@ -1085,6 +1087,44 @@ defaults.vim from your .vimrc, first unl
 example above.
 
 
+					*xdg-base-dir* *$XDG_CONFIG_HOME*
+XDG Base Directory Specification ~
+
+The XDG Base Directory Specification aims to define a standard location for
+configuration files used by applications.  This is mainly done to prevent
+the legacy behavior of dumping everything into the users home directory.
+The specification can be found online at
+https://specifications.freedesktop.org/basedir-spec/latest/
+
+The location of this standard configuration directory is configurable by the
+user, using environment variable but should also give fallback in case those
+variables weren't set.
+
+This is a not an exhaustive list of those directories:
+   Environment var	default location	Description ~
+  `$XDG_CACHE_HOME`	$HOME/.cache		Ephemiral data files
+  `$XDG_CONFIG_HOME`	$HOME/.config		Configuration files
+  `$XDG_DATA_HOME`	$HOME/.local/share	Persistent data files
+  `$XDG_STATE_HOME`	$HOME/.local/state	State data files
+
+Vim will only care of the `$XDG_CONFIG_HOME` directory, the others are not
+(yet) used for its various configuration and state files.
+
+							*xdg-vimrc*
+Vim, on Unix systems, will look at `$XDG_CONFIG_HOME/vim/vimrc` for its
+configuration (see |vimrc|) but it will source it only if no other
+initialization file is found in `$HOME` or `$HOME/.vim` (thus making this
+feature backward compatible). However, if you want to migrate to use
+`$XDG_CONFIG_HOME/vim/` directory, you will have to move away your `~/.vimrc`
+and `~/.vim/vimrc` file.
+
+							*xdg-runtime*
+When the |xdg-vimrc| is used the |'runtimepath'| will be modified accordingly
+to respect the |xdg-base-dir|: >
+
+    "$XDG_CONFIG_HOME/vim,$VIMRUNTIME,/after,$XDG_CONFIG_HOME/vim/after"
+<
+
 Avoiding trojan horses ~
 							*trojan-horse*
 While reading the "vimrc" or the "exrc" file in the current directory, some
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -12,6 +12,7 @@
 $VIM-use	version5.txt	/*$VIM-use*
 $VIMRUNTIME	starting.txt	/*$VIMRUNTIME*
 $VIM_POSIX	vi_diff.txt	/*$VIM_POSIX*
+$XDG_CONFIG_HOME	starting.txt	/*$XDG_CONFIG_HOME*
 $quote	eval.txt	/*$quote*
 %	motion.txt	/*%*
 %:.	cmdline.txt	/*%:.*
@@ -11371,6 +11372,9 @@ x11-clientserver	remote.txt	/*x11-client
 x11-cut-buffer	gui_x11.txt	/*x11-cut-buffer*
 x11-selection	gui_x11.txt	/*x11-selection*
 xattr	editing.txt	/*xattr*
+xdg-base-dir	starting.txt	/*xdg-base-dir*
+xdg-runtime	starting.txt	/*xdg-runtime*
+xdg-vimrc	starting.txt	/*xdg-vimrc*
 xf86conf.vim	syntax.txt	/*xf86conf.vim*
 xfontset	mbyte.txt	/*xfontset*
 xfree-xterm	syntax.txt	/*xfree-xterm*
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -41543,6 +41543,8 @@ and is a work in progress.
 
 Support for Wayland UI.
 
+Support for the XDG Desktop Specification |xdg-base-dir|
+
 Vim9 script
 -----------
 Add support for internal builtin functions with vim9 objects, see
--- a/src/main.c
+++ b/src/main.c
@@ -3276,6 +3276,10 @@ source_startup_scripts(mparm_T *parmp)
 		&& do_source((char_u *)USR_VIMRC_FILE2, TRUE,
 						      DOSO_VIMRC, NULL) == FAIL
 #endif
+#ifdef XDG_VIMRC_FILE
+		&& do_source((char_u *)XDG_VIMRC_FILE, TRUE,
+						      DOSO_VIMRC, NULL) == FAIL
+#endif
 #ifdef USR_VIMRC_FILE3
 		&& do_source((char_u *)USR_VIMRC_FILE3, TRUE,
 						      DOSO_VIMRC, NULL) == FAIL
--- a/src/option.c
+++ b/src/option.c
@@ -364,6 +364,66 @@ set_init_clean_rtp(void)
 }
 #endif
 
+#ifdef UNIX
+/*
+ * Change 'runtimepath' and 'packdir' to '$XDG_CONFIG_HOME/vim' if the only
+ * vimrc found is located in '$XDG_CONFIG_HOME/vim/vimrc'.
+ * In case the '$XDG_CONFIG_HOME' variable is not set, '$HOME/.config' is used
+ * as a fallback as is defined in the XDG base dir specification:
+ * <https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>
+ */
+    static void
+set_init_xdg_rtp(void)
+{
+    int		opt_idx;
+    int		has_xdg_env = TRUE;
+    int		should_free_xdg_dir = FALSE;
+    char_u	*vimrc1 = NULL;
+    char_u	*vimrc2 = NULL;
+    char_u	*xdg_dir = NULL;
+    char_u	*xdg_rtp = NULL;
+    char_u	*vimrc_xdg = NULL;
+
+    vimrc1 = expand_env_save((char_u *)USR_VIMRC_FILE);
+    vimrc2 = expand_env_save((char_u *)USR_VIMRC_FILE2);
+
+    xdg_dir = mch_getenv("XDG_CONFIG_HOME");
+    if (!xdg_dir)
+    {
+	xdg_dir = expand_env_save((char_u *)"~/.config");
+	should_free_xdg_dir = TRUE;
+	has_xdg_env = FALSE;
+    }
+    vimrc_xdg = concat_fnames(xdg_dir, (char_u *)"vim/vimrc", TRUE);
+
+    if (file_is_readable(vimrc1) || file_is_readable(vimrc2) ||
+	    !file_is_readable(vimrc_xdg))
+	goto theend;
+
+    xdg_rtp = has_xdg_env ? (char_u *)XDG_RUNTIMEPATH
+	: (char_u *)XDG_RUNTIMEPATH_FB;
+
+    if ((opt_idx = findoption((char_u *)"runtimepath")) < 0)
+	goto theend;
+
+    options[opt_idx].def_val[VI_DEFAULT] = xdg_rtp;
+    p_rtp = xdg_rtp;
+
+    if ((opt_idx = findoption((char_u *)"packpath")) < 0)
+	goto theend;
+
+    options[opt_idx].def_val[VI_DEFAULT] = xdg_rtp;
+    p_pp = xdg_rtp;
+
+theend:
+    vim_free(vimrc1);
+    vim_free(vimrc2);
+    vim_free(vimrc_xdg);
+    if (should_free_xdg_dir)
+	vim_free(xdg_dir);
+}
+#endif
+
 /*
  * Expand environment variables and things like "~" for the defaults.
  * If option_expand() returns non-NULL the variable is expanded.  This can
@@ -588,6 +648,7 @@ set_init_1(int clean_arg)
     set_options_default(0);
 
 #ifdef UNIX
+    set_init_xdg_rtp();
     set_init_restricted_mode();
 #endif
 
--- a/src/os_unix.h
+++ b/src/os_unix.h
@@ -236,7 +236,7 @@ typedef struct dsc$descriptor   DESC;
 # ifdef VMS
 # define USR_VIMRC_FILE  "sys$login:.vimrc"
 # else
-#  define USR_VIMRC_FILE "$HOME/.vimrc"
+#  define USR_VIMRC_FILE "~/.vimrc"
 # endif
 #endif
 
@@ -249,6 +249,12 @@ typedef struct dsc$descriptor   DESC;
 # endif
 #endif
 
+#ifndef XDG_VIMRC_FILE
+# define XDG_VIMRC_FILE mch_getenv("XDG_CONFIG_HOME") \
+	? (char_u *)"$XDG_CONFIG_HOME/vim/vimrc" \
+	: (char_u *)"~/.config/vim/vimrc"
+#endif
+
 #if !defined(USR_VIMRC_FILE3) && defined(VMS)
 # define USR_VIMRC_FILE3 "sys$login:_vimrc"
 #endif
@@ -349,13 +355,19 @@ typedef struct dsc$descriptor   DESC;
 #  ifdef RUNTIME_GLOBAL
 #   ifdef RUNTIME_GLOBAL_AFTER
 #    define DFLT_RUNTIMEPATH	"~/.vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER ",~/.vim/after"
+#    define XDG_RUNTIMEPATH	"$XDG_CONFIG_HOME/vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER "/after,$XDG_CONFIG_HOME/vim/after"
+#    define XDG_RUNTIMEPATH_FB	"~/.config/vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER "/after,~/.config/vim/after"
 #    define CLEAN_RUNTIMEPATH	RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER
 #   else
 #    define DFLT_RUNTIMEPATH	"~/.vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after,~/.vim/after"
+#    define XDG_RUNTIMEPATH	"$XDG_CONFIG_HOME/vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after,$XDG_CONFIG_HOME/vim/after"
+#    define XDG_RUNTIMEPATH_FB	"~/.config/vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after,~/.config/vim/after"
 #    define CLEAN_RUNTIMEPATH	RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after"
 #   endif
 #  else
 #   define DFLT_RUNTIMEPATH	"~/.vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.vim/after"
+#   define XDG_RUNTIMEPATH	"$XDG_CONFIG_HOME/vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,$XDG_CONFIG_HOME/vim/after"
+#   define XDG_RUNTIMEPATH_FB	"~/.config/vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.config/vim/after"
 #   define CLEAN_RUNTIMEPATH	"$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
 #  endif
 # endif
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -331,6 +331,7 @@ NEW_TESTS = \
 	test_wnext \
 	test_wordcount \
 	test_writefile \
+	test_xdg \
 	test_xxd \
 	test_alot_latin \
 	test_alot_utf8 \
@@ -564,6 +565,7 @@ NEW_TESTS_RES = \
 	test_winfixbuf.res \
 	test_wordcount.res \
 	test_writefile.res \
+	test_xdg.res \
 	test_xxd.res \
 	test_alot_latin.res \
 	test_alot_utf8.res \
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_xdg_1.dump
@@ -0,0 +1,20 @@
+|~+0#4040ff13#ffffff0| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|r+0#0000000&|c|_|o|n|e| @16|o|n|e| @48
+|r|c| @20|.|v|i|m|r|c| @45
+|P+0#00e0003&|r|e|s@1| |E|N|T|E|R| |o|r| |t|y|p|e| |c|o|m@1|a|n|d| |t|o| |c|o|n|t|i|n|u|e> +0#0000000&@35
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_xdg_2.dump
@@ -0,0 +1,20 @@
+|~+0#4040ff13#ffffff0| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|r+0#0000000&|c|_|t|w|o| @16|t|w|o| @48
+|r|c| @20|.|v|i|m|/|v|i|m|r|c| @41
+|P+0#00e0003&|r|e|s@1| |E|N|T|E|R| |o|r| |t|y|p|e| |c|o|m@1|a|n|d| |t|o| |c|o|n|t|i|n|u|e> +0#0000000&@35
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_xdg_3.dump
@@ -0,0 +1,20 @@
+|~+0#4040ff13#ffffff0| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|r+0#0000000&|c|_|t|h|r|e@1| @14|t|h|r|e@1| @46
+|r|c| @20|.|c|o|n|f|i|g|/|v|i|m|/|v|i|m|r|c| @34
+|P+0#00e0003&|r|e|s@1| |E|N|T|E|R| |o|r| |t|y|p|e| |c|o|m@1|a|n|d| |t|o| |c|o|n|t|i|n|u|e> +0#0000000&@35
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_xdg_4.dump
@@ -0,0 +1,20 @@
+|~+0#4040ff13#ffffff0| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|r+0#0000000&|c|_|f|o|u|r| @15|f|o|u|r| @47
+|r|c| @20|x|d|g|/|v|i|m|/|v|i|m|r|c| @38
+|P+0#00e0003&|r|e|s@1| |E|N|T|E|R| |o|r| |t|y|p|e| |c|o|m@1|a|n|d| |t|o| |c|o|n|t|i|n|u|e> +0#0000000&@35
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_xdg.vim
@@ -0,0 +1,140 @@
+" Tests for the XDG feature
+
+source check.vim
+CheckFeature terminal
+
+source shared.vim
+source screendump.vim
+source mouse.vim
+source term_util.vim
+
+func s:get_rcs()
+  let rcs = {
+        \ 'file1': { 'path': '~/.vimrc' },
+        \ 'file2': { 'path': '~/.vim/vimrc' },
+        \ 'xdg': { 'path': exists('$XDG_CONFIG_HOME') ? '$XDG_CONFIG_HOME' : "~/.config" },
+        \}
+  for v in values(rcs)
+    let v.exists = filereadable(expand(v.path))
+  endfor
+  return rcs
+endfunc
+
+func Test_xdg_rc_detection()
+  CheckUnix
+  let rc = s:get_rcs()
+  let before =<< trim CODE
+    call writefile([expand('$MYVIMRC')], "XMY_VIMRC")
+    quit!
+  CODE
+  call RunVim(before, [], "")
+  let my_rc = readfile("XMY_VIMRC")
+  if rc.file1.exists
+    call assert_equal(rc.file1.path, my_rc)
+  elseif !rc.file1.exists && rc.file2.exists
+    call assert_equal(rc.file2.path, my_rc)
+  elseif !rc.file1.exists && !rc.file2.exists && rc.xdg.exists
+    call assert_equal(rc.xdg.path, my_rc)
+  endif
+  call delete("XMY_VIMRC")
+endfunc
+
+func Test_xdg_runtime_files()
+  " This tests, that the initialization file from
+  " ~/.vimrc, ~/.vim/vimrc and ~/.config/vim/vimrc (or
+  " $XDG_HOMECONFIG/vim/vimrc) are sourced in that order
+  CheckUnix
+  call mkdir(expand('~/.vim/'), 'pD')
+  call mkdir(expand('~/.config/vim/'), 'pD')
+  call mkdir(expand('~/xdg/vim/'), 'pD')
+ 
+  let rc1=expand('~/.vimrc')
+  let rc2=expand('~/.vim/vimrc')
+  let rc3=expand('~/.config/vim/vimrc')
+  let rc4=expand('~/xdg/vim/vimrc')
+
+  " g:rc_one|two|three|four is to verify, that the other
+  " init files are not source
+  " g:rc is to verify which rc file has been loaded.
+  let file1 =<< trim CODE
+    let g:rc_one = 'one'
+    let g:rc = '.vimrc'
+  CODE
+  let file2 =<< trim CODE
+    let g:rc_two = 'two'
+    let g:rc = '.vim/vimrc'
+  CODE
+  let file3 =<< trim CODE
+    let g:rc_three = 'three'
+    let g:rc = '.config/vim/vimrc'
+  CODE
+  let file4 =<< trim CODE
+    let g:rc_four = 'four'
+    let g:rc = 'xdg/vim/vimrc'
+  CODE
+  call writefile(file1, rc1)
+  call writefile(file2, rc2)
+  call writefile(file3, rc3)
+  call writefile(file4, rc4)
+
+  let rows = 20
+  let buf = RunVimInTerminal('', #{rows: rows, no_clean: 1})
+  call TermWait(buf)
+  call term_sendkeys(buf, ":echo \$MYVIMRC\<cr>")
+  call WaitForAssert({-> assert_match('XfakeHOME/\.vimrc', term_getline(buf, rows))})
+  call term_sendkeys(buf, ":call filter(g:, {idx, _ -> idx =~ '^rc'})\<cr>")
+  call TermWait(buf)
+  call term_sendkeys(buf, ":redraw!\<cr>")
+  call TermWait(buf)
+  call term_sendkeys(buf, ":let g:\<cr>")
+  call VerifyScreenDump(buf, 'Test_xdg_1', {})
+  call StopVimInTerminal(buf)
+  call delete(rc1)
+  bw
+
+  let buf = RunVimInTerminal('', #{rows: rows, no_clean: 1})
+  call TermWait(buf)
+  call term_sendkeys(buf, ":echo \$MYVIMRC\<cr>")
+  call WaitForAssert({-> assert_match('XfakeHOME/\.vim/vimrc', term_getline(buf, rows))})
+  call term_sendkeys(buf, ":call filter(g:, {idx, _ -> idx =~ '^rc'})\<cr>")
+  call TermWait(buf)
+  call term_sendkeys(buf, ":redraw!\<cr>")
+  call TermWait(buf)
+  call term_sendkeys(buf, ":let g:\<cr>")
+  call VerifyScreenDump(buf, 'Test_xdg_2', {})
+  call StopVimInTerminal(buf)
+  call delete(rc2)
+  bw
+
+  let buf = RunVimInTerminal('', #{rows: rows, no_clean: 1})
+  call TermWait(buf)
+  call term_sendkeys(buf, ":echo \$MYVIMRC\<cr>")
+  call WaitForAssert({-> assert_match('XfakeHOME/\.config/vim/vimrc', term_getline(buf, rows))})
+  call term_sendkeys(buf, ":call filter(g:, {idx, _ -> idx =~ '^rc'})\<cr>")
+  call TermWait(buf)
+  call term_sendkeys(buf, ":redraw!\<cr>")
+  call TermWait(buf)
+  call term_sendkeys(buf, ":let g:\<cr>")
+  call VerifyScreenDump(buf, 'Test_xdg_3', {})
+  call StopVimInTerminal(buf)
+  call delete(rc3)
+  bw
+
+  let $XDG_CONFIG_HOME=expand('~/xdg/')
+  let buf = RunVimInTerminal('', #{rows: rows, no_clean: 1})
+  call TermWait(buf)
+  call term_sendkeys(buf, ":redraw!\<cr>")
+  call TermWait(buf)
+  call term_sendkeys(buf, ":echo \$MYVIMRC\<cr>")
+  call WaitForAssert({-> assert_match('xdg/vim/vimrc', term_getline(buf, rows))})
+  call term_sendkeys(buf, ":call filter(g:, {idx, _ -> idx =~ '^rc'})\<cr>")
+  call TermWait(buf)
+  call term_sendkeys(buf, ":let g:\<cr>")
+  call VerifyScreenDump(buf, 'Test_xdg_4', {})
+  call StopVimInTerminal(buf)
+  call delete(rc4)
+  bw
+  unlet $XDG_CONFIG_HOME
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    327,
+/**/
     326,
 /**/
     325,