1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
" Show an error-highlighted message and beep, but without a real :echoerr
function! s:Error(message) abort
execute "normal! \<Esc>"
echohl ErrorMsg
echomsg a:message
echohl None
endfunction
" Test whether an option currently has a flag as part of its value
function! s:Has(option, flag) abort
" Horrible :execute to get the option's current setting into a variable
let current = ''
execute 'let current = &' . a:option
" If the flag we're toggling is longer than one character, this must by
" necessity be a delimited option. I think all of those in VimL are
" comma-separated. Extend the flag and value so that they'll still match at
" the start and end. Otherwise, use them as-is.
if strlen(a:flag) > 1
let search_flag = ',' . a:flag . ','
let search_value = ',' . current . ','
else
let search_flag = a:flag
let search_value = current
endif
" Return whether the flag appears in the value
return stridx(search_value, search_flag) > -1
endfunction
" Internal function to do the toggling
function! toggle_flags#Toggle(option, flag, local) abort
" Check for spurious option strings, we don't want to :execute anything funny
if a:option =~# '\L'
call s:Error('Illegal option name')
return 0
endif
" Check the option actually exists
if !exists('&' . a:option)
call s:Error('No such option: ' . a:option)
return 0
endif
" Choose which set command to use
let set = a:local
\ ? 'setlocal'
\ : 'set'
" Find whether the flag is set before the change
let before = s:Has(a:option, a:flag)
" Assign -= or += as the operation to run based on whether the flag already
" appears in the option value or not
let operation = before
\ ? '-='
\ : '+='
" Try to set the option; suppress errors, we'll check our work
silent! execute set
\ . ' '
\ . a:option . operation . escape(a:flag, '\ ')
" Find whether the flag is set after the change
let after = s:Has(a:option, a:flag)
" If we made a difference, report the new value; if we didn't, admit it
if before != after
execute set . ' ' . a:option . '?'
else
call s:Error('Unable to toggle '.a:option.' flag '.a:flag)
endif
" Return whether we made a change
return before != after
endfunction
|