" Mappings for changing the case type of a text object. These mappings are invoked with . " " This way, to change the case format of a word to snake_case, one can run: " " siw " " the format of this command is " " [j] " " if the j is included the text object is joined using the case format. " " valid case formats are " " s - snake_case " S - Upper_Snake_Case " c - camelCase " C - UpperCamelCase " k - KONSTANT_CASE " K - KONSTANT CASE (toupper(title case)) " t - title case " T - Title Case " - - dashed-case " u - lowercase " U - UPPERCASE if ! exists('g:casefmt_include_bindings') let g:casefmt_include_bindings = 1 endif if ! exists('g:casefmt_leader') let g:casefmt_leader = '' endif let s:case_fmts = { \ 's': 'to_snake', \ '_': 'to_snake', \ 'S': 'to_Snake', \ 'c': 'to_camel', \ 'C': 'to_Camel', \ 'k': 'to_CONSTANT', \ 'K': 'to_CONSTANT_space', \ 't': 'to_title', \ 'T': 'to_Title', \ '-': 'to_dashed', \ 'u': 'to_lower', \ 'U': 'to_upper' \ } function! CaseFmt_AddFormat(key, funcname) abort exec printf("noremap (casefmt-leader-no-set)%s " \ . "let g:CaseFmtFunction=function(\"\%s\")" \ . "set operatorfunc=\casefmt_dog@", a:key, a:funcname) endfunction noremap (casefmt-leader) let g:CaseFmtProcessor=function("casefmt_default_processor")(casefmt-leader-no-set) for [k, v] in items(s:case_fmts) call CaseFmt_AddFormat(k, v) endfor if g:casefmt_include_bindings exec printf("nmap %s (casefmt-leader)", g:casefmt_leader) exec printf("vmap %s (casefmt-leader)", g:casefmt_leader) endif noremap (casefmt-leader)j let g:CaseFmtProcessor=function("casefmt_joiner")(casefmt-leader-no-set) function! s:casefmt_do(type, ...) abort let cb = {} if !exists('g:CaseFmtProcessor') let g:CaseFmtProcessor = function("\casefmt_default_processor") endif let cb.operate = g:CaseFmtProcessor call fieldmarshal#modifytext(a:type, cb) normal! `` endfunction " Default processor. Calls change case fmt on each word. function! s:casefmt_default_processor(yanked, type) let changed = [] for n in a: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, g:CaseFmtFunction(s:normalize(s))) else call add(new_split, s) endif endfor call add(changed, join(new_split, '')) endfor return changed endfunction function! s:casefmt_joiner(yanked, type) abort let changed = [] for n in a:yanked call add(changed, g:CaseFmtFunction(tolower(substitute(n, '\s\+', '_', 'g')))) endfor return changed endfunction " snake_case is the platonic form that all other forms build from. This function " tries to be SmartAboutDetecting_the current case format and converting it " properly. function! s:normalize(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_snake(s) abort return a:s endfunction function! s:to_Snake(s) abort return substitute(a:s, '\%(_\|\<\)\zs\w\ze', '\u\0', 'g') endfunction function! s:to_camel(s) abort return substitute(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(a:s) endfunction function! s:to_CONSTANT_space(s) abort return toupper(s:to_title(a:s)) endfunction function! s:to_title(s) abort return substitute(a:s, '_', ' ', 'g') endfunction function! s:to_Title(s) abort return substitute(s:to_title(a:s), '\<[a-z]', '\u\0', 'g') endfunction function! s:to_lower(s) abort return tolower(substitute(a:s, '_', '', 'g')) endfunction function! s:to_upper(s) abort return toupper(substitute(a:s, '_', '', 'g')) endfunction function! s:to_dashed(s) abort return substitute(a:s, '_', '-', 'g') endfunction " Replaces "search" with "replace" across a given range, but rather than replace " verbatim, replace respecting the case format given. function! s:case_substitute(start, end, search, replace, ...) if a:0 > 1 throw "Command takes either 2 or 3 arguments!" endif let flags = a:0 == 1 ? a:1 : 'cCksS' for c in flags if ! has_key(s:case_fmts, c) throw "Unknown case format: " . c endif endfor let search_norm = s:normalize(a:search) let replace_norm = s:normalize(a:replace) for c in flags let l:Func = function("\" . s:case_fmts[c]) exec printf("silent! %d,%ds/\\V%s/%s/g", a:start, a:end, l:Func(escape(search_norm, '\')), l:Func(escape(replace_norm, '\'))) endfor endfunction " CaseSubstitute command. " " [range] CaseSubstitute [flags] " " This command acts similarly to substitute, except it respects the case format " of what it is trying to replace. For example: " " Running " " CaseSubstitute TestThing DoThing " " on " " TestThing DoThing " testThing doThing " test_thing -> do_thing " Test_Thing Do_Thing " TEST_THING DO_THING " " flags contain the case formats to replace. Default is 'cCksS' for: " " [c]amelCase " [C]amelCase " [k]ONSTANT_CASE " [s]nake_case " [S]nake_Case " " does not include " " [T]itle Case " [t]itle case " [K]ONSTANT CASE " [-]dashed-case " [U]PPERCASE " [u]lowercase command! -range -nargs=+ CaseSubstitute \ call case_substitute(, , )