feat(defaults): session data in $XDG_STATE_HOME #15583

See: 4f2884e16d

- Move session persistent data to $XDG_STATE_HOME Change 'directory',
  'backupdir', 'undodir', 'viewdir' and 'shadafile' default location to
  $XDG_STATE_HOME/nvim.
- Move logs to $XDG_STATE_HOME, too.
- Add stdpath('log') support.

Fixes: #14805
This commit is contained in:
Ivan 2021-09-06 20:35:34 +03:00 committed by Justin M. Keyes
parent a1b663cce8
commit 78a1e6bc00
15 changed files with 303 additions and 224 deletions

View File

@ -188,7 +188,7 @@ loading plugins is also skipped.
Use
.Ar shada
instead of the default
.Pa ~/.local/share/nvim/shada/main.shada .
.Pa ~/.local/state/nvim/shada/main.shada .
If
.Ar shada
is
@ -326,7 +326,7 @@ Print version information and exit.
.Sh ENVIRONMENT
.Bl -tag -width Fl
.It Ev NVIM_LOG_FILE
Low-level log file, usually found at ~/.cache/nvim/log.
Low-level log file, usually found at ~/.local/state/nvim/log.
:help $NVIM_LOG_FILE
.It Ev VIM
Used to locate user files, such as init.vim.
@ -340,12 +340,20 @@ Path to the user-local configuration directory, see
Defaults to
.Pa ~/.config .
:help xdg
.It Ev XDG_DATA_HOME
.It Ev XDG_STATE_HOME
Like
.Ev XDG_CONFIG_HOME ,
but used to store data not generally edited by the user,
namely swap, backup, and ShaDa files.
Defaults to
.Pa ~/.local/state .
:help xdg
.It Ev XDG_DATA_HOME
Like
.Ev XDG_CONFIG_HOME ,
but used to store data not generally edited by the user,
things like runtime files.
Defaults to
.Pa ~/.local/share .
:help xdg
.It Ev VIMINIT

View File

@ -7465,14 +7465,17 @@ stdpath({what}) *stdpath()* *E6100*
directories.
{what} Type Description ~
cache String Cache directory. Arbitrary temporary
cache String Cache directory: arbitrary temporary
storage for plugins, etc.
config String User configuration directory. The
|init.vim| is stored here.
config_dirs List Additional configuration directories.
config String User configuration directory. |init.vim|
is stored here.
config_dirs List Other configuration directories.
data String User data directory. The |shada-file|
is stored here.
data_dirs List Additional data directories.
data_dirs List Other data directories.
log String Logs directory (for use by plugins too).
state String Session state directory: storage for file
drafts, undo history, shada, etc.
Example: >
:echo stdpath("config")

View File

@ -841,7 +841,7 @@ A jump table for the options with a short description can be found at |Q_op|.
again not rename the file.
*'backupdir'* *'bdir'*
'backupdir' 'bdir' string (default ".,$XDG_DATA_HOME/nvim/backup//")
'backupdir' 'bdir' string (default ".,$XDG_STATE_HOME/nvim/backup//")
global
List of directories for the backup file, separated with commas.
- The backup file will be created in the first directory in the list
@ -2063,7 +2063,7 @@ A jump table for the options with a short description can be found at |Q_op|.
{char2}. See |digraphs|.
*'directory'* *'dir'*
'directory' 'dir' string (default "$XDG_DATA_HOME/nvim/swap//")
'directory' 'dir' string (default "$XDG_STATE_HOME/nvim/swap//")
global
List of directory names for the swap file, separated with commas.
@ -3502,7 +3502,7 @@ A jump table for the options with a short description can be found at |Q_op|.
option. For '@' only characters up to 255 are used.
Careful: If you change this option, it might break expanding
environment variables. E.g., when '/' is included and Vim tries to
expand "$HOME/.local/share/nvim/shada/main.shada". Maybe you should
expand "$HOME/.local/state/nvim/shada/main.shada". Maybe you should
change 'iskeyword' instead.
*'iskeyword'* *'isk'*
@ -4942,9 +4942,12 @@ A jump table for the options with a short description can be found at |Q_op|.
but are not part of the Nvim distribution. XDG_DATA_DIRS defaults
to /usr/local/share/:/usr/share/, so system administrators are
expected to install site plugins to /usr/share/nvim/site.
5. $VIMRUNTIME, for files distributed with Neovim.
5. Applications state home directory, for files that contain your
session state (eg. backupdir, viewdir, undodir, etc).
Given by `stdpath("state")`. |$XDG_STATE_HOME|
6. $VIMRUNTIME, for files distributed with Neovim.
*after-directory*
6, 7, 8, 9. In after/ subdirectories of 1, 2, 3 and 4, with reverse
7, 8, 9, 10. In after/ subdirectories of 1, 2, 3 and 4, with reverse
ordering. This is for preferences to overrule or add to the
distributed defaults or system-wide settings (rarely needed).
@ -6623,7 +6626,7 @@ A jump table for the options with a short description can be found at |Q_op|.
'ttyfast' 'tf' Removed. |vim-differences|
*'undodir'* *'udir'* *E5003*
'undodir' 'udir' string (default "$XDG_DATA_HOME/nvim/undo//")
'undodir' 'udir' string (default "$XDG_STATE_HOME/nvim/undo//")
global
List of directory names for undo files, separated with commas.
See 'backupdir' for details of the format.
@ -6786,7 +6789,7 @@ A jump table for the options with a short description can be found at |Q_op|.
displayed when 'verbosefile' is set.
*'viewdir'* *'vdir'*
'viewdir' 'vdir' string (default: "$XDG_DATA_HOME/nvim/view//")
'viewdir' 'vdir' string (default: "$XDG_STATE_HOME/nvim/view//")
global
Name of the directory where to store files for |:mkview|.
This option cannot be set from a |modeline| or in the |sandbox|, for

View File

