aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2019-12-19 18:10:50 +1300
committerTom Ryder <tom@sanctum.geek.nz>2019-12-19 18:17:28 +1300
commitfd3d5183d7c1d7494140ff77ad47857f86657f18 (patch)
treeebbe71d9736ebba502e7a341af21d5b986c4a187
downloadvim-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.md21
-rw-r--r--VERSION1
-rw-r--r--autoload/spellfile_local.vim154
-rw-r--r--doc/spellfile_local.txt30
-rw-r--r--plugin/spellfile_local.vim20
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/
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..6e8bf73
--- /dev/null
+++ b/VERSION
@@ -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