mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 04:17:01 +00:00 
			
		
		
		
	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:
		
							
								
								
									
										14
									
								
								man/nvim.1
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								man/nvim.1
									
									
									
									
									
								
							| @@ -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 | ||||
|   | ||||
| @@ -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") | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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|. | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
| --------------- | ||||
|   | ||||
| @@ -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")) { | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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={ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Ivan
					Ivan