@ -367,7 +367,7 @@ argument.
*--headless*
--headless Start without UI, and do not wait for `nvim_ui_attach`. The
builtin TUI is not used, so stdio works as an arbitrary
communication channel. |channel-stdio|
communication channel. |channel-stdio|
Also useful for scripting (tests) to see messages that would
not be printed by |-es|.
@ -584,7 +584,7 @@ setting can affect the entire editor in ways that are not initially obvious.
To find the cause of a problem in your config, you must "bisect" it:
1. Remove or disable half of your |config|.
2. Restart Nvim.
3. If the problem still occurs, goto 1.
3. If the problem still occurs, goto 1.
4. If the problem is gone, restore half of the removed lines.
5. Continue narrowing your config in this way, until you find the setting or
plugin causing the issue.
@ -701,7 +701,7 @@ vimrc file.
These commands will write ":map" and ":set" commands to a file, in such a way
that when these commands are executed, the current key mappings and options
will be set to the same values. The options 'columns', 'endofline',
'fileformat', 'lines', 'modified', and 'scroll' are not included, because
'fileformat', 'lines', 'modified', and 'scroll' are not included, because
these are terminal or file dependent.
Note that the options 'binary', 'paste' and 'readonly' are included, this
might not always be what you want.
@ -718,7 +718,7 @@ with ":map" and ":set" commands and write the modified file. First read the
default vimrc in with a command like ":source ~piet/.vimrc.Cprogs", change
the settings and then save them in the current directory with ":mkvimrc!". If
you want to make this file your default |config|, move it to
$XDG_CONFIG_HOME/nvim. You could also use autocommands |autocommand| and/or
$XDG_CONFIG_HOME/nvim. You could also use autocommands |autocommand| and/or
modelines |modeline|.
*vimrc-option-example*
@ -886,7 +886,7 @@ Shada ("shared data") file *shada* *shada-file*
If you exit Vim and later start it again, you would normally lose a lot of
information. The ShaDa file can be used to remember that information, which
enables you to continue where you left off. Its name is the abbreviation of
enables you to continue where you left off. Its name is the abbreviation of
SHAred DAta because it is used for sharing data between Neovim sessions.
This is introduced in section |21.3| of the user manual.
@ -917,9 +917,9 @@ The |v:oldfiles| variable is filled. The marks are not read in at startup
option upon startup.
*shada-write*
When Vim exits and 'shada' is non-empty, the info is stored in the ShaDa file
(it's actually merged with the existing one, if one exists |shada-merging|).
The 'shada' option is a string containing information about what info should
When Vim exits and 'shada' is non-empty, the info is stored in the ShaDa file
(it's actually merged with the existing one, if one exists |shada-merging|).
The 'shada' option is a string containing information about what info should
be stored, and contains limits on how much should be stored (see 'shada').
Notes for Unix:
@ -977,75 +977,75 @@ remembered.
MERGING *shada-merging*
When writing ShaDa files with |:wshada| without bang or at regular exit
information in the existing ShaDa file is merged with information from current
Neovim instance. For this purpose ShaDa files store timestamps associated
When writing ShaDa files with |:wshada| without bang or at regular exit
information in the existing ShaDa file is merged with information from current
Neovim instance. For this purpose ShaDa files store timestamps associated
with ShaDa entries. Specifically the following is being done:
1. History lines are merged, ordered by timestamp. Maximum amount of items in
ShaDa file is defined by 'shada' option (|shada-/|, |shada-:|, |shada-@|,
etc: one suboption for each character that represents history name
1. History lines are merged, ordered by timestamp. Maximum amount of items in
ShaDa file is defined by 'shada' option (|shada-/|, |shada-:|, |shada-@|,
etc: one suboption for each character that represents history name
(|:history|)).
2. Local marks and changes for files that were not opened by Neovim are copied
to new ShaDa file. Marks for files that were opened by Neovim are merged,
2. Local marks and changes for files that were not opened by Neovim are copied
to new ShaDa file. Marks for files that were opened by Neovim are merged,
changes to files opened by Neovim are ignored. |shada-'|
3. Jump list is merged: jumps are ordered by timestamp, identical jumps
3. Jump list is merged: jumps are ordered by timestamp, identical jumps
(identical position AND timestamp) are squashed.
4. Search patterns and substitute strings are not merged: search pattern or
substitute string which has greatest timestamp will be the only one copied
4. Search patterns and substitute strings are not merged: search pattern or
substitute string which has greatest timestamp will be the only one copied
to ShaDa file.
5. For each register entity with greatest timestamp is the only saved.
5. For each register entity with greatest timestamp is the only saved.
|shada-<|
6. All saved variables are saved from current Neovim instance. Additionally
existing variable values are copied, meaning that the only way to remove
variable from a ShaDa file is either removing it by hand or disabling
6. All saved variables are saved from current Neovim instance. Additionally
existing variable values are copied, meaning that the only way to remove
variable from a ShaDa file is either removing it by hand or disabling
writing variables completely. |shada-!|
7. For each global mark entity with greatest timestamp is the only saved.
8. Buffer list and header are the only entries which are not merged in any
fashion: the only header and buffer list present are the ones from the
8. Buffer list and header are the only entries which are not merged in any
fashion: the only header and buffer list present are the ones from the
Neovim instance which was last writing the file. |shada-%|
COMPATIBILITY *shada-compatibility*
ShaDa files are forward and backward compatible. This means that
1. Entries which have unknown type (i.e. that hold unidentified data) are
1. Entries which have unknown type (i.e. that hold unidentified data) are
ignored when reading and blindly copied when writing.
2. Register entries with unknown register name are ignored when reading and
blindly copied when writing. Limitation: only registers that use name with
2. Register entries with unknown register name are ignored when reading and
blindly copied when writing. Limitation: only registers that use name with
code in interval [1, 255] are supported. |registers|
3. Register entries with unknown register type are ignored when reading and
3. Register entries with unknown register type are ignored when reading and
merged as usual when writing. |getregtype()|
4. Local and global mark entries with unknown mark names are ignored when
reading. When writing global mark entries are blindly copied and local mark
entries are also blindly copied, but only if file they are attached to fits
in the |shada-'| limit. Unknown local mark entry's timestamp is also taken
into account when calculating which files exactly should fit into this
limit. Limitation: only marks that use name with code in interval [1, 255]
4. Local and global mark entries with unknown mark names are ignored when
reading. When writing global mark entries are blindly copied and local mark
entries are also blindly copied, but only if file they are attached to fits
in the |shada-'| limit. Unknown local mark entry's timestamp is also taken
into account when calculating which files exactly should fit into this
limit. Limitation: only marks that use name with code in interval [1, 255]
are supported. |mark-motions|
5. History entries with unknown history type are ignored when reading and
blindly copied when writing. Limitation: there can be only up to 256
5. History entries with unknown history type are ignored when reading and
blindly copied when writing. Limitation: there can be only up to 256
history types. |history|
6. Unknown keys found in register, local mark, global mark, change, jump and
search pattern entries are saved internally and dumped when writing.
6. Unknown keys found in register, local mark, global mark, change, jump and
search pattern entries are saved internally and dumped when writing.
Entries created during Neovim session never have such additions.
7. Additional elements found in replacement string and history entries are
saved internally and dumped. Entries created during Neovim session never
7. Additional elements found in replacement string and history entries are
saved internally and dumped. Entries created during Neovim session never
have such additions.
8. Additional elements found in variable entries are simply ignored when
reading. When writing new variables they will be preserved during merging,
but that's all. Variable values dumped from current Neovim session never
have additional elements, even if variables themselves were obtained by
8. Additional elements found in variable entries are simply ignored when
reading. When writing new variables they will be preserved during merging,
but that's all. Variable values dumped from current Neovim session never
have additional elements, even if variables themselves were obtained by
reading ShaDa files.
"Blindly" here means that there will be no attempts to somehow merge them,
"Blindly" here means that there will be no attempts to somehow merge them,
even if other entries (with known name/type/etc) are merged. |shada-merging|
SHADA FILE NAME *shada-file-name*
- Default name of the |shada| file is:
Unix: "$XDG_DATA_HOME/nvim/shada/main.shada"
Windows: "$XDG_DATA_HOME/nvim-data/shada/main.shada"
Unix: "$XDG_STATE_HOME/nvim/shada/main.shada"
Windows: "$XDG_STATE_HOME/nvim-data/shada/main.shada"
See also |base-directories|.
- To choose a different file name you can use:
- The "n" flag in the 'shada' option.
@ -1067,55 +1067,55 @@ however that this means everything will be overwritten with information from
the first Vim, including the command line history, etc.
The ShaDa file itself can be edited by hand too, although we suggest you
start with an existing one to get the format right. You need to understand
MessagePack (or, more likely, find software that is able to use it) format to
do this. This can be useful in order to create a second file, say
"~/.my.shada" which could contain certain settings that you always want when
you first start Neovim. For example, you can preload registers with
particular data, or put certain commands in the command line history. A line
start with an existing one to get the format right. You need to understand
MessagePack (or, more likely, find software that is able to use it) format to
do this. This can be useful in order to create a second file, say
"~/.my.shada" which could contain certain settings that you always want when
you first start Neovim. For example, you can preload registers with
particular data, or put certain commands in the command line history. A line
in your |config| file like >
:rshada! ~/.my.shada
can be used to load this information. You could even have different ShaDa
files for different types of files (e.g., C code) and load them based on the
file name, using the ":autocmd" command (see |:autocmd|). More information on
can be used to load this information. You could even have different ShaDa
files for different types of files (e.g., C code) and load them based on the
file name, using the ":autocmd" command (see |:autocmd|). More information on
ShaDa file format is contained in |shada-format| section.
*E136* *E929* *shada-error-handling*
Some errors make Neovim leave temporary file named `{basename}.tmp.X` (X is
any free letter from `a` to `z`) while normally it will create this file,
write to it and then rename `{basename}.tmp.X` to `{basename}`. Such errors
Some errors make Neovim leave temporary file named `{basename}.tmp.X` (X is
any free letter from `a` to `z`) while normally it will create this file,
write to it and then rename `{basename}.tmp.X` to `{basename}`. Such errors
include:
- Errors which make Neovim think that read file is not a ShaDa file at all:
non-ShaDa files are not overwritten for safety reasons to avoid accidentally
destroying an unrelated file. This could happen e.g. when typing "nvim -i
file" in place of "nvim -R file" (yes, somebody did that at least with Vim).
- Errors which make Neovim think that read file is not a ShaDa file at all:
non-ShaDa files are not overwritten for safety reasons to avoid accidentally
destroying an unrelated file. This could happen e.g. when typing "nvim -i
file" in place of "nvim -R file" (yes, somebody did that at least with Vim).
Such errors are listed at |shada-critical-contents-errors|.
- If writing to the temporary file failed: e.g. because of the insufficient
- If writing to the temporary file failed: e.g. because of the insufficient
space left.
- If renaming file failed: e.g. because of insufficient permissions.
- If target ShaDa file has different from the Neovim instance's owners (user
and group) and changing them failed. Unix-specific, applies only when
- If target ShaDa file has different from the Neovim instance's owners (user
and group) and changing them failed. Unix-specific, applies only when
Neovim was launched from root.
Do not forget to remove the temporary file or replace the target file with
temporary one after getting one of the above errors or all attempts to create
a ShaDa file may fail with |E929|. If you got one of them when using
|:wshada| (and not when exiting Neovim: i.e. when you have Neovim session
Do not forget to remove the temporary file or replace the target file with
temporary one after getting one of the above errors or all attempts to create
a ShaDa file may fail with |E929|. If you got one of them when using
|:wshada| (and not when exiting Neovim: i.e. when you have Neovim session
running) you have additional options:
- First thing which you should consider if you got any error, except failure
to write to the temporary file: remove existing file and replace it with the
- First thing which you should consider if you got any error, except failure
to write to the temporary file: remove existing file and replace it with the
temporary file. Do it even if you have running Neovim instance.
- Fix the permissions and/or file ownership, free some space and attempt to
- Fix the permissions and/or file ownership, free some space and attempt to
write again. Do not remove the existing file.
- Use |:wshada| with bang. Does not help in case of permission error. If
target file was actually the ShaDa file some information may be lost in this
case. To make the matters slightly better use |:rshada| prior to writing,
but this still will loose buffer-local marks and change list entries for any
- Use |:wshada| with bang. Does not help in case of permission error. If
target file was actually the ShaDa file some information may be lost in this
case. To make the matters slightly better use |:rshada| prior to writing,
but this still will loose buffer-local marks and change list entries for any
file which is not opened in the current Neovim instance.
- Remove the target file from shell and use |:wshada|. Consequences are not
different from using |:wshada| with bang, but "rm -f" works in some cases
- Remove the target file from shell and use |:wshada|. Consequences are not
different from using |:wshada| with bang, but "rm -f" works in some cases
when you don't have write permissions.
*:rsh* *:rshada* *E886*
@ -1129,13 +1129,13 @@ running) you have additional options:
The information in the file is first read in to make
a merge between old and new info. When [!] is used,
the old information is not read first, only the
internal info is written (also disables safety checks
described in |shada-error-handling|). If 'shada' is
internal info is written (also disables safety checks
described in |shada-error-handling|). If 'shada' is
empty, marks for up to 100 files will be written.
When you get error "E929: All .tmp.X files exist,
cannot write ShaDa file!" check that no old temp files
were left behind (e.g.
~/.local/share/nvim/shada/main.shada.tmp*).
When you get error "E929: All .tmp.X files exist,
cannot write ShaDa file!" check that no old temp files
were left behind (e.g.
~/.local/state/nvim/shada/main.shada.tmp*).
Note: Executing :wshada will reset all |'quote| marks.
@ -1158,82 +1158,82 @@ running) you have additional options:
SHADA FILE FORMAT *shada-format*
ShaDa files are concats of MessagePack entries. Each entry is a concat of
ShaDa files are concats of MessagePack entries. Each entry is a concat of
exactly four MessagePack objects:
1. First goes type of the entry. Object type must be an unsigned integer.
1. First goes type of the entry. Object type must be an unsigned integer.
Object type must not be equal to zero.
2. Second goes entry timestamp. It must also be an unsigned integer.
3. Third goes the length of the fourth entry. Unsigned integer as well, used
3. Third goes the length of the fourth entry. Unsigned integer as well, used
for fast skipping without parsing.
4. Fourth is actual entry data. All currently used ShaDa entries use
containers to hold data: either map or array. All string values in those
containers are either binary (applies to filenames) or UTF-8, yet parser
4. Fourth is actual entry data. All currently used ShaDa entries use
containers to hold data: either map or array. All string values in those
containers are either binary (applies to filenames) or UTF-8, yet parser
needs to expect that invalid bytes may be present in a UTF-8 string.
Exact format depends on the entry type:
Entry type (name) Entry data ~
1 (Header) Map containing data that describes the generator
instance that wrote this ShaDa file. It is ignored
1 (Header) Map containing data that describes the generator
instance that wrote this ShaDa file. It is ignored
when reading ShaDa files. Contains the following data:
Key Data ~
generator Binary, software used to generate ShaDa
file. Is equal to "nvim" when ShaDa file was
generator Binary, software used to generate ShaDa
file. Is equal to "nvim" when ShaDa file was
written by Neovim.
version Binary, generator version.
encoding Binary, effective 'encoding' value.
max_kbyte Integer, effective |shada-s| limit value.
pid Integer, instance process ID.
* It is allowed to have any number of
* It is allowed to have any number of
additional keys with any data.
2 (SearchPattern) Map containing data describing last used search or
substitute pattern. Normally ShaDa file contains two
such entries: one with "ss" key set to true (describes
substitute pattern, see |:substitute|), and one set to
false (describes search pattern, see
|search-commands|). "su" key should be true on one of
the entries. If key value is equal to default then it
2 (SearchPattern) Map containing data describing last used search or
substitute pattern. Normally ShaDa file contains two
such entries: one with "ss" key set to true (describes
substitute pattern, see |:substitute|), and one set to
false (describes search pattern, see
|search-commands|). "su" key should be true on one of
the entries. If key value is equal to default then it
is normally not present. Keys:
Key Type Default Description ~
sm Boolean true Effective 'magic' value.
sc Boolean false Effective 'smartcase' value.
sl Boolean true True if search pattern comes
with a line offset. See
sl Boolean true True if search pattern comes
with a line offset. See
|search-offset|.
se Boolean false True if |search-offset|
requested to place cursor at
(relative to) the end of the
se Boolean false True if |search-offset|
requested to place cursor at
(relative to) the end of the
pattern.
so Integer 0 Offset value. |search-offset|
su Boolean false True if current entry was the
su Boolean false True if current entry was the
last used search pattern.
ss Boolean false True if current entry describes
ss Boolean false True if current entry describes
|:substitute| pattern.
sh Boolean false True if |v:hlsearch| is on.
With |shada-h| or 'nohlsearch'
With |shada-h| or 'nohlsearch'
this key is always false.
sp Binary N/A Actual pattern. Required.
sb Boolean false True if search direction is
sb Boolean false True if search direction is
backward.
* any none Other keys are allowed for
compatibility reasons, see
* any none Other keys are allowed for
compatibility reasons, see
|shada-compatibility|.
3 (SubString) Array containing last |:substitute| replacement string.
Contains single entry: binary, replacement string used.
More entries are allowed for compatibility reasons, see
3 (SubString) Array containing last |:substitute| replacement string.
Contains single entry: binary, replacement string used.
More entries are allowed for compatibility reasons, see
|shada-compatibility|.
4 (HistoryEntry) Array containing one entry from history. Should have
two or three entries. First one is history type
(unsigned integer), second is history line (binary),
third is the separator character (unsigned integer,
must be in interval [0, 255]). Third item is only
valid for search history. Possible history types are
listed in |hist-names|, here are the corresponding
numbers: 0 - cmd, 1 - search, 2 - expr, 3 - input,
4 (HistoryEntry) Array containing one entry from history. Should have
two or three entries. First one is history type
(unsigned integer), second is history line (binary),
third is the separator character (unsigned integer,
must be in interval [0, 255]). Third item is only
valid for search history. Possible history types are
listed in |hist-names|, here are the corresponding
numbers: 0 - cmd, 1 - search, 2 - expr, 3 - input,
4 - debug.
5 (Register) Map describing one register (|registers|). If key
value is equal to default then it is normally not
5 (Register) Map describing one register (|registers|). If key
value is equal to default then it is normally not
present. Keys:
Key Type Def Description ~
rt UInteger 0 Register type:
@ -1261,12 +1261,12 @@ exactly four MessagePack objects:
* any none Other keys are allowed
for compatibility reasons,
see |shada-compatibility|.
6 (Variable) Array containing two items: variable name (binary) and
variable value (any object). Values are converted
using the same code |msgpackparse()| uses when reading,
|msgpackdump()| when writing, so there may appear
|msgpack-special-dict|s. If there are more then two
entries then the rest are ignored
6 (Variable) Array containing two items: variable name (binary) and
variable value (any object). Values are converted
using the same code |msgpackparse()| uses when reading,
|msgpackdump()| when writing, so there may appear
|msgpack-special-dict|s. If there are more then two
entries then the rest are ignored
(|shada-compatibility|).
7 (GlobalMark)
8 (Jump)
@ -1280,57 +1280,57 @@ exactly four MessagePack objects:
Data contained in the map:
Key Type Default Description ~
l UInteger 1 Position line number. Must be
l UInteger 1 Position line number. Must be
greater then zero.
c UInteger 0 Position column number.
n UInteger 34 ('"') Mark name. Only valid for
GlobalMark and LocalMark
n UInteger 34 ('"') Mark name. Only valid for
GlobalMark and LocalMark
entries.
f Binary N/A File name. Required.
* any none Other keys are allowed for
compatibility reasons, see
* any none Other keys are allowed for
compatibility reasons, see
|shada-compatibility|.
9 (BufferList) Array containing maps. Each map in the array
9 (BufferList) Array containing maps. Each map in the array
represents one buffer. Possible keys:
Key Type Default Description ~
l UInteger 1 Position line number. Must be
l UInteger 1 Position line number. Must be
greater then zero.
c UInteger 0 Position column number.
f Binary N/A File name. Required.
* any none Other keys are allowed for
compatibility reasons, see
* any none Other keys are allowed for
compatibility reasons, see
|shada-compatibility|.
* (Unknown) Any other entry type is allowed for compatibility
* (Unknown) Any other entry type is allowed for compatibility
reasons, see |shada-compatibility|.
*E575* *E576*
Errors in ShaDa file may have two types: E575 used for all “logical” errors
and E576 used for all “critical” errors. Critical errors trigger behaviour
described in |shada-error-handling| when writing and skipping the rest of the
Errors in ShaDa file may have two types: E575 used for all “logical” errors
and E576 used for all “critical” errors. Critical errors trigger behaviour
described in |shada-error-handling| when writing and skipping the rest of the
file when reading and include:
*shada-critical-contents-errors*
- Any of first three MessagePack objects being not an unsigned integer.
- Third object requesting amount of bytes greater then bytes left in the ShaDa
- Third object requesting amount of bytes greater then bytes left in the ShaDa
file.
- Entry with zero type. I.e. first object being equal to zero.
- MessagePack parser failing to parse the entry data.
- MessagePack parser consuming less or requesting greater bytes then described
in the third object for parsing fourth object. I.e. when fourth object
either contains more then one MessagePack object or it does not contain
- MessagePack parser consuming less or requesting greater bytes then described
in the third object for parsing fourth object. I.e. when fourth object
either contains more then one MessagePack object or it does not contain
complete MessagePack object.
==============================================================================
Standard Paths *standard-path*
Nvim stores configuration, data, and logs in standard locations. Plugins are
strongly encouraged to follow this pattern also. Use |stdpath()| to get the
Nvim stores configuration, data, and logs in standard locations. Plugins are
strongly encouraged to follow this pattern also. Use |stdpath()| to get the
paths.
*base-directories* *xdg*
The "base" (root) directories conform to the XDG Base Directory Specification.
https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
The $XDG_CONFIG_HOME and $XDG_DATA_HOME environment variables are used if they
exist, otherwise default values (listed below) are used.
The $XDG_CONFIG_HOME, $XDG_DATA_HOME and $XDG_STATE_HOME environment variables
are used if they exist, otherwise default values (listed below) are used.
CONFIG DIRECTORY (DEFAULT) ~
*$XDG_CONFIG_HOME* Nvim: stdpath("config")
@ -1342,6 +1342,11 @@ DATA DIRECTORY (DEFAULT) ~
Unix: ~/.local/share ~/.local/share/nvim
Windows: ~/AppData/Local ~/AppData/Local/nvim-data
STATE DIRECTORY (DEFAULT) ~
*$XDG_STATE_HOME* Nvim: stdpath("state")
Unix: ~/.local/state ~/.local/state/nvim
Windows: ~/AppData/Local ~/AppData/Local/nvim-data
Note: Throughout the user manual these defaults are used as placeholders, e.g.
"~/.config" is understood to mean "$XDG_CONFIG_HOME or ~/.config".
@ -1349,7 +1354,7 @@ LOG FILE *$NVIM_LOG_FILE*
Besides 'debug' and 'verbose', Nvim keeps a general log file for internal
debugging, plugins and RPC clients. >
:echo $NVIM_LOG_FILE
By default, the file is located at stdpath('cache')/log unless that path
By default, the file is located at stdpath('log')/log unless that path
is inaccessible or if $NVIM_LOG_FILE was set before |startup|.

