aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2022-08-04 13:16:12 -0600
committerJosh Rahm <rahm@google.com>2022-08-04 13:16:12 -0600
commit3340b11176d467961ae8426091d53c6ad1a01d2c (patch)
tree49b7d8772081265088e69e7d7d50b747769418b0
parent6f7c03150b25c2895c852e5068d8c890246ba231 (diff)
downloadfieldmarshal.vim-3340b11176d467961ae8426091d53c6ad1a01d2c.tar.gz
fieldmarshal.vim-3340b11176d467961ae8426091d53c6ad1a01d2c.tar.bz2
fieldmarshal.vim-3340b11176d467961ae8426091d53c6ad1a01d2c.zip
Add Fall.vim
-rw-r--r--autoload/fall.vim80
-rw-r--r--plugin/fall.vim26
2 files changed, 106 insertions, 0 deletions
diff --git a/autoload/fall.vim b/autoload/fall.vim
new file mode 100644
index 0000000..493ded3
--- /dev/null
+++ b/autoload/fall.vim
@@ -0,0 +1,80 @@
+" 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!
diff --git a/plugin/fall.vim b/plugin/fall.vim
new file mode 100644
index 0000000..3fba6d5
--- /dev/null
+++ b/plugin/fall.vim
@@ -0,0 +1,26 @@
+" Fall through whitespace.
+noremap <expr> <silent> <leader>k fall#fall('k', '^\s*$')
+noremap <expr> <silent> <leader>j fall#fall('j', '^\s*$')
+
+" Text object to fall through whitepacea
+onoremap <silent> <leader>k :<c-u>exec "normal! V" . fall#fall('k', '^\s*$')<cr>
+onoremap <silent> <leader>j :<c-u>exec "normal! V" . fall#fall('j', '^\s*$')<cr>
+
+" Text object to fall though whitespace, but exclude the last line.
+onoremap <silent> i<leader>k :<c-u>exec "normal! V" . fall#fall('k', '^\s*$') . "j"<cr>
+onoremap <silent> i<leader>j :<c-u>exec "normal! V" . fall#fall('j', '^\s*$') . "k"<cr>
+
+" Text object to fall though whitespace, but exclude the last line.
+onoremap <silent> i<leader>k :<c-u>exec "normal! V" . fall#fall('k', '^\s*$') . "j"<cr>
+onoremap <silent> i<leader>j :<c-u>exec "normal! V" . fall#fall('j', '^\s*$') . "k"<cr>
+
+" Text objects to describe "falling" down, and then "falling" up. Equivalent to
+" V<leader>kO<leader>j
+onoremap <silent> ai :<c-u>exec "normal! V"
+ \ . fall#fall('j', '^\s*$')
+ \ . "O"
+ \ . fall#fall('k', '^\s*$') <cr>
+onoremap <silent> ii :<c-u>exec "normal! V"
+ \ . fall#fall('j', '^\s*$')
+ \ . "kO"
+ \ . fall#fall('k', '^\s*$') . 'j' <cr>