Skip to content

Commit

Permalink
Version 1.40
Browse files Browse the repository at this point in the history
- ENH: Added CountJump#Region#TextObject#Make() to easily define text objects for regions.
- Interface change: Jump functions again return position (and actual, corrected one for a:isToEndOfLine). Though the position is not used for motions, it is necessary for text objects to differentiate between "already at the begin/end position" and "no such position".
  • Loading branch information
Ingo Karkat authored and vim-scripts committed Dec 20, 2010
1 parent 0a0ac1c commit 433018f
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 21 deletions.
18 changes: 14 additions & 4 deletions autoload/CountJump/Region.vim
Expand Up @@ -8,6 +8,12 @@
" Maintainer: Ingo Karkat <ingo@karkat.de>
"
" REVISION DATE REMARKS
" 1.40.008 20-Dec-2010 Jump functions again return position (and
" actual, corrected one for a:isToEndOfLine).
" Though the position is not used for motions, it
" is necessary for text objects to differentiate
" between "already at the begin/end position" and
" "no such position".
" 1.30.007 19-Dec-2010 Shuffling of responsibilities in
" CountJump#JumpFunc():
" CountJump#Region#JumpToRegionEnd() and
Expand Down Expand Up @@ -65,10 +71,14 @@ function! s:DoJump( position, isToEndOfLine )
else
call setpos('.', [0] + a:position + [0])
if a:isToEndOfLine
normal! $
normal! $zv
return getpos('.')[1:2]
else
normal! zv
endif
normal! zv
endif

return a:position
endfunction

function! s:SearchInLineMatching( line, pattern, isMatch )
Expand Down Expand Up @@ -178,7 +188,7 @@ function! CountJump#Region#SearchForRegionEnd( count, pattern, isMatch, step )
endfunction
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)
return s:DoJump(l:position, a:isToEndOfLine)
endfunction

function! CountJump#Region#SearchForNextRegion( count, pattern, isMatch, step, isAcrossRegion )
Expand Down Expand Up @@ -286,7 +296,7 @@ function! CountJump#Region#SearchForNextRegion( count, pattern, isMatch, step, i
endfunction
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)
return s:DoJump(l:position, a:isToEndOfLine)
endfunction

" vim: set sts=4 sw=4 noexpandtab ff=unix fdm=syntax :
1 change: 1 addition & 0 deletions autoload/CountJump/Region/Motion.vim
Expand Up @@ -2,6 +2,7 @@
" lines.
"
" DEPENDENCIES:
" - CountJump.vim, CountJump/Region.vim autoload scripts.
"
" Copyright: (C) 2010 Ingo Karkat
" The VIM LICENSE applies to this script; see ':help copyright'.
Expand Down
121 changes: 121 additions & 0 deletions autoload/CountJump/Region/TextObject.vim
@@ -0,0 +1,121 @@
" TextObject.vim: Create custom text objects via jumps over matching lines.
"
" DEPENDENCIES:
" - CountJump/Region.vim, CountJump/TextObjects.vim autoload scripts.
"
" 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.40.001 20-Dec-2010 file creation

