diff options
author | Tom Ryder <tom@sanctum.geek.nz> | 2020-05-15 00:10:13 +1200 |
---|---|---|
committer | Tom Ryder <tom@sanctum.geek.nz> | 2020-05-15 00:10:13 +1200 |
commit | 9ca6705feb0e89fdaef318774d54cc63853a507c (patch) | |
tree | ee1b677e39ad86065bf3e04f7b1c357856545724 | |
parent | Correct and expand a doc sentence (diff) | |
download | vim-spellfile-local-9ca6705feb0e89fdaef318774d54cc63853a507c.tar.gz vim-spellfile-local-9ca6705feb0e89fdaef318774d54cc63853a507c.zip |
Rewrite implementation
Allow custom directories with different behaviour and in general made
the code a bit clearer to read; I really overcooked this the first time
around.
-rw-r--r-- | autoload/spellfile_local.vim | 166 | ||||
-rw-r--r-- | doc/spellfile_local.txt | 17 |
2 files changed, 72 insertions, 111 deletions
diff --git a/autoload/spellfile_local.vim b/autoload/spellfile_local.vim index b61ef3e..618a354 100644 --- a/autoload/spellfile_local.vim +++ b/autoload/spellfile_local.vim @@ -16,85 +16,81 @@ function! spellfile_local#() abort endif let lang = split(spelllangs[0], '_')[0] - " Use current encoding - let encoding = &encoding + " Make a list of all the spellfile names for which we want to search in + " every directory; the first is the normal lang.encoding.add, the second is + " filename.lang.encoding.add, and the third, if there's a filetype set, is + " filetype.lang.encoding.add. + " + let basenames = [ + \ s:Filename([lang, &encoding, 'add']), + \ s:Filename([expand('<afile>:p'), lang, &encoding, 'add']), + \] + if &filetype !=# '' + call add(basenames, s:Filename([&filetype, lang, &encoding, 'add'])) + endif - " Start a list of spellfiles - let spellfiles = [] + " Now make a list of all of the directories in which those files will be + " searched, and where applicable, created; the method for doing this depends + " on whether we have a configured list of directories or not + " + let dirnames = [] - " Imitate Vim's behaviour in creating a `spell` subdir in the first - " writeable element of 'runtimepath' + " If we have a list of directories to use as the base for 'spellfile' /spell + " subdirectories, we'll add all of them to the list, and *attempt* to create + " the first one if it doesn't exist--but it's not fatal if we can't; this is + " intended to be suitable for passing in XDG basedirs " - for runtimepath in s:OptionSplit(&runtimepath) - let path = s:Path(join(add( - \ split(runtimepath, '/', 1), - \ 'spell', - \), '/'), lang, encoding) - if path !=# '' - call add(spellfiles, path) - break + if exists('g:spellfile_local_dirs') && !empty(g:spellfile_local_dirs) + for path in g:spellfile_local_dirs + call add(dirnames, path.'/spell') + endfor + if (!isdirectory(dirnames[0])) + call mkdir(dirnames[0], 'p', 0700) endif - endfor - " Still no 'spellfile'? Quietly give up - if len(spellfiles) == 0 - return + " Failing that, do what Vim does by default: use the first *writeable* entry + " in 'runtimepath', attempting to-create the /spell subdirectory within. If + " none of them are writable, we raise an exception. + " + else + for path in s:OptionSplit(&runtimepath) + if filewritable(path) + let spelldir = path.'/spell' + if isdirectory(spelldir) + \ || mkdir(spelldir, 'p', 0700) + call add(dirnames, spelldir) + break + endif + endif + endfor + throw 'No writable runtime dirs for ''spellfile''' endif - " Get the path to the spelling files directory - let dir = fnamemodify(spellfiles[0], ':h') - - " Specify the name and type of spelling files we'll add, with a list of - " two-key dictionaries. For each of these, the `name` is used as the - " subdirectory, and the `value` as the first component of the filename. + " Now we'll actually combine those two together to make a long list of + " spellfiles, and then set the option " - let types = [ - \ { - \ 'name': 'path', - \ 'value': expand('%:p'), - \ }, - \ { - \ 'name': 'filetype', - \ 'value': &filetype, - \ }, - \] - - " Iterate through the specified types to add them to the spelling files list - for type in types - - " Add a new calculated path to the spellfiles list, if valid - let spellfile = s:Path(dir, lang, encoding, type) - if spellfile !=# '' - call add(spellfiles, spellfile) - endif - + let spellfiles = [] + for dirname in dirnames + for basename in basenames + call add(spellfiles, join([dirname, basename], '/')) + endfor endfor - - " Set the spellfile path list to the concatenated list - let &spellfile = s:OptionJoin(spellfiles) + let &l:spellfile = s:OptionJoin(spellfiles) endfunction -" Escape a path for use as a valid spelling file name; replace any characters +" Escape a path for use as a valid option file name; replace any characters " not in 'isfname' with percent symbols -function! s:Escape(filename) abort +function! s:Filename(parts) abort let filename = '' - for char in split(a:filename, '\zs') - if char !=# '_' && char !=# '/' && char =~# '^\f$' - let filename .= char - else - let filename .= '%' - endif + for char in split(join(a:parts, '.'), '\zs') + let filename .= (char !=# '_' && char !=# '/' && char =~# '^\f$') + \ ? char + \ : '%' endfor return filename endfunction -" Ensure a directory exists, or create it -function! s:Establish(path) abort - return isdirectory(a:path) - \ || exists('*mkdir') && mkdir(a:path, 'p', 0700) -endfunction - " Join a list of strings into a comma-separated option function! s:OptionJoin(list) abort return join(map( @@ -110,51 +106,3 @@ function! s:OptionSplit(string) abort \ 'substitute(v:val, ''\\,'', '''', ''g'')', \) endfunction - -" Given a directory, language, encoding, and optionally a type with -" subdirectory and filename value to extend it, calculate a path, ensuring -" that the relevant directory is created; otherwise return nothing -" -function! s:Path(dir, lang, encoding, ...) abort - - " Pull in the type variable if it was defined - if a:0 > 0 - let type = a:1 - endif - - " Make lists representing the directory path elements and the - " period-separated filename - " - let dir = split(a:dir, '/', 1) - let file = [a:lang, a:encoding, 'add'] - - " If we have an optional type, extend the directory with another element - " according to its name, and insert the value before the filename, - " e.g. append "filetype" to the directory, and insert the current value of - " &filetype before the filename; if we have a type but a blank value, which - " is not necessarily an error condition, stop here and return nothing - " - if exists('type') - if type['value'] ==# '' - return - endif - call add(dir, type['name']) - call insert(file, type['value']) - endif - - " Ensure the directory is in place, trying to create it if need be, and that - " all of it passes an 'isfname' filter, since 'spellfile' checks that - " - let ds = join(dir, '/') - if ds !~# '^\f\+$' - \ || filewritable(ds) != 2 && !mkdir(ds, 'p', 0700) - return - endif - - " Build the full spellfile path, escaping the filename appropriately, and - " return it as a path string - " - let path = add(copy(dir), s:Escape(join(file, '.'))) - return join(path, '/') - -endfunction diff --git a/doc/spellfile_local.txt b/doc/spellfile_local.txt index b030f90..83df0b8 100644 --- a/doc/spellfile_local.txt +++ b/doc/spellfile_local.txt @@ -6,13 +6,11 @@ This plugin extends the behaviour of 'spellfile' for file buffers to add extra spelling word lists that are unique to each path and (if applicable) filetype. The 'spellfile' setting for a file named `test.vim` in one's home directory while writing English in UTF-8 encoding might look like this: - > spellfile=~/.vim/spell/en.utf-8.add ,~/.vim/spell/path/%home%user%test.vim.en.utf-8.add ,~/.vim/spell/filetype/vim.en.utf-8.add < - Words can then be added to the file's word list with `2zg`, or to the filetype's list with `3zg`. @@ -20,6 +18,21 @@ REQUIREMENTS *spellfile_local-requirements* This plugin only loads if 'compatible' is not set. +OPTIONS *spellfile_local-requirements* + + *g:spellfile_local_dirs* +By default, the plugin mimics Vim's default behaviour for 'spellfile' in +attempting to create the "spell" subdirectory in the first path in +'runtimepath' for which it has write permission. To change this behaviour, +perhaps to use XDG basedirs, set the `g:spellfile_local_dirs` option in your +|vimrc|: +> + let g:spellfile_local_dirs = [ + \ '~/.local/share/vim', + \ '/usr/local/share/vim', + \ '/usr/share/vim', + \] +< AUTHOR *spellfile_local-author* Written and maintained by Tom Ryder <tom@sanctum.geek.nz>. |