Thanks to visit codestin.com
Credit goes to github.com

Skip to content

defaults.vim: add XDG support#19421

Closed
bam80 wants to merge 8 commits intovim:masterfrom
bam80:patch-1
Closed

defaults.vim: add XDG support#19421
bam80 wants to merge 8 commits intovim:masterfrom
bam80:patch-1

Conversation

@bam80
Copy link
Contributor

@bam80 bam80 commented Feb 15, 2026

If the system has XDG basedirs for Vim already, do support them.

Fixes #19399

If the system has XDG basedirs for Vim already, do support them.
$XDG_CONFIG_HOME is supported by Vim itself,
other XDG dirs are handled by defaults.vim.
@bam80 bam80 marked this pull request as ready for review February 16, 2026 19:02
@chrisbra
Copy link
Member

I am not sure. defaults.vim is only sourced when the user does not have a vimrc file, so setting those paths in this case is a bit senseless I think. Also we have been trying to get away from defaults.vim, so adding stuff there should be avoided.

How about we either

  • document how to configure using the full XDG spec or
  • drop a file like this into $VIMRUNTIME, so users can simply :ru xdg.vim
let xdg_c = exists("$XDG_CONFIG_HOME") ? $XDG_CONFIG_HOME : "$HOME/.config"
let xdg_d = exists("$XDG_DATA_HOME")   ? $XDG_DATA_HOME   : "$HOME/.local/share/vim"
let xdg_s = exists("$XDG_STATE_HOME")  ? $XDG_STATE_HOME  : "$HOME/.local/state/vim"

if !isdirectory(xdg_d)
  call mkdir(xdg_d, 'p', 0700)
endif
if !isdirectory(xdg_s)
  call mkdir(xdg_s, 'p', 0700)
endif

let &packpath    = printf("%s,%s,%s/after", xdg_d, &packpath, xdg_d)
let &viminfofile = xdg_s .. "/viminfo"
let &backupdir   = xdg_s .. "/backup"
let &viewdir     = xdg_s .. "/view"
let &undodir     = xdg_s .. "/undo"
" the trailing slash is important
let &directory   = xdg_s .. "/swap//"

@bam80
Copy link
Contributor Author

bam80 commented Feb 16, 2026

I am not sure. defaults.vim is only sourced when the user does not have a vimrc file, so setting those paths in this case is a bit senseless I think. Also we have been trying to get away from defaults.vim, so adding stuff there should be avoided.

I actually targeted system vimrc file. In Fedora, it's /etc/vimrc (there is no $VIM/vimrc), and I don't know where they get this file from for sure. I decided it's most probably slightly modified copy (or different version) of defaults.vim or vimrc_example.vim, that is why I modified one of these files.

How about we either:

  • document how to configure using the full XDG spec or
  • drop a file like this into $VIMRUNTIME, so users can simply :ru xdg.vim

The intention here is to make Vim configure itself for XDG scheme automatically.
It should not require any interventions from the user, because if $XDG_CONFIG_HOME/vim/ directory exists, it means he explicitly created it, so it's already known he want's XDG scheme for Vim. That's all that should be necessary from the user, I believe.

@chrisbra
Copy link
Member

As I said, I won't enable this by default (and for some of those configuration changes, like swapfile) this would be backwards incompatible change. If users want this, they have to configure it. It's not that hard.

@bam80
Copy link
Contributor Author

bam80 commented Feb 16, 2026

But the script I suggested checks the presence of $XDG_CONFIG_HOME/vim/ directory, and only then makes any modifications. That shouldn't impose any incompatibilities, right?
We can make the condition even tighter, if you wish.

@chrisbra
Copy link
Member

chrisbra commented Feb 16, 2026

But it doesn't belong into defaults.vim. That would be effective only for some niche use-cases.

@bam80
Copy link
Contributor Author

bam80 commented Feb 16, 2026

Do you know where the system vimrc usually comes from?

@bam80
Copy link
Contributor Author

bam80 commented Feb 16, 2026

In Fedora, it's /etc/vimrc (there is no $VIM/vimrc), and I don't know where they get this file from for sure. I decided it's most probably slightly modified copy (or different version) of defaults.vim or vimrc_example.vim, that is why I modified one of these files.

