summaryrefslogtreecommitdiffstats
path: root/autoload/vimtex/imaps.vim
blob: 6b682f0c0c20f9eaf8f2b1913761ec002384f3d5 (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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1

" vimtex - LaTeX plugin for Vim
"
" Maintainer: Karl Yngve Lervåg
" Email:      karl.yngve@gmail.com
"

function! vimtex#imaps#init_buffer() abort " {{{1
  if !g:vimtex_imaps_enabled | return | endif

  "
  " Create imaps
  "
  let l:maps = g:vimtex_imaps_list
  for l:disable in g:vimtex_imaps_disabled
    let l:maps = filter(l:maps, 'v:val.lhs !=# ''' . l:disable . '''')
  endfor
  for l:map in l:maps + get(s:, 'custom_maps', [])
    call s:create_map(l:map)
  endfor

  "
  " Add mappings and commands
  "
  command! -buffer  VimtexImapsList            call vimtex#imaps#list()
  nnoremap <buffer> <plug>(vimtex-imaps-list) :call vimtex#imaps#list()<cr>
endfunction

" }}}1

function! vimtex#imaps#add_map(map) abort " {{{1
  let s:custom_maps = get(s:, 'custom_maps', []) + [a:map]

  if exists('s:created_maps')
    call s:create_map(a:map)
  endif
endfunction

" }}}1
function! vimtex#imaps#list() abort " {{{1
  silent new vimtex\ imaps

  for l:map in s:created_maps
    call append('$', printf('%5S  ->  %-30S %S',
          \ get(l:map, 'leader', get(g:, 'vimtex_imaps_leader', '`')) . l:map.lhs,
          \ l:map.rhs,
          \ get(l:map, 'wrapper', 'vimtex#imaps#wrap_math')))
  endfor
  0delete _

  nnoremap <silent><nowait><buffer> q     :bwipeout<cr>
  nnoremap <silent><nowait><buffer> <esc> :bwipeout<cr>

  setlocal bufhidden=wipe
  setlocal buftype=nofile
  setlocal concealcursor=nvic
  setlocal conceallevel=0
  setlocal cursorline
  setlocal nobuflisted
  setlocal nolist
  setlocal nospell
  setlocal noswapfile
  setlocal nowrap
  setlocal nonumber
  setlocal norelativenumber
  setlocal nomodifiable

  syntax match VimtexImapsLhs     /^.*\ze->/ nextgroup=VimtexImapsArrow
  syntax match VimtexImapsArrow   /->/       contained nextgroup=VimtexImapsRhs
  syntax match VimtexImapsRhs     /\s*\S*/   contained nextgroup=VimtexImapsWrapper
  syntax match VimtexImapsWrapper /.*/       contained
endfunction

" }}}1

"
" The imap generator
"
function! s:create_map(map) abort " {{{1
  if index(s:created_maps, a:map) >= 0 | return | endif

  let l:leader = get(a:map, 'leader', get(g:, 'vimtex_imaps_leader', '`'))
  if l:leader !=# '' && !hasmapto(l:leader, 'i')
    silent execute 'inoremap <silent><nowait><buffer>' l:leader . l:leader l:leader
  endif
  let l:lhs = l:leader . a:map.lhs

  let l:wrapper = get(a:map, 'wrapper', 'vimtex#imaps#wrap_math')
  if ! exists('*' . l:wrapper)
    echoerr 'vimtex error: imaps wrapper does not exist!'
    echoerr '              ' . l:wrapper
    return
  endif

  " Some wrappers use a context which must be made available to the wrapper
  " function at run time.
  if has_key(a:map, 'context')
    execute 'let l:key = "' . escape(l:lhs, '<') . '"'
    let l:key .= a:map.rhs
    if !exists('b:vimtex_context')
      let b:vimtex_context = {}
    endif
    let b:vimtex_context[l:key] = a:map.context
  endif

  " The rhs may be evaluated before being passed to wrapper, unless expr is
  " disabled (which it is by default)
  if !get(a:map, 'expr')
    let a:map.rhs = string(a:map.rhs)
  endif

  silent execute 'inoremap <expr><silent><nowait><buffer>' l:lhs
        \ l:wrapper . '("' . escape(l:lhs, '\') . '", ' . a:map.rhs . ')'

  let s:created_maps += [a:map]
endfunction

" }}}1

"
" Wrappers
"
function! vimtex#imaps#wrap_trivial(lhs, rhs) abort " {{{1
  return a:rhs
endfunction

" }}}1
function! vimtex#imaps#wrap_math(lhs, rhs) abort " {{{1
  return s:is_math() ? a:rhs : a:lhs
endfunction

" }}}1
function! vimtex#imaps#wrap_environment(lhs, rhs) abort " {{{1
  let l:return = a:lhs
  let l:cursor = vimtex#pos#val(vimtex#pos#get_cursor())
  let l:value = 0

  for l:context in b:vimtex_context[a:lhs . a:rhs]
    if type(l:context) == type('')
      let l:envs = [l:context]
      let l:rhs = a:rhs
    elseif type(l:context) == type({})
      let l:envs = l:context.envs
      let l:rhs = l:context.rhs
    endif

    for l:env in l:envs
      let l:candidate_value = vimtex#pos#val(vimtex#env#is_inside(l:env))
      if l:candidate_value > l:value
        let l:value = l:candidate_value
        let l:return = l:rhs
      endif
    endfor

    unlet l:context
  endfor

  return l:return
endfunction

" }}}1

"
" Special rhs styles
"
function! vimtex#imaps#style_math(command) " {{{1
  return s:is_math()
        \ ? '\' . a:command . '{' . nr2char(getchar()) . '}'
        \ : ''
endfunction

" }}}1

"
" Helpers
"
function! s:is_math() abort " {{{1
  return match(map(synstack(line('.'), max([col('.') - 1, 1])),
        \ 'synIDattr(v:val, ''name'')'), '^texMathZone') >= 0
endfunction

" }}}1


" {{{1 Initialize module

let s:created_maps = []

" }}}1

endif