function! s:EscapeForFunctionName( text )
" Convert all non-alphabetical characters to their hex value to create a
" valid function name.
return substitute(a:text, '\A', '\=char2nr(submatch(0))', 'g')
endfunction
function! s:function(name)
return function(substitute(a:name, '^s:', matchstr(expand('<sfile>'), '<SNR>\d\+_\zefunction$'),''))
endfunction
function! CountJump#Region#TextObject#Make( mapArgs, textObjectKey, types, selectionMode, pattern, isMatch )
"*******************************************************************************
"* PURPOSE:
" Define 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.
"
"* ASSUMPTIONS / PRECONDITIONS:
" None.
"
"* EFFECTS / POSTCONDITIONS:
" Creates mappings for operator-pending and visual mode which act upon /
" select the text delimited by the begin and end patterns.
" If there are no <count> regions, a beep is emitted.
"
"* INPUTS:
" a:mapArgs Arguments to the :map command, like '<buffer>' for a
" buffer-local mapping.
" a:textObjectKey Mapping key [sequence] after the mandatory i/a which
" start the mapping for the text object.
" a:types String containing 'i' for inner and 'a' for outer text
" objects.
" a:selectionMode Type of selection used between the patterns:
" 'v' for characterwise, 'V' for linewise, '<CTRL-V>' for
" blockwise. Since regions are defined over full lines,
" this should typically be 'V'.
" 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.
"
"* RETURN VALUES:
" None.
"*******************************************************************************
let l:scope = (a:mapArgs =~# '<buffer>' ? 'b:' : 's:')

if a:types !~# '^[ai]\+$'
throw "ASSERT: Type must consist of 'a' and/or 'i', but is: '" . a:types . "'"
endif

" If only either an inner or outer text object is defined, the generated
" function must include the type, so that it is possible to separately
" define a text object of the other type (via a second invocation of this
" function). If the same region definition is used for both inner and outer
" text objects, no such distinction need to be made.
let l:typePrefix = (strlen(a:types) == 1 ? a:types : '')

let l:functionToBeginName = printf('%sJumpToBegin_%s%s', l:scope, l:typePrefix, s:EscapeForFunctionName(a:textObjectKey))
let l:functionToEndName = printf('%sJumpToEnd_%s%s', l:scope, l:typePrefix, s:EscapeForFunctionName(a:textObjectKey))

let l:regionFunction = "
\ function! %s( count, isInner )\n
\ %s\n
\ let [l:pattern, l:isMatch, l:step, l:isToEndOfLine] = [%s, %d, %d, %d]\n
\ if a:isInner\n
\ return CountJump#Region#JumpToRegionEnd(a:count, l:pattern, l:isMatch, l:step, l:isToEndOfLine)\n
\ else\n
\ let l:isBackward = (l:step < 0)\n
\ let l:regionEndPosition = CountJump#Region#JumpToRegionEnd(a:count, l:pattern, l:isMatch, l:step, 0)\n
\ if l:regionEndPosition == [0, 0] || l:regionEndPosition[0] == (l:isBackward ? 1 : line('$'))\n
\ return l:regionEndPosition\n
\ endif\n
\ execute 'normal!' (l:isBackward ? 'k' : 'j')\n
\ return CountJump#Region#JumpToRegionEnd(1, l:pattern, ! l:isMatch, l:step, l:isToEndOfLine)\n
\ endif\n
\ endfunction"

" The function-to-end starts at the beginning of the text object. For the
" outer text object, this would make moving back into the region and then
" beyond it complex. To instead, we use the knowledge that the
" function-to-begin is executed first, and set the original cursor line
" there, then start the function-to-end at that position. Since this may
" also slightly speed up the search for the inner text object, we use it
" unconditionally.
execute printf(l:regionFunction,
\ l:functionToBeginName,
\ 'let s:originalLineNum = line(".")',
\ string(a:pattern),
\ a:isMatch,
\ -1,
\ 0
\)
execute printf(l:regionFunction,
\ l:functionToEndName,
\ 'execute s:originalLineNum',
\ string(a:pattern),
\ a:isMatch,
\ 1,
\ 1
\)

" For regions, the inner text object must include the text object's
" boundaries = lines.
let l:types = substitute(a:types, 'i', 'I', 'g')
return CountJump#TextObject#MakeWithJumpFunctions(a:mapArgs, a:textObjectKey, l:types, a:selectionMode, s:function(l:functionToBeginName), s:function(l:functionToEndName))
endfunction

" vim: set sts=4 sw=4 noexpandtab ff=unix fdm=syntax :
31 changes: 14 additions & 17 deletions autoload/CountJump/TextObject.vim
Expand Up @@ -9,6 +9,7 @@
" Maintainer: Ingo Karkat <ingo@karkat.de>
"
" REVISION DATE REMARKS
" 1.40.010 20-Dec-2010 Replaced s:Escape() function with string().
" 1.22.009 06-Aug-2010 No more text objects for select mode; as the
" mappings start with a printable character ("a" /
" "i"), no select-mode mapping should be defined.
Expand Down Expand Up @@ -62,10 +63,6 @@
let s:save_cpo = &cpo
set cpo&vim

function! s:Escape( argumentText )
return substitute(a:argumentText, "'", "''", 'g')
endfunction

" Select text delimited by ???.
"ix Select [count] text blocks delimited by ??? without the
" outer delimiters.
Expand Down Expand Up @@ -242,8 +239,12 @@ function! CountJump#TextObject#MakeWithJumpFunctions( mapArgs, textObjectKey, ty
" the complete lines matching the pattern.
" a:JumpToBegin Function which is invoked to jump to the begin of the
" block.
" The function is invoked at the cursor position where the
" text object was requested.
" a:JumpToEnd Function which is invoked to jump to the end of the
" block.
" The function is invoked after the call to a:JumpToBegin,
" with the cursor located at the beginning of the text object.
" The jump functions must take two arguments:
" JumpToBegin( count, isInner )
" JumpToEnd( count, isInner )
Expand Down Expand Up @@ -363,30 +364,26 @@ function! CountJump#TextObject#MakeWithCountSearch( mapArgs, textObjectKey, type
let l:searchFunction = "
\ function! %s( count, isInner )\n
\ if a:isInner\n
\ let l:matchPos = CountJump#CountSearch(a:count, ['%s', '%s'])\n
\ let l:matchPos = CountJump#CountSearch(a:count, [%s, %s])\n
\ if l:matchPos != [0, 0]\n
\ call CountJump#CountSearch(1, ['%s', '%s'])\n
\ call CountJump#CountSearch(1, [%s, %s])\n
\ endif\n
\ return l:matchPos\n
\ else\n
\ return CountJump#CountSearch(a:count, ['%s', '%s'])\n
\ return CountJump#CountSearch(a:count, [%s, %s])\n
\ endif\n
\ endfunction"
"execute printf("function! %s( count, isInner )\nreturn CountJump#CountSearch(a:count, ['%s', 'bcW' . (a:isInner ? 'e' : '')])\nendfunction", l:functionToBeginName, s:Escape(a:patternToBegin))
"execute printf("function! %s( count, isInner )\nif a:isInner\nreturn (CountJump#CountSearch(a:count, ['%s', 'bcW']) ? CountJump#CountSearch(1, ['%s', 'ceW']) : 0)\nelse\nreturn CountJump#CountSearch(a:count, ['%s', 'bcW'])\nendif\nendfunction", l:functionToBeginName, s:Escape(a:patternToBegin), s:Escape(a:patternToBegin), s:Escape(a:patternToBegin))
execute printf(l:searchFunction,
\ l:functionToBeginName,
\ s:Escape(a:patternToBegin), 'bcW',
\ s:Escape(a:patternToBegin), 'ceW',
\ s:Escape(a:patternToBegin), 'bcW'
\ string(a:patternToBegin), string('bcW'),
\ string(a:patternToBegin), string('ceW'),
\ string(a:patternToBegin), string('bcW')
\)
"execute printf("function! %s( count, isInner )\nreturn CountJump#CountSearch(a:count, ['%s', 'cW' . (a:isInner ? '' : 'e')])\nendfunction", l:functionToEndName, s:Escape(a:patternToEnd))
"execute printf("function! %s( count, isInner )\nif a:isInner\nreturn (CountJump#CountSearch(a:count, ['%s', 'ceW']) ? CountJump#CountSearch(1, ['%s', 'bcW']) : 0)\nelse\nreturn CountJump#CountSearch(a:count, ['%s', 'ceW'])\nendif\nendfunction", l:functionToEndName, s:Escape(a:patternToEnd), s:Escape(a:patternToEnd), s:Escape(a:patternToEnd))
execute printf(l:searchFunction,
\ l:functionToEndName,
\ s:Escape(a:patternToEnd), 'ceW',
\ s:Escape(a:patternToEnd), 'bcW',
\ s:Escape(a:patternToEnd), 'eW'
\ string(a:patternToEnd), string('ceW'),
\ string(a:patternToEnd), string('bcW'),
\ string(a:patternToEnd), string('eW')
\)
" Note: For the outer jump to end, a:patternToEnd must not match at the
" current cursor position (no 'c' flag to search()). This allows to handle
Expand Down
17 changes: 17 additions & 0 deletions doc/CountJump.txt
Expand Up @@ -112,6 +112,15 @@ 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 *CountJump-example*

Expand Down Expand Up @@ -185,6 +194,14 @@ IDEAS *CountJump-ideas*
==============================================================================
HISTORY *CountJump-history*

1.40 20-Dec-2010
- ENH: Added CountJump#Region#TextObject#Make() to easily define text objects
for regions.
- Interface change: Jump functions again return position (and actual,
corrected one for a:isToEndOfLine). Though the position is not used for
motions, it is necessary for text objects to differentiate between "already
at the begin/end position" and "no such position".

1.30 20-Dec-2010
- ENH: Added CountJump#Region#Motion#MakeBracketMotion() to easily define
bracket motions for regions.
Expand Down

0 comments on commit 433018f

Please sign in to comment.