aboutsummaryrefslogtreecommitdiff
path: root/autoload/toggle_flags.vim
blob: eba30c20764d99ee3ead4051384f4c47903f0629 (plain) (blame)
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