diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..926ccaa --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +doc/tags diff --git a/doc/tags b/doc/tags deleted file mode 100644 index 43bf136..0000000 --- a/doc/tags +++ /dev/null @@ -1,27 +0,0 @@ -aC textobj-word-column.txt /*aC* -ac textobj-word-column.txt /*ac* -caC textobj-word-column.txt /*caC* -cac textobj-word-column.txt /*cac* -ciC textobj-word-column.txt /*ciC* -cic textobj-word-column.txt /*cic* -daC textobj-word-column.txt /*daC* -dac textobj-word-column.txt /*dac* -diC textobj-word-column.txt /*diC* -dic textobj-word-column.txt /*dic* -iC textobj-word-column.txt /*iC* -ic textobj-word-column.txt /*ic* -textobj-word-column-changelog textobj-word-column.txt /*textobj-word-column-changelog* -textobj-word-column-contributing textobj-word-column.txt /*textobj-word-column-contributing* -textobj-word-column-credits textobj-word-column.txt /*textobj-word-column-credits* -textobj-word-column-examples textobj-word-column.txt /*textobj-word-column-examples* -textobj-word-column-intro textobj-word-column.txt /*textobj-word-column-intro* -textobj-word-column-mappings textobj-word-column.txt /*textobj-word-column-mappings* -textobj-word-column.txt textobj-word-column.txt /*textobj-word-column.txt* -vaC textobj-word-column.txt /*vaC* -vac textobj-word-column.txt /*vac* -viC textobj-word-column.txt /*viC* -vic textobj-word-column.txt /*vic* -yaC textobj-word-column.txt /*yaC* -yac textobj-word-column.txt /*yac* -yiC textobj-word-column.txt /*yiC* -yic textobj-word-column.txt /*yic* diff --git a/doc/textobj-word-column.txt b/doc/textobj-word-column.txt index 4c79c64..ab9bab1 100644 --- a/doc/textobj-word-column.txt +++ b/doc/textobj-word-column.txt @@ -75,4 +75,29 @@ Git repository: https://github.com/coderifous/textobj-word-column.vim =============================================================================== CHANGELOG *textobj-word-column-changelog* -First Public Release: 2012/06/18 +2012/06/18: First Public Release. + +2012/06/23: Added smart-column-boundaries: + + Smart boundaries do a better job of figuring out where the visual block + should start and stop for columns with variable length words, and are + smarter about when to do when whitespace is in the mix. + +> + * Cursor position | vic Without Smart Boundaries | vic With Smart Boundaries + ------------------+------------------------------+--------------------------- + + ab*c omg |abc| omg |abc | omg + abcdef omg |abc|def omg |abcdef| omg + abc omg |abc| omg |abc | omg + + abc * omg abc| |omg |abc | omg + abcdef omg abc|def |omg |abcdef| omg + abc omg abc| |omg |abc | omg + + abc *omg abc| |omg abc | |omg + abcdef omg abc|def |omg abcdef| |omg + abc omg abc| |omg abc | |omg +< + +2012/08/05: Bug fix: Switched recursive function with iteration. diff --git a/plugin/textobj/word-column.vim b/plugin/textobj/word-column.vim old mode 100644 new mode 100755 index 1d95939..5538314 --- a/plugin/textobj/word-column.vim +++ b/plugin/textobj/word-column.vim @@ -3,60 +3,109 @@ if (exists("g:loaded_textobj_word_column")) endif function! TextObjWordBasedColumn(textobj) - let cursor_col = col(".") + let cursor_col = virtcol(".") exec "silent normal! v" . a:textobj . "\" - let start_col = col("'<") - let stop_col = col("'>") - let line_num = line(".") - let indent_level = s:indent_levell(".") - let start_line = s:find_boundary_row(line_num, start_col, indent_level, -1) - let stop_line = s:find_boundary_row(line_num, start_col, indent_level, 1) + let start_col = virtcol("'<") + let stop_col = virtcol("'>") + let line_num = line(".") + let indent_level = s:indent_level(".") + let start_line = s:find_boundary_row(line_num, col("'<"), start_col, indent_level, -1) + let stop_line = s:find_boundary_row(line_num, col("'<"), start_col, indent_level, 1) + let whitespace_only = s:whitespace_column_wanted(start_line, stop_line, cursor_col) + if (exists("g:textobj_word_column_no_smart_boundary_cols")) let col_bounds = [start_col, stop_col] else - let col_bounds = s:find_smart_boundary_cols(start_line, stop_line, cursor_col, a:textobj) + let col_bounds = s:find_smart_boundary_cols(start_line, stop_line, cursor_col, a:textobj, whitespace_only) endif - exec "keepjumps silent normal!" . start_line . "gg" . col_bounds[0] . "|" stop_line . "gg" . col_bounds[1] . "|" + + exec "keepjumps silent normal!" . start_line . "gg" . col_bounds[0] . "|" . stop_line . "gg" . col_bounds[1] . "|" endfunction -function! s:find_smart_boundary_cols(start_line, stop_line, cursor_col, textobj) +function! s:find_smart_boundary_cols(start_line, stop_line, cursor_col, textobj, whitespace_only) let col_bounds = [] let index = a:start_line + if a:whitespace_only + let word_start = "" + let s:col_bounds_fn = function("s:col_bounds_min") + else + let word_start = "lb" + let s:col_bounds_fn = function("s:col_bounds_max") + endif while index <= a:stop_line - exec "keepjumps silent normal!" index . "gg" . a:cursor_col . "|v" . a:textobj . "\" - let start_col = col("'<") - let stop_col = col("'>") + exec "keepjumps silent normal!" index . "gg" . a:cursor_col . "|" . word_start . "v" . a:textobj . "\" + let start_col = virtcol("'<") + let stop_col = virtcol("'>") + let col_bounds = s:col_bounds_fn(start_col, stop_col, col_bounds) + let index = index + 1 + endwhile - if index == a:start_line - let col_bounds = [start_col, stop_col] - else - if start_col < col_bounds[0] - let col_bounds[0] = start_col - endif - if stop_col > col_bounds[1] - let col_bounds[1] = stop_col - endif - endif + return col_bounds +endfunction + +function! s:col_bounds_max(start_col, stop_col, col_bounds) + if a:col_bounds == [] + return [a:start_col, a:stop_col] + endif + if a:start_col < a:col_bounds[0] + let a:col_bounds[0] = a:start_col + endif + if a:stop_col > a:col_bounds[1] + let a:col_bounds[1] = a:stop_col + endif + return a:col_bounds +endfunction +function! s:col_bounds_min(start_col, stop_col, col_bounds) + if a:col_bounds == [] + return [a:start_col, a:stop_col] + endif + if a:start_col > a:col_bounds[0] + let a:col_bounds[0] = a:start_col + endif + if a:stop_col < a:col_bounds[1] + let a:col_bounds[1] = a:stop_col + endif + return a:col_bounds +endfunction + +function! s:whitespace_column_wanted(start_line, stop_line, cursor_col) + let index = a:start_line + let expanded_tabs = repeat(" ", &tabstop) + while index <= a:stop_line + let line = substitute(getline(index), "\t", expanded_tabs, "g") + let char = line[a:cursor_col - 1] + if char != " " && char != "\t" + return 0 + end let index = index + 1 endwhile - - return col_bounds + return 1 endfunction -function! s:find_boundary_row(line_num, start_col, indent_level, step) - let non_blank = getline(a:line_num + a:step) =~ "[^ \t]" - let same_indent = s:indent_levell(a:line_num + a:step) == a:indent_level - let is_not_comment = ! s:is_comment(a:line_num + a:step, a:start_col) - if same_indent && non_blank && is_not_comment - return s:find_boundary_row(a:line_num + a:step, a:start_col, a:indent_level, a:step) - else - return a:line_num +function! s:find_boundary_row(start_line, start_col, start_vcol, indent_level, step) + let current_line = a:start_line + let max_boundary = 0 + if a:step == 1 + let max_boundary = line("$") endif + while current_line != max_boundary + let next_line = current_line + a:step + let non_blank = getline(next_line) =~ "[^ \t]" + let same_indent = s:indent_level(next_line) == a:indent_level + let has_width = getline(next_line) =~ '\%'.a:start_vcol.'v' + let is_not_comment = ! s:is_comment(next_line, a:start_col) + if same_indent && non_blank && has_width && is_not_comment + let current_line = next_line + else + return current_line + endif + endwhile + return max_boundary endfunction -function! s:indent_levell(line_num) +function! s:indent_level(line_num) let line = getline(a:line_num) return match(line, "[^ \t]") endfunction @@ -66,11 +115,10 @@ function! s:is_comment(line_num, column) endfunction if (!exists("g:skip_default_textobj_word_column_mappings")) - nnoremap vac :call TextObjWordBasedColumn("aw") - nnoremap vaC :call TextObjWordBasedColumn("aW") - nnoremap vic :call TextObjWordBasedColumn("iw") - nnoremap viC :call TextObjWordBasedColumn("iW") - + xnoremap ac :call TextObjWordBasedColumn("aw") + xnoremap aC :call TextObjWordBasedColumn("aW") + xnoremap ic :call TextObjWordBasedColumn("iw") + xnoremap iC :call TextObjWordBasedColumn("iW") onoremap ac :call TextObjWordBasedColumn("aw") onoremap aC :call TextObjWordBasedColumn("aW") onoremap ic :call TextObjWordBasedColumn("iw")