aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2020-05-15 00:10:13 +1200
committerTom Ryder <tom@sanctum.geek.nz>2020-05-15 00:10:13 +1200
commit9ca6705feb0e89fdaef318774d54cc63853a507c (patch)
treeee1b677e39ad86065bf3e04f7b1c357856545724
parentCorrect and expand a doc sentence (diff)
downloadvim-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.vim166
-rw-r--r--doc/spellfile_local.txt17
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>.