From 1b69a9a9c12fb7df3888d7d0e5ac39e6249813ef Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Mon, 11 Mar 2024 22:21:31 +0100 Subject: [PATCH 1/5] Add XDG_CONFIG_HOME/vim/vimrc support --- runtime/doc/starting.txt | 3 ++- src/main.c | 4 ++++ src/os_unix.h | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index ff069ca3f40e1..37ed0c30a89c0 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -809,7 +809,8 @@ accordingly. Vim proceeds in this order: 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 diff --git a/src/main.c b/src/main.c index 770726f6d3a80..64563cede0602 100644 --- 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 diff --git a/src/os_unix.h b/src/os_unix.h index 4c77e158629f2..3a1e06a1445a8 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -249,6 +249,12 @@ typedef struct dsc$descriptor DESC; # endif #endif +#ifndef XDG_VIMRC_FILE +# define XDG_VIMRC_FILE mch_getenv("XDG_CONFIG_HOME") \ + ? "$XDG_CONFIG_HOME/vim/vimrc" \ + : "~/.config/vim/vimrc" +#endif + #if !defined(USR_VIMRC_FILE3) && defined(VMS) # define USR_VIMRC_FILE3 "sys$login:_vimrc" #endif From 54ed71efbf755a98e9735c9cdcc47fd252b7ed72 Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Mon, 18 Mar 2024 22:26:00 +0100 Subject: [PATCH 2/5] Add XDG_CONFIG_HOME runtimepath support --- src/option.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/os_unix.h | 12 +++++++--- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/option.c b/src/option.c index 8123a2a2c6315..425aea110e0ad 100644 --- a/src/option.c +++ b/src/option.c @@ -364,6 +364,71 @@ 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: + * + */ + 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; + + if ((opt_idx = findoption((char_u *)"viminfo")) < 0) + goto theend; + + options[opt_idx].def_val[VI_DEFAULT] = 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 +653,7 @@ set_init_1(int clean_arg) set_options_default(0); #ifdef UNIX + set_init_xdg_rtp(); set_init_restricted_mode(); #endif diff --git a/src/os_unix.h b/src/os_unix.h index 3a1e06a1445a8..100d55b50ed24 100644 --- 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 @@ -251,8 +251,8 @@ typedef struct dsc$descriptor DESC; #ifndef XDG_VIMRC_FILE # define XDG_VIMRC_FILE mch_getenv("XDG_CONFIG_HOME") \ - ? "$XDG_CONFIG_HOME/vim/vimrc" \ - : "~/.config/vim/vimrc" + ? (char_u *)"$XDG_CONFIG_HOME/vim/vimrc" \ + : (char_u *)"~/.config/vim/vimrc" #endif #if !defined(USR_VIMRC_FILE3) && defined(VMS) @@ -355,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/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/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 From fc6605ad40256b81b500bf420fddf25d610dc3bd Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Tue, 19 Mar 2024 09:29:37 +0100 Subject: [PATCH 3/5] Fix typo in XDG_RUNTIMEPATH --- src/option.c | 5 ----- src/os_unix.h | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/option.c b/src/option.c index 425aea110e0ad..48ab3ed28598a 100644 --- a/src/option.c +++ b/src/option.c @@ -415,11 +415,6 @@ set_init_xdg_rtp(void) options[opt_idx].def_val[VI_DEFAULT] = xdg_rtp; p_pp = xdg_rtp; - if ((opt_idx = findoption((char_u *)"viminfo")) < 0) - goto theend; - - options[opt_idx].def_val[VI_DEFAULT] = xdg_rtp; - theend: vim_free(vimrc1); vim_free(vimrc2); diff --git a/src/os_unix.h b/src/os_unix.h index 100d55b50ed24..37b0ba2e18d49 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -355,12 +355,12 @@ 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/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/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 From 37ded4a4165f10ae052ec0b0c4102f7a7095d500 Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Fri, 22 Mar 2024 18:05:02 +0100 Subject: [PATCH 4/5] Adding documentation on freedesktop and xdg --- runtime/doc/freedesktop.txt | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 runtime/doc/freedesktop.txt diff --git a/runtime/doc/freedesktop.txt b/runtime/doc/freedesktop.txt new file mode 100644 index 0000000000000..5458f7fdcf989 --- /dev/null +++ b/runtime/doc/freedesktop.txt @@ -0,0 +1,46 @@ +*freedesktop.txt* For Vim version 9.1. Last change: 2024 Mar 20 + + + VIM REFERENCE MANUAL by Bram Moolenaar + + + *freedesktop* *X-desktop-group* *xdg* +This file contains some information on what it is freedesktop and the XDG +families of specifications. + +Freedesktop is a project aiming to develop specifications to enable +interoperability between Unix-like operating systems. + +Vim tries to conform, for some extent, to the specifications made by +freedesktop (see |xdg-base-dir|). + +============================================================================== +XDG Base Directory Specification *xdg-base-dir* *$XDG_CONFIG_HOME* + +The XDG Base Directory Specification aim to define standard locations for the +multilple data e configuration files used by applications. In order to divide +this files by their use and not by application. This is mainly done to go +against the legacy behavior of dumping everything in the home directory. + +This directories should be overwritable by the user, using environment +variable but should also give fallback in case those variables weren't set. + +This is a not exhaustive of those directories: + 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 + + *xdg-vimrc* +Vim, on Unix systems, will look at `$XDG_CONFIG_HOME/vim/vimrc` for +configuration (see |vimrc|) but it will source it only if no other rc is found +in `$HOME` or `$HOME/vim`. + + *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" +< + + vim:tw=78:ts=8:noet:ft=help:norl: From a2a413e2b51a28cb07c3ab7d538e29c3561a4db8 Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Thu, 11 Apr 2024 15:44:12 +0200 Subject: [PATCH 5/5] Add tests for XDG_VIMRC detection --- src/testdir/Make_all.mak | 2 ++ src/testdir/test_xdg.vim | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/testdir/test_xdg.vim diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index c4403e67ae6ff..e82839dafbab9 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -329,6 +329,7 @@ NEW_TESTS = \ test_wnext \ test_wordcount \ test_writefile \ + test_xdg \ test_xxd \ test_alot_latin \ test_alot_utf8 \ @@ -561,6 +562,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 \ diff --git a/src/testdir/test_xdg.vim b/src/testdir/test_xdg.vim new file mode 100644 index 0000000000000..b7477c9e6cf6e --- /dev/null +++ b/src/testdir/test_xdg.vim @@ -0,0 +1,34 @@ +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() + if !has('unix') + return v:false + endif + 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 + +" vim: shiftwidth=2 sts=2 expandtab