aboutsummaryrefslogtreecommitdiff
path: root/autoload
diff options
context:
space:
mode:
Diffstat (limited to 'autoload')
-rw-r--r--autoload/subwords.vim185
1 files changed, 185 insertions, 0 deletions
diff --git a/autoload/subwords.vim b/autoload/subwords.vim
new file mode 100644
index 0000000..eef8f8b
--- /dev/null
+++ b/autoload/subwords.vim
@@ -0,0 +1,185 @@
+let s:subword_motion = ""
+let s:subword_nosave = 0
+
+" Return the type of meta-word (i.e. camelCase, snake_case). If
+" a:prefer_camel is set, then a word like ThisIs_A_MixOfCamel_And_Snake will
+" some_snake_cae SomeCamelCase SOME_CONSTANT_CASE
+" return 'camel', otherwise it'll return 'snake'.
+function! s:detect_word_type(prefer_camel, word) abort
+ let is_camel = 0
+ if a:word =~ '[a-z][A-Z]'
+ let is_camel = 1
+
+ if a:prefer_camel
+ " The word contains a camelCase boundary.
+ return 'camel'
+ endif
+ endif
+
+ if a:word =~ '_\|\W'
+ " The word contains a sake_case boundary.
+ return 'snake'
+ endif
+
+ if is_camel
+ return 'camel'
+ endif
+
+ " There is not discernible type, it's probably just a single word.
+ return 'word'
+endfunction
+
+" Move the cursor to the next subowrd.
+function! subwords#next(vis, forward)
+ if ! s:subword_nosave
+ if a:forward
+ let s:subword_motion = 'next'
+ else
+ let s:subword_motion = 'prev'
+ endif
+ endif
+
+ let i = 0
+ while i < v:count1
+ call search(
+ \ '\([a-z]\zs[A-Z]\ze\)\|\(\W\|_\)\zs\w\ze', (a:forward ? '' : 'b'))
+ let i += 1
+ endwhile
+
+ let s:subword_nosave = 0
+endfunction
+
+" Visually highlights a subword.
+"
+" If a:prefer_camel is set, then WordsLike_This will be interpreted with
+" camelCase.
+"
+" if a:around is set, the highlight around the subword (otherwise highlight the
+" inner subword).
+function! subwords#visual(prefer_camel, around)
+
+ " Detect the type of the word.
+ let word = expand("<cword>")
+ let t = s:detect_word_type(a:prefer_camel, word)
+
+ let expr = ''
+
+ if t == 'camel'
+ let expr = 'v'
+
+ let line = getline('.')
+ let c = col('.') - 1
+ let i = 0
+
+ while line[c] =~ '[a-z]' && c >= 0
+ let c -= 1
+ let i += 1
+ endwhile
+
+ " camelCase
+
+ if c >= 0 && ! (line[c] =~ '[A-Z_]')
+ " If we are at the beginning of the meta word, the don't go back too far.
+ let i -= 1
+ endif
+
+ if i > 0
+ let expr .= printf("%dh", i)
+ endif
+
+ let expr .= 'o'
+
+ let c = col('.') - 1
+ let i = 0
+
+ if line[c] =~ '[A-Z_]'
+ " Actually on the starting capital letter, include it, but start counting
+ " from the next character.
+ let i += 1
+ let c += 1
+ endif
+
+ while c < len(line) && line[c] =~ '[a-z]'
+ let c += 1
+ let i += 1
+ endwhile
+
+ if i > 1
+ let expr .= printf("%dl", i - 1)
+ endif
+
+ elseif t == "snake"
+ let expr = 'v'
+
+ let line = getline('.')
+ let c = col('.') - 1
+ let i = 0
+
+ while c >= 0 && !( line[c] =~ '\W' ) && line[c] != '_'
+ let c -= 1
+ let i += 1
+ endwhile
+
+ let lhs_under = c >= 0 && line[c] == '_'
+
+ let i -= 1
+ let c += 1
+
+ if i > 0
+ let expr .= printf('%dho', i)
+ endif
+
+ let c = col('.') - 1
+ let i = 0
+
+ while c < len(line) && !(line[c] =~ '\W') && line[c] != '_'
+ let c += 1
+ let i += 1
+ endwhile
+
+ let rhs_under = c < len(line) && line[c] == '_'
+
+ let i -= 1
+ let c -= 1
+
+ if i > 0
+ let expr .= printf('%dl', i)
+ endif
+
+ if a:around
+ if rhs_under
+ let expr .= 'l'
+ elseif lhs_under
+ let expr .= 'oho'
+ endif
+ endif
+
+
+ elseif t == "word"
+ " Just a word? Easy peasy.
+ let expr = 'viw'
+ endif
+
+ return expr
+endfunction!
+
+" Clear the subword motion. (used for replacement TtfF)
+function! subwords#clear_mark()
+ let s:subword_motion = ""
+ return ''
+endfunction
+
+function! subwords#repeat(char)
+ if s:subword_motion == ''
+ return a:char
+ endif
+
+ let mot = (s:subword_motion == 'next') != (a:char == ',')
+
+ let s:subword_nosave = 1
+ if mot
+ return "\<Plug>(next-subword)"
+ else
+ return "\<Plug>(prev-subword)"
+ endif
+endfunction