diff options
author | Tom Ryder <tom@sanctum.geek.nz> | 2019-12-19 18:10:50 +1300 |
---|---|---|
committer | Tom Ryder <tom@sanctum.geek.nz> | 2019-12-19 18:17:28 +1300 |
commit | fd3d5183d7c1d7494140ff77ad47857f86657f18 (patch) | |
tree | ebbe71d9736ebba502e7a341af21d5b986c4a187 | |
download | vim-spellfile-local-fd3d5183d7c1d7494140ff77ad47857f86657f18.tar.gz vim-spellfile-local-fd3d5183d7c1d7494140ff77ad47857f86657f18.zip |
First version, spun out from tejr dotfiles v8.7.0v0.1.0
-rw-r--r-- | README.md | 21 | ||||
-rw-r--r-- | VERSION | 1 | ||||
-rw-r--r-- | autoload/spellfile_local.vim | 154 | ||||
-rw-r--r-- | doc/spellfile_local.txt | 30 | ||||
-rw-r--r-- | plugin/spellfile_local.vim | 20 |
5 files changed, 226 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..3942a96 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +spellfile\_local.vim +==================== + +This plugin extends the behaviour of `%` for file buffers to add extra spelling +word lists that are unique to each path and (if applicable) filetype. The `%` +setting for a file named `test.vim` 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`. + +License +------- + +Copyright (c) [Tom Ryder][1]. Distributed under the same terms as Vim itself. +See `:help license`. + +[1]: https://sanctum.geek.nz/ @@ -0,0 +1 @@ +0.1.0 diff --git a/autoload/spellfile_local.vim b/autoload/spellfile_local.vim new file mode 100644 index 0000000..7dbe8fb --- /dev/null +++ b/autoload/spellfile_local.vim @@ -0,0 +1,154 @@ +" Entry point for plugin +function! spellfile_local#() abort + + " If this is a special buffer, don't do anything + if index(['nofile', 'quickfix', 'help'], &buftype) >= 0 + return + endif + + " Get the first item in the spelling languages list, bail if there aren't + " any; strip any regional suffix (e.g. en_NZ), too, as the final 'spellfile' + " value won't tolerate it + " + let spelllangs = s:OptionSplit(&spelllang) + if len(spelllangs) == 0 + return + endif + let lang = split(spelllangs[0], '_')[0] + + " Use current encoding + let encoding = &encoding + + " Start a list of spellfiles + let spellfiles = [] + + " Imitate Vim's behaviour in creating a `spell` subdir in the first + " writeable element of 'runtimepath' + " + 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 + endif + endfor + + " Still no 'spellfile'? Quietly give up + if len(spellfiles) == 0 + return + 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. We + " + 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 + + endfor + + " Set the spellfile path list to the concatenated list + let &spellfile = s:OptionJoin(spellfiles) + +endfunction + +" Escape a path for use as a valid spelling file name; replace any characters +" not in 'isfname' with percent symbols +function! s:Escape(filename) abort + let filename = '' + for char in split(a:filename, '\zs') + if char !=# '_' && char !=# '/' && char =~# '^\f$' + let filename .= char + else + let filename .= '%' + endif + 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( + \ a:list + \,'substitute(v:val, ''\\\@<!,'', ''\\,'', ''g'')' + \), ',') +endfunction + +" Split a comma-separated option into a list of strings +function! s:OptionSplit(string) abort + return map( + \ split(a:string, '\\\@<!,[, ]*') + \,'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, '0700', 'p') + 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 new file mode 100644 index 0000000..976614b --- /dev/null +++ b/doc/spellfile_local.txt @@ -0,0 +1,30 @@ +*spellfile_local.txt* For Vim version 7.0 Last change: 2019 Dec 19 + +DESCRIPTION *spellfile_local* + +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` 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`. + +REQUIREMENTS *spellfile_local-requirements* + +This plugin only loads if 'compatible' is not set. + +AUTHOR *spellfile_local-author* + +Written and maintained by Tom Ryder <tom@sanctum.geek.nz>. + +LICENSE *spellfile_local-license* + +Licensed for distribution under the same terms as Vim itself (see |license|). + + vim:tw=78:ts=8:ft=help:norl: diff --git a/plugin/spellfile_local.vim b/plugin/spellfile_local.vim new file mode 100644 index 0000000..0730775 --- /dev/null +++ b/plugin/spellfile_local.vim @@ -0,0 +1,20 @@ +" +" spellfile_local.vim: Set extra 'spellfile' elements for full file paths and +" filetype, to give the option of adding to file-specific or filetype-specific +" spelling word lists. +" +" Author: Tom Ryder <tom@sanctum.geek.nz> +" License: Same as Vim itself +" +if exists('loaded_spellfile_local') || &compatible + finish +endif +let loaded_spellfile_local = 1 + +" For various events involving establishing or renaming a file buffer or +" changing its filetype, rebuild the 'spellfile' definition accordingly +" +augroup spellfile_local + autocmd BufFilePost,BufNewFile,BufRead,EncodingChanged,FileType * + \ call spellfile_local#() +augroup END |