aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2019-12-19 17:20:01 +1300
committerTom Ryder <tom@sanctum.geek.nz>2019-12-19 17:20:01 +1300
commit5f3b58d62ca9e348468f1ce622e86badbd5d6e8f (patch)
treef2d81aaa586d379f0998a6a02e34ec8a2997bf19
parentMerge branch 'release/v8.6.0' (diff)
parentBump VERSION (diff)
downloaddotfiles-5f3b58d62ca9e348468f1ce622e86badbd5d6e8f.tar.gz
dotfiles-5f3b58d62ca9e348468f1ce622e86badbd5d6e8f.zip
Merge branch 'release/v8.7.0'v8.7.0
* release/v8.7.0: Overhaul spellfile_local.vim plugin Remove complex 'spellfile' setting Comment and clean up new Vim configuration
-rw-r--r--VERSION4
-rw-r--r--vim/autoload/colorscheme.vim13
-rw-r--r--vim/autoload/indent.vim27
-rw-r--r--vim/autoload/spellfile_local.vim186
-rw-r--r--vim/plugin/spellfile_local.vim18
-rw-r--r--vim/vimrc27
6 files changed, 183 insertions, 92 deletions
diff --git a/VERSION b/VERSION
index 1d6c61ac..421c7f5a 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-tejr dotfiles v8.6.0
-Wed, 18 Dec 2019 04:32:16 +0000
+tejr dotfiles v8.7.0
+Thu, 19 Dec 2019 04:19:58 +0000
diff --git a/vim/autoload/colorscheme.vim b/vim/autoload/colorscheme.vim
index 591550fd..db965d99 100644
--- a/vim/autoload/colorscheme.vim
+++ b/vim/autoload/colorscheme.vim
@@ -1,10 +1,21 @@
" Reset window-global value for 'cursorline' based on current colorscheme name
function! colorscheme#UpdateCursorline(colors_name, list) abort
+
+ " Record current tab and window number so we can jump back once we're done
let l:tab = tabpagenr()
let l:win = winnr()
- tabdo windo let &g:cursorline = index(a:list, a:colors_name) >= 0
+
+ " Set the window-global value for 'cursorline' in each window of each tab;
+ " on if the current colorscheme is in the whitelist, and off otherwise; fire
+ " the WinEnter and WinLeave events so any other 'cursorline' related hooks
+ " can run too
+ let l:cursorline = index(a:list, a:colors_name) >= 0
+ tabdo windo let &g:cursorline = l:cursorline
\| silent doautocmd WinEnter,WinLeave
+
+ " Move back to the tab and window the user started in
execute l:tab . 'tabnext'
execute l:win . 'wincmd w'
\| silent doautocmd WinEnter
+
endfunction
diff --git a/vim/autoload/indent.vim b/vim/autoload/indent.vim
index 3e850c63..77403658 100644
--- a/vim/autoload/indent.vim
+++ b/vim/autoload/indent.vim
@@ -1,32 +1,45 @@
+" Set the current buffer to space indent
function! indent#spaces(...) abort
setlocal expandtab
+
+ " If an argument was provided, use that for the number of spaces; otherwise,
+ " set 'shiftwidth' to 0, which then copies 'tabstop'
let &l:shiftwidth = a:0
\ ? a:1
\ : 0
+
+ " If we have the patch that supports it, set 'softtabstop' to dynamically
+ " mirror the value of 'shiftwidth'; failing that, just copy it
let &l:softtabstop = has#('patch-7.3.693')
\ ? -1
\ : &l:shiftwidth
+
call indent#undo()
endfunction
+" Set the current buffer to tab indent
function! indent#tabs() abort
- setlocal noexpandtab shiftwidth< softtabstop<
+ setlocal noexpandtab
+ setlocal shiftwidth< softtabstop<
call indent#undo()
endfunction
+" Add commands to b:undo_indent to clean up buffer-local indentation changes
+" on a change of filetype
function! indent#undo() abort
- if exists('b:undo_indent_set')
+
+ " Check and set a flag so that we only do this once per buffer
+ if exists('b:undo_indent_type_set')
return
endif
- let l:undo = 'call indent#reset()'
+ let b:undo_indent_type_set = 1
+
+ " Either set or append relevant commands to b:undo_indent
+ let l:undo = 'setlocal expandtab< shiftwidth< softtabstop< tabstop<'
if exists('b:undo_indent')
let b:undo_indent .= '|'.l:undo
else
let b:undo_indent = l:undo
endif
- let b:undo_indent_set = 1
-endfunction
-function! indent#reset() abort
- setlocal expandtab< shiftwidth< softtabstop< tabstop<
endfunction
diff --git a/vim/autoload/spellfile_local.vim b/vim/autoload/spellfile_local.vim
index e119b718..7dbe8fb5 100644
--- a/vim/autoload/spellfile_local.vim
+++ b/vim/autoload/spellfile_local.vim
@@ -1,72 +1,154 @@
-function! s:SplitOption(string) abort
- return map(
- \ split(a:string, '\\\@<!,[, ]*')
- \,'substitute(v:val, ''\\,'', '''', ''g'')'
- \)
+" 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
-function! s:JoinOption(list) abort
- return join(map(
- \ a:list
- \,'substitute(v:val, ''\\\@<!,'', ''\\,'', ''g'')'
- \), ',')
+" 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
-function! spellfile_local#() abort
+" 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
- set spellfile<
+" 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
- let spelllangs = s:SplitOption(&spelllang)
- if !len(spelllangs) || spelllangs[0] ==# ''
- echoerr 'Blank ''spelllang'''
- endif
- let spelllang = substitute(spelllangs[0], '_.*', '', '')
+" 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
- if !len(&encoding)
- echoerr 'Blank ''encoding'''
+ " Pull in the type variable if it was defined
+ if a:0 > 0
+ let type = a:1
endif
- let spellfiles = s:SplitOption(&spellfile)
- if len(spellfiles) != 1 || spellfiles[0] ==# ''
- return
+ " 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
- let spelldir = fnamemodify(spellfiles[0], ':h')
- if spelldir ==# ''
- echoerr 'Blank directory'
+ " 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
- try
- let path = tr(expand('%:p'), '/', '%')
- if path ==# ''
- echoerr 'Blank path'
- endif
- call s:Establish(spelldir.'/path')
- call add(spellfiles, spelldir.'/path/'.join([
- \ path
- \,spelllang
- \,&encoding
- \,'add'
- \], '.'))
-
- if &filetype ==# ''
- echoerr 'Blank filetype'
- endif
- call s:Establish(spelldir.'/filetype')
- call add(spellfiles, spelldir.'/filetype/'.join([
- \ &filetype
- \,spelllang
- \,&encoding
- \,'add'
- \], '.'))
- catch
- endtry
-
- let &l:spellfile = s:JoinOption(spellfiles)
+ " 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/vim/plugin/spellfile_local.vim b/vim/plugin/spellfile_local.vim
index f6918bfb..07307754 100644
--- a/vim/plugin/spellfile_local.vim
+++ b/vim/plugin/spellfile_local.vim
@@ -1,12 +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
-command! -bar SetLocalSpellFiles
- \ call spellfile_local#()
-
+" For various events involving establishing or renaming a file buffer or
+" changing its filetype, rebuild the 'spellfile' definition accordingly
+"
augroup spellfile_local
- autocmd BufNew,BufRead *
- \ SetLocalSpellFiles
+ autocmd BufFilePost,BufNewFile,BufRead,EncodingChanged,FileType *
+ \ call spellfile_local#()
augroup END
diff --git a/vim/vimrc b/vim/vimrc
index 91424fd1..07f979b8 100644
--- a/vim/vimrc
+++ b/vim/vimrc
@@ -2,7 +2,7 @@
" Tom Ryder (tejr)’s Literate Vimrc
" ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
"
-" Last updated: Wed, 18 Dec 2019 16:02:05 +1300
+" Last updated: Thu, 19 Dec 2019 17:07:46 +1300
"
" │ And I was lifted up in heart, and thought
" │ Of all my late-shown prowess in the lists,
@@ -300,32 +300,9 @@ endif
" For spelling, use New Zealand English by default, but later on we’ll
" configure a leader mapping to switch to United States English, since I so
-" often have to write for Yankees. We’ll set the 'spellfile' option too, to
-" place it in the cache directory into which we’ve been putting everything.
-" We’ll follow Vim’s standard naming convention for the file itself, though.
-" If available, my plugin spellfile_local.vim will extend this later to add
-" more spelling word lists per filetype and per file.
-"
-" We briefly set 'isfname' to every character but NUL if we’re using Unix,
-" since Vim uses it internally for 'spellfile' assignment to decide whether
-" the path is valid. We put it back immediately afterwards.
+" often have to write for Yankees.
"
set spelllang=en_nz
-let s:spelllang = split#Option(&spelllang)
-let s:spellfile = $MYVIM.'/spell/'.join([
- \ split(s:spelllang[0], '_')[0], &encoding, 'add',
- \], '.')
-if has#('unix')
- let s:isfname = &isfname
- set isfname=1-255
-endif
-set spellfile&
-execute 'set spellfile^='.escape#Arg(escape#Item(s:spellfile))
-if exists('s:isfname')
- execute 'set isfname='.escape#Arg(s:isfname)
- unlet s:isfname
-endif
-CreatePath $MYVIM/spell
" Spell checking includes optional support for catching lower case letters at
" the start of sentences, and defines a pattern in 'spellcapcheck' for the end