aboutsummaryrefslogtreecommitdiff
path: root/plugin/casefmt.vim
blob: 4824092ab3dcf00fdcabb39c8dc34f078c3f8231 (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
" Mappings for changing the case type of a text object. These mappings are invoked with <C-c>.
"
" This way, to change the case format of a word to snake_case, one can run:
"
" <C-c>siw
"
" The format of this command is
"
" <C-c><target_casefmt><text_object>
"
" valid case formats are
"
"   s - snake_case
"   S - Upper_Snake_Case
"   c - camelCase
"   C - UpperCamelCase
"   k - KONSTANT_CASE

noremap  <silent> <C-c>s :<C-u>let g:CaseFmtFunction=function("<SID>to_snake")<cr>:<C-u>set operatorfunc=<SID>casefmt_do<cr>g@
vnoremap <silent> <C-c>s :<C-u>let g:CaseFmtFunction=function("<SID>to_snake")<cr>:<C-u>call <SID>casefmt_do(visualmode(), 1)<cr>
nmap <C-c>ss ^<C-c>s$

noremap  <silent> <C-c>S :<C-u>let g:CaseFmtFunction=function("<SID>to_upper_snake")<cr>:<C-u>set operatorfunc=<SID>casefmt_do<cr>g@
vnoremap <silent> <C-c>S :<C-u>let g:CaseFmtFunction=function("<SID>to_upper_snake")<cr>:<C-u>call <SID>casefmt_do(visualmode(), 1)<cr>
nmap <C-c>SS ^<C-c>S$

noremap  <silent> <C-c>c :<C-u>let g:CaseFmtFunction=function("<SID>to_camel")<cr>:<C-u>set operatorfunc=<SID>casefmt_do<cr>g@
vnoremap <silent> <C-c>c :<C-u>let g:CaseFmtFunction=function("<SID>to_camel")<cr>:<C-u>call <SID>casefmt_do(visualmode(), 1)<cr>
nmap <C-c>cc ^<C-c>c$

noremap  <silent> <C-c>C :<C-u>let g:CaseFmtFunction=function("<SID>to_Camel")<cr>:<C-u>set operatorfunc=<SID>casefmt_do<cr>g@
vnoremap <silent> <C-c>C :<C-u>let g:CaseFmtFunction=function("<SID>to_Camel")<cr>:<C-u>call <SID>casefmt_do(visualmode(), 1)<cr>
nmap <C-c>CC ^<C-c>C$

noremap  <silent> <C-c>k :<C-u>let g:CaseFmtFunction=function("<SID>to_CONSTANT")<cr>:<C-u>set operatorfunc=<SID>casefmt_do<cr>g@
vnoremap <silent> <C-c>k :<C-u>let g:CaseFmtFunction=function("<SID>to_CONSTANT")<cr>:<C-u>call <SID>casefmt_do(visualmode(), 1)<cr>
nmap <C-c>kk ^<C-c>k$

" CamelCaseStuff

" what_about_this
" test_camel_case

function! s:casefmt_do(type, ...) abort
  if a:0
    silent exe "norm! gvy"
  elseif a:type == 'line'
    " yank the text described by the motion
    silent exe "norm! '[V']y"
  else
    silent exe "norm! `[v`]y"
  endif

  let yanked = getreg('"', 1, v:true)
  let yankedtype = getregtype('"')

  let changed = []
  for n in yanked
    let split = split(n, '\<\|\>') " Split by word boundaries
    let new_split = []

    for s in split " Iterate by words.
      if s =~ "[a-zA-Z_0-9]*" " Is s an identifier?
        call add(new_split, call(g:CaseFmtFunction, [s]))
      else
        call add(new_split, s)
      endif
    endfor

    call add(changed, join(new_split, ''))
  endfor

  call setreg('"', changed, yankedtype)

  norm gvp

  " Reset the yanked text to what it was originally.
  call setreg('"', yanked, yankedtype)
endfunction

" snake_case is the platonic form that all other forms build from. This function
" tries to be smart about detecting the current case format and converting it
" properly.
function! s:to_snake(s) abort
  if a:s =~ '[a-z][A-Z]'
    " a:s has a camel case boundary in it.
    return tolower(substitute(a:s, '\%([a-zA-Z]\)\zs\ze\([A-Z0-9]\)', '_', "g"))
  endif

  return tolower(a:s)
endfunction

function s:to_upper_snake(s) abort
  return substitute(s:to_snake(a:s), '\%(_\|\<\)\zs\w\ze', '\u\0', 'g')
endfunction

function! s:to_camel(s) abort
  return substitute(s:to_snake(a:s), '_\([a-z]\)', '\u\1', "g")
endfunction

function! s:to_Camel(s) abort
  return substitute(s:to_camel(a:s), '\<\w', '\u\0', 'g')
endfunction

function! s:to_CONSTANT(s) abort
  return toupper(s:to_snake(a:s))
endfunction