View File

@ -352,12 +352,12 @@ another session.
this yourself then. Example: >
:mksession! ~/.config/nvim/secret.vim
:wshada! ~/.local/share/nvim/shada/secret.shada
:wshada! ~/.local/state/nvim/shada/secret.shada
And to restore this again: >
:source ~/.config/nvim/secret.vim
:rshada! ~/.local/share/nvim/shada/secret.shada
:rshada! ~/.local/state/nvim/shada/secret.shada
==============================================================================
*21.5* Views

View File

@ -17,7 +17,7 @@ centralized reference of the differences.
- Use `$XDG_CONFIG_HOME/nvim/init.vim` instead of `.vimrc` for your |config|.
- Use `$XDG_CONFIG_HOME/nvim` instead of `.vim` to store configuration files.
- Use `$XDG_DATA_HOME/nvim/shada/main.shada` instead of `.viminfo` for persistent
- Use `$XDG_STATE_HOME/nvim/shada/main.shada` instead of `.viminfo` for persistent
session information. |shada|
==============================================================================
@ -32,12 +32,12 @@ centralized reference of the differences.
- 'autoread' is enabled
- 'background' defaults to "dark" (unless set automatically by the terminal/UI)
- 'backspace' defaults to "indent,eol,start"
- 'backupdir' defaults to .,~/.local/share/nvim/backup// (|xdg|), auto-created
- 'backupdir' defaults to .,~/.local/state/nvim/backup// (|xdg|), auto-created
- 'belloff' defaults to "all"
- 'compatible' is always disabled
- 'complete' excludes "i"
- 'cscopeverbose' is enabled
- 'directory' defaults to ~/.local/share/nvim/swap// (|xdg|), auto-created
- 'directory' defaults to ~/.local/state/nvim/swap// (|xdg|), auto-created
- 'display' defaults to "lastline,msgsep"
- 'encoding' is UTF-8 (cf. 'fileencoding' for file-content encoding)
- 'fillchars' defaults (in effect) to "vert:│,fold:·,sep:│"
@ -65,7 +65,7 @@ centralized reference of the differences.
- 'tags' defaults to "./tags;,tags"
- 'ttimeoutlen' defaults to 50
- 'ttyfast' is always set
- 'undodir' defaults to ~/.local/share/nvim/undo// (|xdg|), auto-created
- 'undodir' defaults to ~/.local/state/nvim/undo// (|xdg|), auto-created
- 'viewoptions' includes "unix,slash", excludes "options"
- 'viminfo' includes "!"
- 'wildmenu' is enabled