Yes, apparently they maintain their own system vimrc and just pull things there from defaults.vim (I couldn't see the history):
https://src.fedoraproject.org/rpms/vim/c/c8b04c80dd1fcafe208a7969ab40c584e320d5f3?branch=rawhide

So for me, it would be good enough if we just include the code to defaults.vim, probably.
If you know better place where the code could be included or sourced from by default, please share.

@bam80
Copy link
Contributor Author

bam80 commented Feb 16, 2026

But it doesn't belong into defaults.vim.

We could separate the code to xdg.vim for clarity and just source it from there to defaults.vim.
That way even if we delete defaults.vim later, the valuable piece of code will still be kept with Vim.

@chrisbra
Copy link
Member

chrisbra commented Feb 17, 2026

I had a look. Fedora's /etc/vimrc appears to be a custom configuration specific to Fedora, heavily inspired by defaults.vim, but not identical. For example, it still sets history=50, whereas the current default is already 200. @zdohnal fyi.

In any case, if people think such an xdg.vim makes sense, I am happy to provide it with Vim. In the same spirit, we could also support %AppData% for MS-Windows users. However, I do not want to change the defaults, as that would likely cause significant backlash.

It should remain an intentional choice by each user whether they want to split their configuration, state, and temporary files across different directory trees.

@bam80
Copy link
Contributor Author

bam80 commented Feb 17, 2026

As I said, the condition we have in the script would already mean we don't enable it by default.
And even then, the user would have to additionally create $XDG_DATA_HOME/vim manually (after $XDG_CONFIG_HOME/vim) for the separation. No need to require even more steps from him.
So the only thing that changes (after passing the condition) is possibly creating $XDG_STATE_HOME/vim dir and make use .viminfo file in it, which shouldn't cause any problems, as the user certainly wants it if he already switched to (semi)-XDG scheme.
No files should be left and used in $HOME.

But, if you insist - better have something than nothing.

Copy link
Member

@chrisbra chrisbra left a comment

Choose a reason for hiding this comment

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

There should be at least a few comments, why some of those settings are commented out.

Also to be robust, I think we should make sure that the other XDG directories exist, so there should probably be a few mkdir() calls, if those do not exist. And then I think to always call mkdir() when setting those options does not make sense. It should only be done if the directory does not yet exist.

endif

" XDG Base Directory support
source $VIMRUNTIME/xdg.vim
Copy link
Member

Choose a reason for hiding this comment

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

This can simply be :ru xdg.vim, but I don't want this to be part of defaults.vim

Copy link
Contributor Author

Choose a reason for hiding this comment

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

$VIMRUNTIME is more precise, as we know where the file is.

runtime/xdg.vim Outdated

if isdirectory(expand($XDG_CONFIG_HOME."/vim"))
set viminfofile=$XDG_STATE_HOME/vim/viminfo | call mkdir($XDG_STATE_HOME."/vim", 'p', 0700)
" set backupdir=$XDG_STATE_HOME/vim/backup | call mkdir(&backupdir, 'p', 0700)
Copy link
Member

Choose a reason for hiding this comment

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

Are backups really state? I would think they are data. Besides, it should be:
set backupdir=$XDG_<whatever>_HOME/vim/backup//

Copy link
Contributor Author

@bam80 bam80 Feb 17, 2026

Choose a reason for hiding this comment

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

By default, backupdir=.,~/tmp,~/. It includes ~/tmp, and 'writebackup' option is the default (backup is written temporary), so it doesn't look like something to pretend to be DATA for me.

Anyway, I don't see a good candidate for backupdir to commonly override here:
. (directory of the file?) still makes sense to me, as it allows lightweight reflink copies of the file on filesystems supporting it (BTRFS, etc.).
Non-doubtfully, we could just override ~/ part here, but I don't know an elegant way to do it in VimL, and as it goes last - we could just don't bother and keep it commented, letting the user to set whatever he actually wants.

If someone has strong opinion it should be set here - well, we could reconsider then.
Just my 2 cents.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it should be: set backupdir=$XDG__HOME/vim/backup//

done

" set backupdir=$XDG_STATE_HOME/vim/backup | call mkdir(&backupdir, 'p', 0700)
" set directory=$XDG_STATE_HOME/vim/swap | call mkdir(&directory, 'p', 0700)
" set viewdir=$XDG_STATE_HOME/vim/view | call mkdir(&viewdir, 'p', 0700)
" set undodir=$XDG_STATE_HOME/vim/undo | call mkdir(&undodir, 'p', 0700)
Copy link
Member

Choose a reason for hiding this comment

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

viewdir and undo files I would also consider DATA files

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • By default, directory=.,~/tmp,/var/tmp,/tmp - seems purely temporary. No need to override.
  • For XDG, viewdir is set by Vim already: viewdir=~/.config/vim/view, which suggests it goes to backup anyway. So I don't see the necessity to override it here (even if I would consider it STATE personally).
  • undodir=. is the default, and 'undofile' option is off. That doesn't contradicts with XDG scheme. At least - these files never stayed on my way. No reason to override IMO.

So among all of these write-sensitive options, only viminfofile is clearly out of place for me. That is why I changed it only.
Considering amount of uncertainty, I would prefer progress in small steps, and this is the first step. Will see how it goes.

@diegoviola
Copy link
Contributor

@bam80 do you mind mentioning $XDG_CONFIG_HOME/vim/vimrc here as well:

https://github.com/vim/vim/blob/master/src/main.c#L3386

@benknoble
Copy link
Contributor

I am not sure. defaults.vim is only sourced when the user does not have a vimrc file, so setting those paths in this case is a bit senseless I think. Also we have been trying to get away from defaults.vim, so adding stuff there should be avoided.

I actually targeted system vimrc file. In Fedora, it's /etc/vimrc (there is no $VIM/vimrc), and I don't know where they get this file from for sure. I decided it's most probably slightly modified copy (or different version) of defaults.vim or vimrc_example.vim, that is why I modified one of these files.

Those are typically distro-specific files that packagers control. Gentoo and other distros ship their own, IME.

IIRC Vim itself does not ship a system vimrc, and modifying defaults.vim is not the right way to tweak such a file.

How about we either:

  • document how to configure using the full XDG spec or
  • drop a file like this into $VIMRUNTIME, so users can simply :ru xdg.vim

Either of these ought be simple and easy to maintain. The latter should come with a short help tag explaining how to use Vim with the XDG setup.

@bam80
Copy link
Contributor Author

bam80 commented Feb 17, 2026

@bam80 do you mind mentioning $XDG_CONFIG_HOME/vim/vimrc here as well:

https://github.com/vim/vim/blob/master/src/main.c#L3386

@diegoviola this seems out of scope here, please do yourself if you wish. Thanks.

@bam80
Copy link
Contributor Author

bam80 commented Feb 17, 2026

And then I think to always call mkdir() when setting those options does not make sense. It should only be done if the directory does not yet exist.

I don't know the internals, but on the first glance, if the directory exists already, mkdir() just does nothing. At least I didn't notice even timestamp change.
So hopefully there is zero overhead here, and considering simplicity, I preferred non-conditional approach to call mkdir().

@bam80
Copy link
Contributor Author

bam80 commented Feb 17, 2026

There should be at least a few comments, why some of those settings are commented out.

Done


" These options are not essential for XDG, but you might want to set them:
" set backupdir=$XDG_STATE_HOME/vim/backup// | call mkdir(&backupdir, 'p', 0700)
" set directory=$XDG_STATE_HOME/vim/swap | call mkdir(&directory, 'p', 0700)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could someone outline format of the swap file? Does it always contain a full copy of the original?

@bam80
Copy link
Contributor Author

bam80 commented Feb 18, 2026

@chrisbra I deem this PR ready. If something else needs to be adjusted, it seems can be done later.
Let's start with this minimal step first.

PS:
(if I missed something, please let me know, of course)

@@ -0,0 +1,21 @@
" XDG Base Directory support

if empty($XDG_CONFIG_HOME) | let $XDG_CONFIG_HOME = $HOME."/.config" | endif
Copy link

Choose a reason for hiding this comment

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

Sorry for just chiming in, but I don't think Vim should define these variables as environment variables, as they bleed into processes Vim spawns. Other programs Vim might spawn are expected handle the absence of these environment variables themselves and set their configuration accordingly.

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 also noticed this. That's one of the reasons I completely re-wrote the script.

Copy link
Contributor Author

@bam80 bam80 Feb 18, 2026

Choose a reason for hiding this comment

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

Defining these standard $XDG_ variables here this way should be safe, as if they are not set, XDG mandates default values for them that any other program spawned from Vim should not change. Setting them to the default values is perfectly OK, though.

So defining them here also gives additional convenience for any other vim scripts that goes after.
Thus, I can just rely on $XDG_DATA_HOME in my minpac setup and do not bother to handle the fallback there (as we can handle it once and for all here).

Copy link
Contributor

Choose a reason for hiding this comment

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

I think @janvhs 's point is that some programs behave differently if the environment variables are set at all (for example, a program that supports XDG but has it's own defaults that are not XDG might honor the environment but otherwise default to ~/.myprog or something). That makes it not-so-safe.

