Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add XDG_BASE_DIR support #14182

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions runtime/doc/freedesktop.txt
Original file line number Diff line number Diff line change
@@ -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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed those when merging. You should probably compare against what was committed instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:
3 changes: 2 additions & 1 deletion runtime/doc/starting.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are changing also changing 'runtimepath' and 'packpath'. That should also be documented.

MS-Windows $HOME/_vimrc, $HOME/vimfiles/vimrc
or $VIM/_vimrc
Amiga s:.vimrc, home:.vimrc, home:vimfiles:vimrc
Expand Down
4 changes: 4 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
61 changes: 61 additions & 0 deletions src/option.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options[opt_idx].def_val[VI_DEFAULT] = xdg_rtp;

This just overrides the default, right? I guess, this is not needed or is it?

Copy link
Contributor Author

@saccarosium saccarosium Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'packpath' defaults to DFLT_RUNTIMEPATH witch is:

// src/os_unix.h

#  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
// src/optiondefs.h

    {"packpath",    "pp",   P_STRING|P_VI_DEF|P_EXPAND|P_ONECOMMA|P_NODUP
								    |P_SECURE,
			    (char_u *)&p_pp, PV_NONE, NULL, NULL,
			    {(char_u *)DFLT_RUNTIMEPATH, (char_u *)0L}
			    SCTX_INIT},

It should be need it unless I do the checks when initializing the options. But I don't know if there is a benefit or not

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I know. I was just wondering if we need to override the default or if simply setting the option pointer is enough.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you want :set packpath& to do? Doesn't the default have to be overwritten with the XDG path for that command to restore the initial state?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, yes makes sense. Thanks

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
Expand Down Expand Up @@ -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

Expand Down
14 changes: 13 additions & 1 deletion src/os_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this change? That seems unrelated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got a strange bug where it did expanded correctly (I was probably doing something wrong). Also is more consistent between other prepocessor variables. I can adress it in another PR if you want to.

# endif
#endif

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/testdir/Make_all.mak
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ NEW_TESTS = \
test_wnext \
test_wordcount \
test_writefile \
test_xdg \
test_xxd \
test_alot_latin \
test_alot_utf8 \
Expand Down Expand Up @@ -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 \
Expand Down
34 changes: 34 additions & 0 deletions src/testdir/test_xdg.vim
Original file line number Diff line number Diff line change
@@ -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
Loading