View File

@ -25,12 +25,12 @@ do
local function path_join(...)
return table.concat(vim.tbl_flatten({ ... }), path_sep)
end
local logfilename = path_join(vim.fn.stdpath('cache'), 'lsp.log')
local logfilename = path_join(vim.fn.stdpath('log'), 'lsp.log')
-- TODO: Ideally the directory should be created in open_logfile(), right
-- before opening the log file, but open_logfile() can be called from libuv
-- callbacks, where using fn.mkdir() is not allowed.
vim.fn.mkdir(vim.fn.stdpath('cache'), 'p')
vim.fn.mkdir(vim.fn.stdpath('log'), 'p')
--- Returns the log filename.
---@returns (string) log filename

View File

@ -38,7 +38,7 @@ alternate file (e.g. stderr) use `LOG_CALLSTACK_TO_FILE(FILE*)`. Requires
Many log messages have a shared prefix, such as "UI" or "RPC". Use the shell to
filter the log, e.g. at DEBUG level you might want to exclude UI messages:
tail -F ~/.cache/nvim/log | cat -v | stdbuf -o0 grep -v UI | stdbuf -o0 tee -a log
tail -F ~/.local/state/nvim/log | cat -v | stdbuf -o0 grep -v UI | stdbuf -o0 tee -a log
Build with ASAN
---------------