@chrisbra
Copy link
Member

chrisbra commented Feb 18, 2026

I have made quite a few more changes. The script now looks completely different, but I want to make sure:

  • $XDG variables don't leak into the environment (:shell, :term, any other external scripts called)
  • I don't want to run mkdir() each and every time
  • I moved viewdir and undodir and viminfo file to $DATA
  • I wanted the script to be safe to be re-sourced several times
  • We need to ensure the script is actually installed
  • I don't want this in defaults.vim

Please check if this all works fine. Thanks

@chrisbra chrisbra closed this in 4f04efb Feb 18, 2026
@benknoble
Copy link
Contributor

  func s:mkvimdir(dir)
    if !isdirectory(a:dir)
      call mkdir(a:dir, 'p', 0700)
    endif
    return a:dir
  endfunc

In shell (ignoring error handling and proper quoting, etc.) test -d $x || mkdir -p $x would be inefficient, since -p does the right thing.

I think the same is true for Vim:

		There is no error if the directory already exists and the "p"
		flag is passed (since patch 8.0.1708).  However, without the
		"p" option the call will fail.

I found some time ago that checks like isdirectory(), executable(), etc. are a bit slow for the purposes of a vimrc startup script, so I try to avoid them now. Making this unconditional is simpler and likely faster.

