Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Version 1.30

- ENH: Added CountJump#Region#Motion#MakeBracketMotion() to easily define bracket motions for regions.
- Interface changes:
  - Jump functions don't necessarily return jump position any more; this special case is only required for text objects.
  - Moved CountJump#Region#Jump() to CountJump#JumpFunc().
  - Added a:isToEndOfLine argument to CountJump#Region#JumpToRegionEnd() and CountJump#Region#JumpToNextRegion(), which is useful for operator-pending and characterwise visual mode mappings; the entire last line will then be operated on / selected.
  - Added a:isMatch argument to CountJump#Region#SearchForRegionEnd(), CountJump#Region#JumpToRegionEnd(), CountJump#Region#SearchForNextRegion(), CountJump#Region#JumpToNextRegion(). This allows definition of regions via non-matches, which can be substantially simpler (and faster to match) than coming up with a "negative" regular expression.
  • Loading branch information...
commit 0a0ac1c80f04683f33a3837d02fa19293c59fbda 1 parent cbc2370
Ingo Karkat authored committed
View
25 README
@@ -77,26 +77,31 @@ Often, a region can be defined as a block of continuous lines that all match a
certain pattern. The following functions aid in implementing movements to the
boundaries of these regions and text objects consisting of the region:
-CountJump#Region#JumpToRegionEnd( count, pattern, step )
+CountJump#Region#JumpToRegionEnd( count, pattern, isMatch, step, isToEndOfLine )
Starting from the current line, search for the position where the count'th
region ends. Use this function to build Funcrefs for forward / backward jumps
that can then be passed to CountJump#TextObject#MakeWithJumpFunctions().
-CountJump#Region#JumpToNextRegion( count, pattern, step, isAcrossRegion )
+CountJump#Region#JumpToNextRegion( count, pattern, isMatch, step, isAcrossRegion, isToEndOfLine )
Starting from the current line, search for the position where the count'th
region begins/ends.
-CountJump#Region#Jump( mode, JumpFunc, ... )
+CountJump#Region#Motion#MakeBracketMotion( mapArgs, keyAfterBracket, inverseKeyAfterBracket, pattern, isMatch, ... )
-Implement a custom motion by jumping to the <count>th occurrence of the passed
-pattern. This function allows to implement jump functions working on text
-regions. These can then be passed to
-CountJump#Motion#MakeBracketMotionWithJumpFunctions().
- function! s:JumpToBeginForward( mode )
- return CountJump#Region#Jump(a:mode, function('CountJump#Region#JumpToNextRegion'), '^\s*#', 1, 0)
- endfunction
+This function sets up mappings starting with [ and ] for movement (with
+optional [count]) relative to the current cursor position, targeting a text
+region defined by contiguous lines that (don't) match a:pattern.
+
+CountJump#Region#TextObject#Make( mapArgs, textObjectKey, types, selectionMode, pattern, isMatch )
+
+Defines a complete set of mappings for inner and/or outer text objects that
+support an optional [count] and select regions of lines which are defined by
+contiguous lines that (don't) match a:pattern.
+The inner text object comprises all lines of the region itself, while the
+outer text object also includes all adjacent lines above and below which do
+not themselves belong to a region.
EXAMPLE
Let's illustrate the usage by developing custom motions and text objects for
View
101 autoload/CountJump.vim
@@ -8,6 +8,22 @@
" Maintainer: Ingo Karkat <ingo@karkat.de>
"
" REVISION DATE REMARKS
+" 1.30.011 19-Dec-2010 Removed return value of jump position from
+" CountJump#CountJump() and CountJump#JumpFunc();
+" it isn't needed, as these functions are
+" typically used directly in motion mappings.
+" CountJump#JumpFunc() now uses cursor position
+" after invoking jump function, and doesn't
+" require a returned position any more. This is
+" only a special case for CountJump#TextObject,
+" and should not be generally required of a jump
+" function. The jump function is now also expected
+" to beep, so removed that here.
+" 1.30.010 18-Dec-2010 Moved CountJump#Region#Jump() here as
+" CountJump#JumpFunc(). It fits here much better
+" because of the similarity to
+" CountJump#CountJump(), and actually has nothing
+" to do with regions.
" 1.20.009 30-Jul-2010 FIX: CountJump#CountJump() with mode "O" didn't
" add original position to jump list. Simplified
" conditional.
@@ -62,8 +78,8 @@ function! CountJump#CountSearch( count, searchArguments )
let l:searchArguments = copy(a:searchArguments)
for l:i in range(1, a:count)
- let l:matchPos = call('searchpos', l:searchArguments)
- if l:matchPos == [0, 0]
+ let l:matchPosition = call('searchpos', l:searchArguments)
+ if l:matchPosition == [0, 0]
if l:i > 1
" (Due to the count,) we've already moved to an intermediate
" match. Undo that to behave like the old vi-compatible
@@ -80,7 +96,7 @@ function! CountJump#CountSearch( count, searchArguments )
" \<Esc>", which only works in normal mode.
execute "normal \<Plug>RingTheBell"
- return l:matchPos
+ return l:matchPosition
endif
if len(l:searchArguments) > 1 && l:i == 1
@@ -97,7 +113,7 @@ function! CountJump#CountSearch( count, searchArguments )
" a match inside a closed fold.
normal! zv
- return l:matchPos
+ return l:matchPosition
endfunction
function! CountJump#CountJump( mode, ... )
"*******************************************************************************
@@ -120,7 +136,7 @@ function! CountJump#CountJump( mode, ... )
" ... Arguments to search().
"
"* RETURN VALUES:
-" List with the line and column position, or [0, 0], like searchpos().
+" None.
"*******************************************************************************
let l:save_view = winsaveview()
@@ -128,12 +144,12 @@ function! CountJump#CountJump( mode, ... )
normal! gv
endif
- let l:matchPos = CountJump#CountSearch(v:count1, a:000)
- if l:matchPos != [0, 0]
+ let l:matchPosition = CountJump#CountSearch(v:count1, a:000)
+ if l:matchPosition != [0, 0]
" Add the original cursor position to the jump list.
call winrestview(l:save_view)
normal! m'
- call setpos('.', [0] + l:matchPos + [0])
+ call setpos('.', [0] + l:matchPosition + [0])
if a:mode ==# 'O'
" Special additional treatment for operator-pending mode with a pattern
@@ -157,8 +173,75 @@ function! CountJump#CountJump( mode, ... )
let &whichwrap = l:save_ww
endif
endif
+endfunction
+function! CountJump#JumpFunc( mode, JumpFunc, ... )
+"*******************************************************************************
+"* PURPOSE:
+" Implement a custom motion by invoking a jump function that is passed the
+" <count> and the optional arguments.
+"
+"* ASSUMPTIONS / PRECONDITIONS:
+" None.
+"
+"* EFFECTS / POSTCONDITIONS:
+" Normal mode: Jumps to the <count>th occurrence.
+" Visual mode: Extends the selection to the <count>th occurrence.
+" If the jump doesn't work, a beep is emitted.
+"
+"* INPUTS:
+" a:mode Mode in which the search is invoked. Either 'n', 'v' or 'o'.
+" With 'O': Special additional treatment for operator-pending mode
+" with a characterwise jump.
+" a:JumpFunc Function which is invoked to jump.
+" The jump function must take at least one argument:
+" a:count Number of matches to jump to.
+" It can take more arguments which must then be passed in here:
+" ... Arguments to the passed a:JumpFunc
+" The jump function should position the cursor to the appropriate position in
+" the current window, and open any folds there. It is expected to beep and
+" keep the cursor at its original position when no appropriate position can be
+" found.
+"
+"* RETURN VALUES:
+" None.
+"*******************************************************************************
+ let l:save_view = winsaveview()
+ let l:originalPosition = getpos('.')
+
+ if a:mode ==# 'v'
+ normal! gv
+ endif
- return l:matchPos
+ call call(a:JumpFunc, [v:count1] + a:000)
+ let l:matchPosition = getpos('.')
+ if l:matchPosition != l:originalPosition
+ " Add the original cursor position to the jump list.
+ call winrestview(l:save_view)
+ normal! m'
+ call setpos('.', l:matchPosition)
+
+ if a:mode ==# 'O'
+ " Special additional treatment for operator-pending mode with a
+ " characterwise jump.
+ " The difference between normal mode, visual and operator-pending
+ " mode is that in the latter, the motion must go _past_ the final
+ " character, so that all characters are selected. This is done by
+ " appending a 'l' motion after the search.
+ "
+ " In operator-pending mode, the 'l' motion only works properly
+ " at the end of the line (i.e. when the moved-over "word" is at
+ " the end of the line) when the 'l' motion is allowed to move
+ " over to the next line. Thus, the 'l' motion is added
+ " temporarily to the global 'whichwrap' setting.
+ " Without this, the motion would leave out the last character in
+ " the line. I've also experimented with temporarily setting
+ " "set virtualedit=onemore", but that didn't work.
+ let l:save_ww = &whichwrap
+ set whichwrap+=l
+ normal! l
+ let &whichwrap = l:save_ww
+ endif
+ endif
endfunction
" vim: set sts=4 sw=4 noexpandtab ff=unix fdm=syntax :
View
8 autoload/CountJump/Motion.vim
@@ -9,6 +9,8 @@
" Maintainer: Ingo Karkat <ingo@karkat.de>
"
" REVISION DATE REMARKS
+" 1.30.006 19-Dec-2010 Clarified interface of jump function arguments;
+" no need to return jump position here.
" 1.22.005 06-Aug-2010 No more motion mappings for select mode; as the
" mappings start with a printable character, no
" select-mode mapping should be defined.
@@ -202,10 +204,8 @@ function! CountJump#Motion#MakeBracketMotionWithJumpFunctions( mapArgs, keyAfter
" a:mode Mode in which the search is invoked. Either 'n', 'v' or 'o'.
" With 'O': Special additional treatment for operator-pending mode
" with a pattern to end.
-" Both funcrefs must return a list [lnum, col], like searchpos(). This should
-" be the jump position (or [0, 0] if a jump wasn't possible).
-" They should position the cursor to the appropriate position in the current
-" window.
+" All funcrefs should position the cursor to the appropriate position in the
+" current window.
" If no jump function is passed, the corresponding mappings are omitted.
" a:isEndJumpToEnd Flag that specifies whether a jump to the end of a block
View
180 autoload/CountJump/Region.vim
@@ -8,6 +8,32 @@
" Maintainer: Ingo Karkat <ingo@karkat.de>
"
" REVISION DATE REMARKS
+" 1.30.007 19-Dec-2010 Shuffling of responsibilities in
+" CountJump#JumpFunc():
+" CountJump#Region#JumpToRegionEnd() and
+" CountJump#Region#JumpToNextRegion() now need to
+" beep themselves if no match is found, but do not
+" return the position any more.
+" Added a:isToEndOfLine argument to
+" CountJump#Region#JumpToRegionEnd() and
+" CountJump#Region#JumpToNextRegion(), which is
+" useful for operator-pending and characterwise
+" visual mode mappings; the entire last line will
+" then be operated on / selected.
+" 1.30.006 18-Dec-2010 Moved CountJump#Region#Jump() to CountJump.vim
+" as CountJump#JumpFunc(). It fits there much
+" better because of the similarity to
+" CountJump#CountJump(), and actually has nothing
+" to do with regions.
+" 1.30.005 18-Dec-2010 ENH: Added a:isMatch argument to
+" CountJump#Region#SearchForRegionEnd(),
+" CountJump#Region#JumpToRegionEnd(),
+" CountJump#Region#SearchForNextRegion(),
+" CountJump#Region#JumpToNextRegion(). This allows
+" definition of regions via non-matches, which can
+" be substantially simpler (and faster to match)
+" than coming up with a "negative" regular
+" expression.
" 1.21.004 03-Aug-2010 FIX: A 2]] jump inside a region (unless last
" line) jumped like a 1]] jump. The search for
" next region must not decrease the iteration
@@ -28,6 +54,23 @@
" separate #JumpTo...() functions.
" 001 21-Jul-2010 file creation
+function! s:DoJump( position, isToEndOfLine )
+ if a:position == [0, 0]
+ " Ring the bell to indicate that no further match exists.
+ "
+ " As long as this mapping does not exist, it causes a beep in both
+ " normal and visual mode. This is easier than the customary "normal!
+ " \<Esc>", which only works in normal mode.
+ execute "normal \<Plug>RingTheBell"
+ else
+ call setpos('.', [0] + a:position + [0])
+ if a:isToEndOfLine
+ normal! $
+ endif
+ normal! zv
+ endif
+endfunction
+
function! s:SearchInLineMatching( line, pattern, isMatch )
"******************************************************************************
"* PURPOSE:
@@ -38,7 +81,7 @@ function! s:SearchInLineMatching( line, pattern, isMatch )
" None.
"* INPUTS:
" a:line Line in the current buffer to search. Can be an invalid one.
-" a:pattern Regular expression to match.
+" a:pattern Regular expression to (not) match.
" a:isMatch Flag whether to match.
"* RETURN VALUES:
" Screen column of the first match, 1 in case of desired non-match, 0 if there
@@ -67,8 +110,8 @@ function! s:SearchForLastLineContinuouslyMatching( startLine, pattern, isMatch,
"* INPUTS:
" a:startLine Line in the current buffer where the search starts. Can be an
" invalid one.
-" a:pattern Regular expression to match.
-" a:isMatch Flag whether to search matching or non-matching lines.
+" a:pattern Regular expression to (not) match.
+" a:isMatch Flag whether to search matching (vs. non-matching) lines.
" a:step Increment to go to next line. Use 1 for forward, -1 for backward
" search.
"* RETURN VALUES:
@@ -86,19 +129,20 @@ function! s:SearchForLastLineContinuouslyMatching( startLine, pattern, isMatch,
return l:foundPosition
endfunction
-function! CountJump#Region#SearchForRegionEnd( count, pattern, step )
+function! CountJump#Region#SearchForRegionEnd( count, pattern, isMatch, step )
"******************************************************************************
"* PURPOSE:
" Starting from the current line, search for the position where the a:count'th
-" region (as defined by contiguous lines that match a:pattern) ends.
+" region (as defined by contiguous lines that (don't) match a:pattern) ends.
"* ASSUMPTIONS / PRECONDITIONS:
" None.
"* EFFECTS / POSTCONDITIONS:
" None.
"* INPUTS:
" a:count Number of regions to cover.
-" a:pattern Regular expression that defines the region, i.e. must match in
-" all lines belonging to it.
+" a:pattern Regular expression that defines the region, i.e. must (not)
+" match in all lines belonging to it.
+" a:isMatch Flag whether to search matching (vs. non-matching) lines.
" a:step Increment to go to next line. Use 1 for forward, -1 for backward
" search.
"* RETURN VALUES:
@@ -109,7 +153,7 @@ function! CountJump#Region#SearchForRegionEnd( count, pattern, step )
let l:line = line('.')
while 1
" Search for the current region's end.
- let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, 1, a:step)
+ let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, a:isMatch, a:step)
if l:line == 0
return [0, 0]
endif
@@ -122,7 +166,7 @@ function! CountJump#Region#SearchForRegionEnd( count, pattern, step )
" Otherwise, search for the next region's start.
let l:line += a:step
- let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, 0, a:step)
+ let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, ! a:isMatch, a:step)
if l:line == 0
return [0, 0]
endif
@@ -132,20 +176,17 @@ function! CountJump#Region#SearchForRegionEnd( count, pattern, step )
return [l:line, l:col]
endfunction
-function! CountJump#Region#JumpToRegionEnd( count, pattern, step )
- let l:pos = CountJump#Region#SearchForRegionEnd(a:count, a:pattern, a:step)
- if l:pos != [0, 0]
- call setpos('.', [0] + l:pos + [0])
- normal! zv
- endif
- return l:pos
+function! CountJump#Region#JumpToRegionEnd( count, pattern, isMatch, step, isToEndOfLine )
+ let l:position = CountJump#Region#SearchForRegionEnd(a:count, a:pattern, a:isMatch, a:step)
+ call s:DoJump(l:position, a:isToEndOfLine)
endfunction
-function! CountJump#Region#SearchForNextRegion( count, pattern, step, isAcrossRegion )
+function! CountJump#Region#SearchForNextRegion( count, pattern, isMatch, step, isAcrossRegion )
"******************************************************************************
"* PURPOSE:
" Starting from the current line, search for the position where the a:count'th
-" region (as defined by contiguous lines that match a:pattern) begins/ends.
+" region (as defined by contiguous lines that (don't) match a:pattern)
+" begins/ends.
" If the current line is inside the border of a region, jumps to the next one.
" If it is actually inside a region, jumps to the current region's border.
" This makes it work like the built-in motions: [[, ]], etc.
@@ -155,8 +196,9 @@ function! CountJump#Region#SearchForNextRegion( count, pattern, step, isAcrossRe
" Moves cursor to match if it exists.
"* INPUTS:
" a:count Number of regions to cover.
-" a:pattern Regular expression that defines the region, i.e. must match in
-" all lines belonging to it.
+" a:pattern Regular expression that defines the region, i.e. must (not)
+" match in all lines belonging to it.
+" a:isMatch Flag whether to search matching (vs. non-matching) lines.
" a:step Increment to go to next line. Use 1 for forward, -1 for backward
" search.
" a:isAcrossRegion Flag whether to search across the region for the last
@@ -171,13 +213,13 @@ function! CountJump#Region#SearchForNextRegion( count, pattern, step, isAcrossRe
let l:line = line('.')
" Check whether we're currently on the border of a region.
- let l:isInRegion = (s:SearchInLineMatching(l:line, a:pattern, 1) != 0)
- let l:isNextInRegion = (s:SearchInLineMatching((l:line + a:step), a:pattern, 1) != 0)
+ let l:isInRegion = (s:SearchInLineMatching(l:line, a:pattern, a:isMatch) != 0)
+ let l:isNextInRegion = (s:SearchInLineMatching((l:line + a:step), a:pattern, a:isMatch) != 0)
"****D echomsg '**** in region:' (l:isInRegion ? 'current' : '') (l:isNextInRegion ? 'next' : '')
if l:isInRegion
if l:isNextInRegion
" We're inside a region; search for the current region's end.
- let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, 1, a:step)
+ let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, a:isMatch, a:step)
if a:isAcrossRegion
if l:c == 1
" We're done already!
@@ -205,7 +247,7 @@ function! CountJump#Region#SearchForNextRegion( count, pattern, step, isAcrossRe
"****D echomsg '**** starting iteration on line' l:line
while ! l:isDone
" Search for the next region's start.
- let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, 0, a:step)
+ let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, ! a:isMatch, a:step)
if l:line == 0
return [0, 0]
endif
@@ -217,13 +259,13 @@ function! CountJump#Region#SearchForNextRegion( count, pattern, step, isAcrossRe
if l:c == 0
if a:isAcrossRegion
" Search for the current region's end.
- let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, 1, a:step)
+ let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, a:isMatch, a:step)
if l:line == 0
return [0, 0]
endif
else
" Check whether another region starts at the current line.
- let l:col = s:SearchInLineMatching(l:line, a:pattern, 1)
+ let l:col = s:SearchInLineMatching(l:line, a:pattern, a:isMatch)
if l:col == 0
return [0, 0]
endif
@@ -233,7 +275,7 @@ function! CountJump#Region#SearchForNextRegion( count, pattern, step, isAcrossRe
endif
" Otherwise, we're not done; skip over the next region.
- let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, 1, a:step)
+ let [l:line, l:col] = s:SearchForLastLineContinuouslyMatching(l:line, a:pattern, a:isMatch, a:step)
if l:line == 0
return [0, 0]
endif
@@ -242,87 +284,9 @@ function! CountJump#Region#SearchForNextRegion( count, pattern, step, isAcrossRe
return [l:line, l:col]
endfunction
-function! CountJump#Region#JumpToNextRegion( count, pattern, step, isAcrossRegion )
- let l:pos = CountJump#Region#SearchForNextRegion(a:count, a:pattern, a:step, a:isAcrossRegion)
- if l:pos != [0, 0]
- call setpos('.', [0] + l:pos + [0])
- normal! zv
- endif
- return l:pos
-endfunction
-
-function! CountJump#Region#Jump( mode, JumpFunc, ... )
-"*******************************************************************************
-"* PURPOSE:
-" Implement a custom motion by jumping to the <count>th occurrence of the
-" passed pattern.
-"
-"* ASSUMPTIONS / PRECONDITIONS:
-" None.
-"
-"* EFFECTS / POSTCONDITIONS:
-" Normal mode: Jumps to the <count>th occurrence.
-" Visual mode: Extends the selection to the <count>th occurrence.
-" If the jump doesn't work, a beep is emitted.
-"
-"* INPUTS:
-" a:mode Mode in which the search is invoked. Either 'n', 'v' or 'o'.
-" With 'O': Special additional treatment for operator-pending mode
-" with a pattern to end.
-" a:JumpFunc Function which is invoked to jump.
-" The jump function must take at least one argument:
-" a:count Number of matches to jump to.
-" It can take more arguments which must then be passed in here:
-" ... Arguments to the passed a:JumpFunc
-"
-"* RETURN VALUES:
-" List with the line and column position, or [0, 0], like searchpos().
-"*******************************************************************************
- let l:save_view = winsaveview()
-
- if a:mode ==# 'v'
- normal! gv
- endif
-
- let l:matchPos = call(a:JumpFunc, [v:count1] + a:000)
- if l:matchPos == [0, 0]
- " Ring the bell to indicate that no match exists.
- "
- " As long as this mapping does not exist, it causes a beep in both
- " normal and visual mode. This is easier than the customary "normal!
- " \<Esc>", which only works in normal mode.
- execute "normal \<Plug>RingTheBell"
- else
- " Add the original cursor position to the jump list.
- call winrestview(l:save_view)
- normal! m'
- call setpos('.', [0] + l:matchPos + [0])
-
- if a:mode ==# 'O'
- " Special additional treatment for operator-pending mode with a pattern
- " to end.
- " The difference between normal mode, visual and operator-pending
- " mode is that in the latter, the motion must go _past_ the final
- " character, so that all characters are selected. This is done by
- " appending a 'l' motion after the search.
- "
- " In operator-pending mode, the 'l' motion only works properly
- " at the end of the line (i.e. when the moved-over "word" is at
- " the end of the line) when the 'l' motion is allowed to move
- " over to the next line. Thus, the 'l' motion is added
- " temporarily to the global 'whichwrap' setting.
- " Without this, the motion would leave out the last character in
- " the line. I've also experimented with temporarily setting
- " "set virtualedit=onemore", but that didn't work.
- let l:save_ww = &whichwrap
- set whichwrap+=l
- normal! l
- let &whichwrap = l:save_ww
- endif
-
- endif
-
- return l:matchPos
+function! CountJump#Region#JumpToNextRegion( count, pattern, isMatch, step, isAcrossRegion, isToEndOfLine )
+ let l:position = CountJump#Region#SearchForNextRegion(a:count, a:pattern, a:isMatch, a:step, a:isAcrossRegion)
+ call s:DoJump(l:position, a:isToEndOfLine)
endfunction
" vim: set sts=4 sw=4 noexpandtab ff=unix fdm=syntax :
View
125 autoload/CountJump/Region/Motion.vim
@@ -0,0 +1,125 @@
+" CountJump#Region#Motion.vim: Create custom motions via jumps over matching
+" lines.
+"
+" DEPENDENCIES:
+"
+" Copyright: (C) 2010 Ingo Karkat
+" The VIM LICENSE applies to this script; see ':help copyright'.
+"
+" Maintainer: Ingo Karkat <ingo@karkat.de>
+"
+" REVISION DATE REMARKS
+" 1.30.002 19-Dec-2010 Added a:isToEndOfLine argument to
+" CountJump#Region#JumpToNextRegion(), to be used
+" in operator-pending and visual modes in order to
+" jump to the end of the matching line (for the ][
+" motion only). In that case, also using special
+" 'O' mode argument for CountJump#JumpFunc() to
+" include the last character, too.
+" 001 18-Dec-2010 file creation
+
+" Move around ???
+"]x, ]] Go to [count] next start of ???.
+"]X, ][ Go to [count] next end of ???.
+"[x, [[ Go to [count] previous start of ???.
+"[X, [] Go to [count] previous end of ???.
+
+function! CountJump#Region#Motion#MakeBracketMotion( mapArgs, keyAfterBracket, inverseKeyAfterBracket, pattern, isMatch, ... )
+"*******************************************************************************
+"* PURPOSE:
+" Define a complete set of mappings for a [x / ]x motion (e.g. like the
+" built-in ]m "Jump to start of next method") that support an optional [count]
+" and jump over regions of lines which are defined by contiguous lines that
+" (don't) match a:pattern.
+" The mappings work in normal mode (jump), visual mode (expand selection) and
+" operator-pending mode (execute operator).
+
+" Normally, it will jump to the column of the first match (typically, that is
+" column 1, always so for non-matches). But for the ]X or ][ mapping, it will
+" include the entire line in operator-pending and visual mode; operating over
+" / selecting the entire region is typically what the user expects.
+" In visual mode, the mode will NOT be changed to linewise, though that, due
+" to the linewise definition of a region, is usually the best mode to use the
+" mappings in. Likewise, an operator will only work from the cursor position,
+" not the entire line the cursor was on. If you want to force linewise mode,
+" either go into linewise visual mode first or try the corresponding text
+" object (if one exists); text objects DO usually switch the selection mode
+" into what's more appropriate for them. (Compare the behavior of the built-in
+" paragraph motion |}| vs. the "a paragraph" text object |ap|.)
+"
+"* ASSUMPTIONS / PRECONDITIONS:
+" None.
+"
+"* EFFECTS / POSTCONDITIONS:
+" Creates mappings for normal, visual and operator-pending mode:
+" Normal mode: Jumps to the <count>th region.
+" Visual mode: Extends the selection to the <count>th region.
+" Operator-pending mode: Applies the operator to the covered text.
+" If there aren't <count> more regions, a beep is emitted.
+"
+"* INPUTS:
+" a:mapArgs Arguments to the :map command, like '<buffer>' for a
+" buffer-local mapping.
+" a:keyAfterBracket Mapping key [sequence] after the mandatory ]/[ which
+" start the mapping for a motion to the beginning of a
+" block.
+" Can be empty; the resulting mappings are then omitted.
+" a:inverseKeyAfterBracket Likewise, but for the motions to the end of a
+" block. Usually the uppercased version of
+" a:keyAfterBracket.
+" Can be empty; the resulting mappings are then
+" omitted.
+" If both a:keyAfterBracket and a:inverseKeyAfterBracket are empty, the
+" default [[ and ]] mappings are overwritten. (Note that this is different
+" from passing ']' and '[', respectively, because the back motions are
+" swapped.)
+" a:pattern Regular expression that defines the region, i.e. must (not)
+" match in all lines belonging to it.
+" a:isMatch Flag whether to search matching (vs. non-matching) lines.
+" a:mapModes Optional string containing 'n', 'o' and/or 'v',
+" representing the modes for which mappings should be
+" created. Defaults to all modes.
+"
+"* RETURN VALUES:
+" None.
+"*******************************************************************************
+ let l:mapModes = split((a:0 ? a:1 : 'nov'), '\zs')
+
+ let l:dataset = [] " List of [ mapping keys, step, isAcrossRegion, isToEndOfLine ]
+ if empty(a:keyAfterBracket) && empty(a:inverseKeyAfterBracket)
+ call add(l:dataset, ['[[', -1, 1, 0])
+ call add(l:dataset, [']]', 1, 0, 0])
+ call add(l:dataset, ['[]', -1, 0, 0])
+ call add(l:dataset, ['][', 1, 1, 1])
+ else
+ if ! empty(a:keyAfterBracket)
+ call add(l:dataset, ['[' . a:keyAfterBracket, -1, 1, 0])
+ call add(l:dataset, [']' . a:keyAfterBracket, 1, 0, 0])
+ endif
+ if ! empty(a:inverseKeyAfterBracket)
+ call add(l:dataset, ['[' . a:inverseKeyAfterBracket, -1, 0, 0])
+ call add(l:dataset, [']' . a:inverseKeyAfterBracket, 1, 1, 1])
+ endif
+ endif
+
+ for l:mode in l:mapModes
+ for l:data in l:dataset
+ let l:useToEndOfLine = (l:mode ==# 'n' ? 0 : l:data[3])
+ execute escape(
+ \ printf("%snoremap <silent> %s %s :<C-U>call CountJump#JumpFunc(%s, 'CountJump#Region#JumpToNextRegion', %s, %d, %d, %d, %d)<CR>",
+ \ (l:mode ==# 'v' ? 'x' : l:mode),
+ \ a:mapArgs,
+ \ l:data[0],
+ \ string(l:mode ==# 'o' && l:useToEndOfLine ? 'O' : l:mode),
+ \ string(a:pattern),
+ \ a:isMatch,
+ \ l:data[1],
+ \ l:data[2],
+ \ l:useToEndOfLine
+ \ ), '|'
+ \)
+ endfor
+ endfor
+endfunction
+
+" vim: set sts=4 sw=4 noexpandtab ff=unix fdm=syntax :
View
51 doc/CountJump.txt
@@ -3,9 +3,9 @@
COUNT JUMP by Ingo Karkat
*CountJump.vim*
description |CountJump-description|
-usage |CountJump-usage|
-example |CountJump-example|
-installation |CountJump-installation|
+usage |CountJump-usage|
+example |CountJump-example|
+installation |CountJump-installation|
limitations |CountJump-limitations|
known problems |CountJump-known-problems|
todo |CountJump-todo|
@@ -35,6 +35,7 @@ text regions that can be defined by continuous lines that match a particular
pattern, e.g. comment blocks that all start with /^\s*#/.
SEE ALSO *
+
The following ftplugins use this plugin:
diff_movement (vimscript #3180): Movement over diff hunks with ]] etc.
@@ -94,27 +95,23 @@ Often, a region can be defined as a block of continuous lines that all match a
certain pattern. The following functions aid in implementing movements to the
boundaries of these regions and text objects consisting of the region:
-CountJump#Region#JumpToRegionEnd( count, pattern, step )
+CountJump#Region#JumpToRegionEnd( count, pattern, isMatch, step, isToEndOfLine )
Starting from the current line, search for the position where the count'th
region ends. Use this function to build Funcrefs for forward / backward jumps
that can then be passed to CountJump#TextObject#MakeWithJumpFunctions().
-CountJump#Region#JumpToNextRegion( count, pattern, step, isAcrossRegion )
+CountJump#Region#JumpToNextRegion( count, pattern, isMatch, step, isAcrossRegion, isToEndOfLine )
Starting from the current line, search for the position where the count'th
region begins/ends.
-CountJump#Region#Jump( mode, JumpFunc, ... )
+CountJump#Region#Motion#MakeBracketMotion( mapArgs, keyAfterBracket, inverseKeyAfterBracket, pattern, isMatch, ... )
+
+This function sets up mappings starting with [ and ] for movement (with
+optional [count]) relative to the current cursor position, targeting a text
+region defined by contiguous lines that (don't) match a:pattern.
-Implement a custom motion by jumping to the <count>th occurrence of the passed
-pattern. This function allows to implement jump functions working on text
-regions. These can then be passed to
-CountJump#Motion#MakeBracketMotionWithJumpFunctions(). >
- function! s:JumpToBeginForward( mode )
- return CountJump#Region#Jump(a:mode, function('CountJump#Region#JumpToNextRegion'), '^\s*#', 1, 0)
- endfunction
-<
==============================================================================
EXAMPLE *CountJump-example*
@@ -148,13 +145,13 @@ above calls in a ~/.vim/ftplugin/pascal_movement.vim script and are done.
==============================================================================
INSTALLATION *CountJump-installation*
-This script is packaged as a|vimball|. If you have the "gunzip" decompressor
+This script is packaged as a |vimball|. If you have the "gunzip" decompressor
in your PATH, simply edit the *.vba.gz package in Vim; otherwise, decompress
the archive first, e.g. using WinZip. Inside Vim, install by sourcing the
-vimball or via the|:UseVimball|command. >
+vimball or via the |:UseVimball| command. >
vim CountJump.vba.gz
:so %
-To uninstall, use the|:RmVimball|command.
+To uninstall, use the |:RmVimball| command.
DEPENDENCIES *CountJump-dependencies*
@@ -188,6 +185,24 @@ IDEAS *CountJump-ideas*
==============================================================================
HISTORY *CountJump-history*
+1.30 20-Dec-2010
+- ENH: Added CountJump#Region#Motion#MakeBracketMotion() to easily define
+ bracket motions for regions.
+- Interface changes:
+ - Jump functions don't necessarily return jump position any more; this
+ special case is only required for text objects.
+ - Moved CountJump#Region#Jump() to CountJump#JumpFunc().
+ - Added a:isToEndOfLine argument to CountJump#Region#JumpToRegionEnd() and
+ CountJump#Region#JumpToNextRegion(), which is useful for operator-pending
+ and characterwise visual mode mappings; the entire last line will then be
+ operated on / selected.
+ - Added a:isMatch argument to CountJump#Region#SearchForRegionEnd(),
+ CountJump#Region#JumpToRegionEnd(),
+ CountJump#Region#SearchForNextRegion(),
+ CountJump#Region#JumpToNextRegion(). This allows definition of regions via
+ non-matches, which can be substantially simpler (and faster to match) than
+ coming up with a "negative" regular expression.
+
1.22 06-Aug-2010
- No more motion mappings and text objects for select mode; as the mappings
start with a printable character, no select-mode mapping should be defined.
@@ -236,7 +251,7 @@ First published version.
Started development.
==============================================================================
-Copyright: (C) 2009-2010 by Ingo Karkat
+Copyright: (C) 2009-2010 Ingo Karkat
The VIM LICENSE applies to this script; see|copyright|.
Maintainer: Ingo Karkat <ingo@karkat.de>
Please sign in to comment.
Something went wrong with that request. Please try again.