aboutsummaryrefslogtreecommitdiff
path: root/autoload/fall.vim
blob: ac54ba0d45d0aaf87d9675d0afe4e3db6364ff96 (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
" Falling motions for Vim. "Falling" means moving the cursor down until it hits
" text that doesn't match a pattern.

" Returns an expression to be used in normal mode that results in the falling
" motion. The semantics are as follows:
"
" The motion moves in the direction given by a:dir (which must be 'j' or 'k').
" The motion moves while the character under the cursor does not match the
" pattern, then it moves while the character under the cursor matches the
" pattern stopping when the character under the cursor does not match the
" pattern once again.
"
" ex.
"
" fall#fall('j', '^\s*$')
"
" for
"
" | t⌷is is some text
" | this is some other text
" |
" |
" | this is some bottom text
" | this is some other bottom text
"
" will return an expression to update the cursor position to:
"
" | this is some text
" | this is some other text
" |
" |
" | t⌷is is some bottom text
" | this is some other bottom text
"
" This works pretty well for navigating around languages that use indentation
" and lack braces for bodies, i.e. vimscript, ruby. Less well for python, but
" still okay.
function! fall#fall(dir, pattern) abort
  let i = 0
  let n = 0

  if a:dir == 'j'
    let delta = 1
  else
    let delta = -1
  endif

  let line = line('.')
  let column = col('.')
  let c = v:count
  if c == 0
    let c = 1
  endif

  while i < c
    let match = matchstr(getline(line), '\%' . column . 'c.')

    while ! (match =~ a:pattern)
      let n += 1
      let line += delta
      if line <= 0 || line >= line('$')
        return "m'" . n . a:dir
      endif
      let match = matchstr(getline(line), '\%' . column . 'c.')
    endwhile

    while (match =~ a:pattern)
      let n += 1
      let line += delta
      if line <= 0 || line >= line('$')
        return "m'" . n . a:dir
      endif
      let match = matchstr(getline(line), '\%' . column . 'c.')
    endwhile

    let i += 1
  endwhile

  return "m'" . n . a:dir
endfunction

function! fall#visual_same_character(dir)
  let start_line = line(".")
  let line = start_line
  let column = col(".")
  let char_to_match = matchstr(getline(line), '\%' . column . 'c.')

  let expr = ""

  if a:dir =~ 'k'
    while line > 1
      let line -= 1
      if matchstr(getline(line), '\%' . column . 'c.') != char_to_match
        break
      endif
      let expr .= 'k'
    endwhile
  endif

  if a:dir == 'jk'
    let expr .= 'o'
    let line = start_line
  endif

  if a:dir =~ 'j'
    while line <= line("$")
      let line += 1
      if matchstr(getline(line), '\%' . column . 'c.') != char_to_match
        break
      endif
      let expr .= 'j'
    endwhile
  endif

  return expr
endfunction

function! fall#visual_vertical_word(dir, def_class)
  let start_line = line(".")
  let line = start_line
  let column = col(".")

  let start_char = matchstr(getline(line), '\%' . column . 'c.')
  if (start_char =~# '\s')
    let class = '\s'
  elseif (start_char =~# a:def_class)
    let class = a:def_class
  else
    return ""
  endif

  let expr = ""

  if a:dir =~ 'k'
    while line > 1
      let line -= 1
      if ! (matchstr(getline(line), '\%' . column . 'c.') =~# class)
        break
      endif
      let expr .= 'k'
    endwhile
  endif

  if a:dir == 'jk'
    let expr .= 'o'
    let line = start_line
  endif

  if a:dir =~ 'j'
    while line <= line("$")
      let line += 1
      if ! (matchstr(getline(line), '\%' . column . 'c.') =~# class)
        break
      endif
      let expr .= 'j'
    endwhile
  endif

  return expr
endfunction