View File

@ -9842,6 +9842,10 @@ static void f_stdpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = get_xdg_home(kXDGDataHome);
} else if (strequal(p, "cache")) {
rettv->vval.v_string = get_xdg_home(kXDGCacheHome);
} else if (strequal(p, "state")) {
rettv->vval.v_string = get_xdg_home(kXDGStateHome);
} else if (strequal(p, "log")) {
rettv->vval.v_string = get_xdg_home(kXDGStateHome);
} else if (strequal(p, "config_dirs")) {
get_xdg_var_list(kXDGConfigDirs, rettv);
} else if (strequal(p, "data_dirs")) {

View File

@ -51,7 +51,7 @@ static bool log_try_create(char *fname)
/// Initializes path to log file. Sets $NVIM_LOG_FILE if empty.
///
/// Tries $NVIM_LOG_FILE, or falls back to $XDG_CACHE_HOME/nvim/log. Path to log
/// Tries $NVIM_LOG_FILE, or falls back to $XDG_STATE_HOME/nvim/log. Path to log
/// file is cached, so only the first call has effect, unless first call was not
/// successful. Failed initialization indicates either a bug in expand_env()
/// or both $NVIM_LOG_FILE and $HOME environment variables are undefined.
@ -69,16 +69,16 @@ static bool log_path_init(void)
|| log_file_path[0] == '\0'
|| os_isdir((char_u *)log_file_path)
|| !log_try_create(log_file_path)) {
// Make kXDGCacheHome if it does not exist.
char *cachehome = get_xdg_home(kXDGCacheHome);
// Make kXDGStateHome if it does not exist.
char *loghome = get_xdg_home(kXDGStateHome);
char *failed_dir = NULL;
bool log_dir_failure = false;
if (!os_isdir((char_u *)cachehome)) {
log_dir_failure = (os_mkdir_recurse(cachehome, 0700, &failed_dir) != 0);
if (!os_isdir((char_u *)loghome)) {
log_dir_failure = (os_mkdir_recurse(loghome, 0700, &failed_dir) != 0);
}
XFREE_CLEAR(cachehome);
XFREE_CLEAR(loghome);
// Invalid $NVIM_LOG_FILE or failed to expand; fall back to default.
char *defaultpath = stdpaths_user_cache_subpath("log");
char *defaultpath = stdpaths_user_state_subpath("log", 0, true);
size_t len = xstrlcpy(log_file_path, defaultpath, size);
xfree(defaultpath);
// Fall back to .nvimlog

View File

@ -491,17 +491,17 @@ void set_init_1(bool clean_arg)
#endif
false);
char *backupdir = stdpaths_user_data_subpath("backup", 2, true);
char *backupdir = stdpaths_user_state_subpath("backup", 2, true);
const size_t backupdir_len = strlen(backupdir);
backupdir = xrealloc(backupdir, backupdir_len + 3);
memmove(backupdir + 2, backupdir, backupdir_len + 1);
memmove(backupdir, ".,", 2);
set_string_default("backupdir", backupdir, true);
set_string_default("viewdir", stdpaths_user_data_subpath("view", 2, true),
set_string_default("viewdir", stdpaths_user_state_subpath("view", 2, true),
true);
set_string_default("directory", stdpaths_user_data_subpath("swap", 2, true),
set_string_default("directory", stdpaths_user_state_subpath("swap", 2, true),
true);
set_string_default("undodir", stdpaths_user_data_subpath("undo", 2, true),
set_string_default("undodir", stdpaths_user_state_subpath("undo", 2, true),
true);
// Set default for &runtimepath. All necessary expansions are performed in
// this function.

View File

@ -14,6 +14,7 @@ static const char *xdg_env_vars[] = {
[kXDGConfigHome] = "XDG_CONFIG_HOME",
[kXDGDataHome] = "XDG_DATA_HOME",
[kXDGCacheHome] = "XDG_CACHE_HOME",
[kXDGStateHome] = "XDG_STATE_HOME",
[kXDGRuntimeDir] = "XDG_RUNTIME_DIR",
[kXDGConfigDirs] = "XDG_CONFIG_DIRS",
[kXDGDataDirs] = "XDG_DATA_DIRS",
@ -24,6 +25,7 @@ static const char *const xdg_defaults_env_vars[] = {
[kXDGConfigHome] = "LOCALAPPDATA",
[kXDGDataHome] = "LOCALAPPDATA",
[kXDGCacheHome] = "TEMP",
[kXDGStateHome] = "LOCALAPPDATA",
[kXDGRuntimeDir] = NULL,
[kXDGConfigDirs] = NULL,
[kXDGDataDirs] = NULL,
@ -38,6 +40,7 @@ static const char *const xdg_defaults[] = {
[kXDGConfigHome] = "~\\AppData\\Local",
[kXDGDataHome] = "~\\AppData\\Local",
[kXDGCacheHome] = "~\\AppData\\Local\\Temp",
[kXDGStateHome] = "~\\AppData\\Local",
[kXDGRuntimeDir] = NULL,
[kXDGConfigDirs] = NULL,
[kXDGDataDirs] = NULL,
@ -45,6 +48,7 @@ static const char *const xdg_defaults[] = {
[kXDGConfigHome] = "~/.config",
[kXDGDataHome] = "~/.local/share",
[kXDGCacheHome] = "~/.cache",
[kXDGStateHome] = "~/.local/state",
[kXDGRuntimeDir] = NULL,
[kXDGConfigDirs] = "/etc/xdg/",
[kXDGDataDirs] = "/usr/local/share/:/usr/share/",
@ -133,15 +137,26 @@ char *stdpaths_user_conf_subpath(const char *fname)
/// Return subpath of $XDG_DATA_HOME
///
/// @param[in] fname New component of the path.
///
/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}`
char *stdpaths_user_data_subpath(const char *fname)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
return concat_fnames_realloc(get_xdg_home(kXDGDataHome), fname, true);
}
/// Return subpath of $XDG_STATE_HOME
///
/// @param[in] fname New component of the path.
/// @param[in] trailing_pathseps Amount of trailing path separators to add.
/// @param[in] escape_commas If true, all commas will be escaped.
///
/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}`.
char *stdpaths_user_data_subpath(const char *fname, const size_t trailing_pathseps,
const bool escape_commas)
/// @return [allocated] `$XDG_STATE_HOME/nvim/{fname}`.
char *stdpaths_user_state_subpath(const char *fname, const size_t trailing_pathseps,
const bool escape_commas)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
char *ret = concat_fnames_realloc(get_xdg_home(kXDGDataHome), fname, true);
char *ret = concat_fnames_realloc(get_xdg_home(kXDGStateHome), fname, true);
const size_t len = strlen(ret);
const size_t numcommas = (escape_commas ? memcnt(ret, ',', len) : 0);
if (numcommas || trailing_pathseps) {

View File

@ -7,6 +7,7 @@ typedef enum {
kXDGConfigHome, ///< XDG_CONFIG_HOME
kXDGDataHome, ///< XDG_DATA_HOME
kXDGCacheHome, ///< XDG_CACHE_HOME
kXDGStateHome, ///< XDG_STATE_HOME
kXDGRuntimeDir, ///< XDG_RUNTIME_DIR
kXDGConfigDirs, ///< XDG_CONFIG_DIRS
kXDGDataDirs, ///< XDG_DATA_DIRS

View File

@ -1447,7 +1447,7 @@ static const char *shada_get_default_file(void)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if (default_shada_file == NULL) {
char *shada_dir = stdpaths_user_data_subpath("shada", 0, false);
char *shada_dir = stdpaths_user_state_subpath("shada", 0, false);
default_shada_file = concat_fnames_realloc(shada_dir, "main.shada", true);
}
return default_shada_file;

View File

@ -163,7 +163,7 @@ describe('startup defaults', function()
end)
it("'shadafile' ('viminfofile')", function()
local env = {XDG_DATA_HOME='Xtest-userdata', XDG_CONFIG_HOME='Xtest-userconfig'}
local env = {XDG_DATA_HOME='Xtest-userdata', XDG_STATE_HOME='Xtest-userstate', XDG_CONFIG_HOME='Xtest-userconfig'}
clear{args={}, args_rm={'-i'}, env=env}
-- Default 'shadafile' is empty.
-- This means use the default location. :help shada-file-name
@ -178,7 +178,7 @@ describe('startup defaults', function()
clear{args={}, args_rm={'-i'}, env=env}
eq({ f }, eval('v:oldfiles'))
os.remove('Xtest-foo')
rmdir('Xtest-userdata')
rmdir('Xtest-userstate')
-- Handles viminfo/viminfofile as alias for shada/shadafile.
eq('\n shadafile=', eval('execute("set shadafile?")'))
@ -206,7 +206,7 @@ describe('startup defaults', function()
describe('$NVIM_LOG_FILE', function()
local xdgdir = 'Xtest-startup-xdg-logpath'
local xdgcachedir = xdgdir..'/nvim'
local xdgstatedir = xdgdir..'/nvim'
after_each(function()
os.remove('Xtest-logpath')
rmdir(xdgdir)
@ -218,21 +218,21 @@ describe('startup defaults', function()
}})
eq('Xtest-logpath', eval('$NVIM_LOG_FILE'))
end)
it('defaults to stdpath("cache")/log if empty', function()
eq(true, mkdir(xdgdir) and mkdir(xdgcachedir))
it('defaults to stdpath("log")/log if empty', function()
eq(true, mkdir(xdgdir) and mkdir(xdgstatedir))
clear({env={
XDG_CACHE_HOME=xdgdir,
XDG_STATE_HOME=xdgdir,
NVIM_LOG_FILE='', -- Empty is invalid.
}})
eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
eq(xdgstatedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
end)
it('defaults to stdpath("cache")/log if invalid', function()
eq(true, mkdir(xdgdir) and mkdir(xdgcachedir))
it('defaults to stdpath("log")/log if invalid', function()
eq(true, mkdir(xdgdir) and mkdir(xdgstatedir))
clear({env={
XDG_CACHE_HOME=xdgdir,
XDG_STATE_HOME=xdgdir,
NVIM_LOG_FILE='.', -- Any directory is invalid.
}})
eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
eq(xdgstatedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
end)
end)
end)
@ -264,6 +264,7 @@ describe('XDG-based defaults', function()
XDG_CONFIG_HOME=nil,
XDG_DATA_HOME=nil,
XDG_CACHE_HOME=nil,
XDG_STATE_HOME=nil,
XDG_RUNTIME_DIR=nil,
XDG_CONFIG_DIRS=nil,
XDG_DATA_DIRS=nil,
@ -293,6 +294,7 @@ describe('XDG-based defaults', function()
local env_sep = iswin() and ';' or ':'
local data_dir = iswin() and 'nvim-data' or 'nvim'
local state_dir = iswin() and 'nvim-data' or 'nvim'
local root_path = iswin() and 'C:' or ''
describe('with too long XDG variables', function()
@ -303,6 +305,7 @@ describe('XDG-based defaults', function()
.. env_sep.. root_path .. ('/b'):rep(2048)
.. (env_sep .. root_path .. '/c'):rep(512)),
XDG_DATA_HOME=(root_path .. ('/X'):rep(4096)),
XDG_STATE_HOME=(root_path .. ('/X'):rep(4096)),
XDG_DATA_DIRS=(root_path .. ('/A'):rep(2048)
.. env_sep .. root_path .. ('/B'):rep(2048)
.. (env_sep .. root_path .. '/C'):rep(512)),
@ -355,13 +358,13 @@ describe('XDG-based defaults', function()
.. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim/after'
.. ',' .. root_path .. ('/x'):rep(4096) .. '/nvim/after'
):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. data_dir .. '/backup//',
eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. state_dir .. '/backup//',
(meths.get_option('backupdir'):gsub('\\', '/')))
eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/swap//',
eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/swap//',
(meths.get_option('directory')):gsub('\\', '/'))
eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/undo//',
eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/undo//',
(meths.get_option('undodir')):gsub('\\', '/'))
eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/view//',
eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/view//',
(meths.get_option('viewdir')):gsub('\\', '/'))
end)
end)
@ -372,6 +375,7 @@ describe('XDG-based defaults', function()
XDG_CONFIG_HOME='$XDG_DATA_HOME',
XDG_CONFIG_DIRS='$XDG_DATA_DIRS',
XDG_DATA_HOME='$XDG_CONFIG_HOME',
XDG_STATE_HOME='$XDG_CONFIG_HOME',
XDG_DATA_DIRS='$XDG_CONFIG_DIRS',
}})
end)
@ -405,13 +409,13 @@ describe('XDG-based defaults', function()
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup//'),
eq(('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
meths.get_option('backupdir'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'),
eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
meths.get_option('directory'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo//'),
eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
meths.get_option('undodir'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view//'),
eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
meths.get_option('viewdir'):gsub('\\', '/'))
meths.command('set all&')
eq(('$XDG_DATA_HOME/nvim'
@ -425,13 +429,13 @@ describe('XDG-based defaults', function()
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
):gsub('\\', '/'), (meths.get_option('runtimepath')):gsub('\\', '/'))
eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup//'),
eq(('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
meths.get_option('backupdir'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'),
eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
meths.get_option('directory'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo//'),
eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
meths.get_option('undodir'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view//'),
eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
meths.get_option('viewdir'):gsub('\\', '/'))
end)
end)
@ -442,6 +446,7 @@ describe('XDG-based defaults', function()
XDG_CONFIG_HOME=', , ,',
XDG_CONFIG_DIRS=',-,-,' .. env_sep .. '-,-,-',
XDG_DATA_HOME=',=,=,',
XDG_STATE_HOME=',=,=,',
XDG_DATA_DIRS=',≡,≡,' .. env_sep .. '≡,≡,≡',
}})
end)
@ -484,13 +489,13 @@ describe('XDG-based defaults', function()
.. ',\\,-\\,-\\,' .. path_sep ..'nvim' .. path_sep ..'after'
.. ',\\, \\, \\,' .. path_sep ..'nvim' .. path_sep ..'after'
), meths.get_option('runtimepath'))
eq('.,\\,=\\,=\\,' .. path_sep .. data_dir .. '' .. path_sep ..'backup' .. (path_sep):rep(2),
eq('.,\\,=\\,=\\,' .. path_sep .. state_dir .. '' .. path_sep ..'backup' .. (path_sep):rep(2),
meths.get_option('backupdir'))
eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'swap' .. (path_sep):rep(2),
eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'swap' .. (path_sep):rep(2),
meths.get_option('directory'))
eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'undo' .. (path_sep):rep(2),
eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'undo' .. (path_sep):rep(2),
meths.get_option('undodir'))
eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'view' .. (path_sep):rep(2),
eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'view' .. (path_sep):rep(2),
meths.get_option('viewdir'))
end)
end)
@ -499,8 +504,9 @@ end)
describe('stdpath()', function()
-- Windows appends 'nvim-data' instead of just 'nvim' to prevent collisions
-- due to XDG_CONFIG_HOME and XDG_DATA_HOME being the same.
-- due to XDG_CONFIG_HOME, XDG_DATA_HOME and XDG_STATE_HOME being the same.
local datadir = iswin() and 'nvim-data' or 'nvim'
local statedir = iswin() and 'nvim-data' or 'nvim'
local env_sep = iswin() and ';' or ':'
it('acceptance', function()
@ -509,6 +515,7 @@ describe('stdpath()', function()
eq('nvim', funcs.fnamemodify(funcs.stdpath('cache'), ':t'))
eq('nvim', funcs.fnamemodify(funcs.stdpath('config'), ':t'))
eq(datadir, funcs.fnamemodify(funcs.stdpath('data'), ':t'))
eq(statedir, funcs.fnamemodify(funcs.stdpath('state'), ':t'))
eq('table', type(funcs.stdpath('config_dirs')))
eq('table', type(funcs.stdpath('data_dirs')))
assert_alive() -- Check for crash. #8393
@ -582,6 +589,39 @@ describe('stdpath()', function()
end)
end)
describe('with "state"' , function ()
it('knows XDG_STATE_HOME', function()
clear({env={
XDG_STATE_HOME=alter_slashes('/home/docwhat/.local'),
}})
eq(alter_slashes('/home/docwhat/.local/'..statedir), funcs.stdpath('state'))
end)
it('handles changes during runtime', function()
clear({env={
XDG_STATE_HOME=alter_slashes('/home/original'),
}})
eq(alter_slashes('/home/original/'..statedir), funcs.stdpath('state'))
command("let $XDG_STATE_HOME='"..alter_slashes('/home/new').."'")
eq(alter_slashes('/home/new/'..statedir), funcs.stdpath('state'))
end)
it("doesn't expand $VARIABLES", function()
clear({env={
XDG_STATE_HOME='$VARIABLES',
VARIABLES='this-should-not-happen',
}})
eq(alter_slashes('$VARIABLES/'..statedir), funcs.stdpath('state'))
end)
it("doesn't expand ~/", function()
clear({env={
XDG_STATE_HOME=alter_slashes('~/frobnitz'),
}})
eq(alter_slashes('~/frobnitz/'..statedir), funcs.stdpath('state'))
end)
end)
describe('with "cache"' , function ()
it('knows XDG_CACHE_HOME', function()
clear({env={