@bam80
Copy link
Contributor Author

bam80 commented Feb 19, 2026

I have made quite a few more changes. The script now looks completely different,

@chrisbra
Thanks, but I expected this would undergo some review cycles first, as I have some objections:
#19454
#19456
#19457

@benknoble
Copy link
Contributor

FWIW, splitting this to 3 separate issues seems likely to fragment the conversation and make more work for the community 😅 OTOH, they are better scoped. Hope you all can work out a reasonable path forward (but at least Vim is so configurable that you can have your wishes even if upstream does something different).

@chrisbra
Copy link
Member

  func s:mkvimdir(dir)
    if !isdirectory(a:dir)
      call mkdir(a:dir, 'p', 0700)
    endif
    return a:dir
  endfunc

In shell (ignoring error handling and proper quoting, etc.) test -d $x || mkdir -p $x would be inefficient, since -p does the right thing.

I think the same is true for Vim:

		There is no error if the directory already exists and the "p"
		flag is passed (since patch 8.0.1708).  However, without the
		"p" option the call will fail.

I found some time ago that checks like isdirectory(), executable(), etc. are a bit slow for the purposes of a vimrc startup script, so I try to avoid them now. Making this unconditional is simpler and likely faster.

This might be true but I consider this to be bad style. For your personal vimrc such hacks are fine, but I want to be explicit about it when we ship this with Vim.

@bam80
Copy link
Contributor Author

bam80 commented Feb 19, 2026

I found some time ago that checks like isdirectory(), executable(), etc. are a bit slow for the purposes of a vimrc startup script, so I try to avoid them now.

@benknoble How did you find that? Is it something noticeable enough to worry about?

@bam80 bam80 deleted the patch-1 branch February 19, 2026 12:10
@benknoble
Copy link
Contributor

I found some time ago that checks like isdirectory(), executable(), etc. are a bit slow for the purposes of a vimrc startup script, so I try to avoid them now.

@benknoble How did you find that? Is it something noticeable enough to worry about?

For example, benknoble/Dotfiles@5068531. You can measure startup times with :help slow-start, and I also have this command for helping analyze those logs.

I think if you're doing lots of conditional things that also reach out to the underlying system it has the potential to be slow, that's all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[RFC] Support all XDG Basedirs

6 participants