From 39d71ddfd36057f8028d19e273432cb19894d782 Mon Sep 17 00:00:00 2001 From: Dhruva Sagar Date: Tue, 19 Mar 2013 09:25:30 +0530 Subject: [PATCH] Releasing v2.0 - Moved relevant code to autoload. - Added markers for folding. - Updated README.md - Updated doc/text-mode.txt --- README.md | 66 ++++++++++----- autoload/tablemode.vim | 180 +++++++++++++++++++++++++++++++++++++++++ doc/table-mode.txt | 4 +- plugin/table-mode.vim | 169 +++++++------------------------------- 4 files changed, 260 insertions(+), 159 deletions(-) create mode 100644 autoload/tablemode.vim diff --git a/README.md b/README.md index 84010d6..54d8dcb 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,18 @@ An awesome automatic table creator & formatter allowing one to create neat tables as you type. -### Change Log -#### version 1.1 : +## Change Log +### Version 2.0 : +* Moved bulk of code to autoload for vimscript optimisation. + +### version 1.1 : * Added Tableize command and mapping to convert existing content into a table. -#### version 1.0 : +### version 1.0 : * First stable release, create tables as you type. -# Installation +## Getting Started +### Installation There are 2 ways to do this @@ -25,33 +29,57 @@ $ git submodule add git@github.com:dhruvasagar/vim-table-mode.git bundle/table-m 2. Copy table-mode.vim into ~/.vim/plugin/ (Unix) or vimfiles/plugin/ (Windows) as with other plugins. -# Requirements +### Requirements Depends on Tabular. Make sure Tabular is installed and loaded into your runtime to ensure this works. -# Usage +### Usage -By default the table column separator is '|' (it can be changed). As soon as -you type it on a new line (ignores indentation) the script gets to work on -creating the table around it. As you type and define more columns, the table is -completed, formatted and aligned automatically. +- On the fly table creation : -Since this could lead to unwanted behavior I have disabled table mode by -default. You would have to use `:TableModeToggle` command or the table mode -toggle mapping, which is `tm` by default to toggle the table mode or -you can directly use `:TableModeEnable` and `:TableModeDisable` to enable or -disable the table mode. This is on a per buffer basis and so it does not cause -any unusual behavior unless enabled explicitly. Please read `:h table-mode` -for further information. + By default the table column separator is '|' (it can be changed). As soon as + you type it on a new line (ignores indentation) the script gets to work on + creating a table around it. As you type and define more columns, the table + is completed, formatted and aligned automatically on the fly. -Demo: + Since this could lead to unwanted behavior I have disabled table mode by + default. You would have to use `:TableModeToggle` command or the table mode + toggle mapping, which is `tm` by default to toggle the table mode or + you can directly use `:TableModeEnable` and `:TableModeDisable` to enable or + disable the table mode. This is on a per buffer basis and so it does not + cause any unusual behavior unless enabled explicitly. Please read `:h + table-mode` for further information. +- Format existing content into a table : + + Table Mode wouldn't justify it's name if it didn't allow formatting + existing content into a table. And it does as promised. Like table creation + on the fly as you type, formatting existing content into a table is equally + simple. You can visually select multiple lines and call `:Tableize` on it, or + alternatively use the mapping `T` (this is configurable). `:Tableize` + accepts a range and so you can also call it by giving lines manually like + `:line1,line2Tableize`, but this is not that intuitive. You can also use + the mapping `T` with a `[count]` to apply it to the next `[count]` + lines in usual vim style. + +### Demo: -# Credits +## Contributing +### Reporting an Issue : +- Use Github + Issue Tracker + +### Contributing to code : +- Fork it. +- Commit your changes and give your commit message some love. +- Push to your fork on github. +- Open a Pull Request. + +## Credit I must thank Tim Pope for inspiration. The initial concept was created by him named cucumbertables.vim. diff --git a/autoload/tablemode.vim b/autoload/tablemode.vim new file mode 100644 index 0000000..110323f --- /dev/null +++ b/autoload/tablemode.vim @@ -0,0 +1,180 @@ +" ============================================================================= +" File: autoload/tablemode.vim +" Description: Table mode for vim for creating neat tables. +" Author: Dhruva Sagar +" License: MIT (http://www.opensource.org/licenses/MIT) +" Website: http://github.com/dhruvasagar/vim-table-mode +" Version: 2.0 +" Note: This plugin was heavily inspired by the 'CucumberTables.vim' +" (https://gist.github.com/tpope/287147) plugin by Tim Pope and +" uses a small amount of code from it. +" +" Copyright Notice: +" Permission is hereby granted to use and distribute this code, +" with or without modifications, provided that this copyright +" notice is copied with it. Like anything else that's free, +" taglist.vim is provided *as is* and comes with no warranty of +" any kind, either expressed or implied. In no event will the +" copyright holder be liable for any damamges resulting from the +" use of this software. +" ============================================================================= + +" Private Functions {{{1 + +function! s:SetBufferOptDefault(opt, val) "{{{2 + if !exists('b:' . a:opt) + let b:{a:opt} = a:val + endif +endfunction +" }}}2 + +" s:Strlen(text) For counting multibyte characters accurately {{{2 +" See :h strlen() for more details +function! s:Strlen(text) + return strlen(substitute(a:text, '.', 'x', 'g')) +endfunction +" }}}2 + +function! s:CountSeparator(line, separator) "{{{2 + return s:Strlen(substitute(getline(a:line), '[^' . a:separator . ']', '', 'g')) +endfunction +" }}}2 + +function! s:UpdateLineBorder(line) "{{{2 + let cline = a:line + let hf = '^\s*' . g:table_mode_corner . '[' . g:table_mode_corner . ' ' . g:table_mode_fillchar . ']*' . g:table_mode_corner . '\?\s*$' + let curr_line_count = s:CountSeparator(cline, g:table_mode_separator) + + if getline(cline-1) =~# hf + let prev_line_count = s:CountSeparator(cline-1, g:table_mode_corner) + if curr_line_count > prev_line_count + exec 'normal! kA' . repeat(g:table_mode_corner, curr_line_count - prev_line_count) . "\j" + endif + else + call append(cline-1, repeat(g:table_mode_corner, curr_line_count)) + let cline = a:line + 1 + endif + + if getline(cline+1) =~# hf + let next_line_count = s:CountSeparator(cline+1, g:table_mode_corner) + if curr_line_count > next_line_count + exec 'normal! jA' . repeat(g:table_mode_corner, curr_line_count - next_line_count) . "\k" + end + else + call append(cline, repeat(g:table_mode_corner, curr_line_count)) + endif +endfunction +" }}}2 + +function! s:FillTableBorder() "{{{2 + let current_col = col('.') + let current_line = line('.') + execute 'silent! %s/' . g:table_mode_corner . ' \zs\([' . g:table_mode_fillchar . ' ]*\)\ze ' . g:table_mode_corner . '/\=repeat("' . g:table_mode_fillchar . '", s:Strlen(submatch(0)))/g' + call cursor(current_line, current_col) +endfunction +" }}}2 + +function! s:Tableizeline(line) "{{{2 + if exists(':Tabularize') + call s:ConvertDelimiterToSeparator(a:line) + call s:UpdateLineBorder(a:line) + exec 'Tabularize/[' . g:table_mode_separator . g:table_mode_corner . ']/l1' + endif +endfunction +" }}}2 + +function! s:ConvertDelimiterToSeparator(line) "{{{2 + execute 'silent! ' . a:line . 's/^\s*\zs\ze.\|' . g:table_mode_delimiter . '\|$/' . g:table_mode_separator . '/g' +endfunction +" }}}2 + +function! s:IsTableModeActive() "{{{2 + if g:table_mode_always_active | return 1 | endif + + call s:SetBufferOptDefault('table_mode_active', 0) + return b:table_mode_active +endfunction +" }}}2 + +function! s:Tableize() "{{{2 + if s:IsTableModeActive() && exists(':Tabularize') && getline('.') =~# ('^\s*' . g:table_mode_separator) + let column = s:Strlen(substitute(getline('.')[0:col('.')], '[^' . g:table_mode_separator . ']', '', 'g')) + let position = s:Strlen(matchstr(getline('.')[0:col('.')], '.*' . g:table_mode_separator . '\s*\zs.*')) + if g:table_mode_border | call s:UpdateLineBorder(line('.')) | endif + exec 'Tabularize/[' . g:table_mode_separator . g:table_mode_corner . ']/l1' + if g:table_mode_border | call s:FillTableBorder() | endif + normal! 0 + call search(repeat('[^' . g:table_mode_separator . ']*' . g:table_mode_separator, column) . '\s\{-\}' . repeat('.', position), 'ce', line('.')) + endif +endfunction +" }}}2 + +function! s:TableModeSeparatorMap() "{{{2 + if g:table_mode_separator ==# '|' + let table_mode_separator_map = '' + else + let table_mode_separator_map = g:table_mode_separator + endif + return table_mode_separator_map +endfunction +" }}}2 + +function! s:ToggleMapping() "{{{2 + if exists('b:table_mode_active') && b:table_mode_active + exec "inoremap " . s:TableModeSeparatorMap() . ' ' . + \ s:TableModeSeparatorMap() . ":call Tableize()a" + else + exec "iunmap " . s:TableModeSeparatorMap() + endif +endfunction +" }}}2 + +function! s:SetActive(bool) "{{{2 + let b:table_mode_active = a:bool + call s:ToggleMapping() +endfunction +" }}}2 + +" }}}1 + +" Public API {{{1 + +function! tablemode#TableModeEnable() "{{{2 + call s:SetActive(1) +endfunction +" }}}2 + +function! tablemode#TableModeDisable() "{{{2 + call s:SetActive(0) +endfunction +" }}}2 + +function! tablemode#TableModeToggle() "{{{2 + if g:table_mode_always_active + return 1 + endif + + call s:SetBufferOptDefault('table_mode_active', 0) + call s:SetActive(!b:table_mode_active) +endfunction +" }}}2 + +function! tablemode#TableizeRange() range "{{{2 + call s:Tableizeline(a:firstline) + undojoin + " The first one causes 2 extra lines for top & bottom border while the + " following lines cause only 1 for the bottom border. + let lnum = a:firstline+3 + while lnum <= (a:firstline + (a:lastline - a:firstline+1)*2) + call s:Tableizeline(lnum) + undojoin + let lnum = lnum + 2 + endwhile + call s:FillTableBorder() +endfunction +" }}}2 + +" }}}1 + +" ModeLine {{{ +" vim:fdm=marker diff --git a/doc/table-mode.txt b/doc/table-mode.txt index 858c2e2..841dbbc 100644 --- a/doc/table-mode.txt +++ b/doc/table-mode.txt @@ -1,7 +1,7 @@ -*table-mode.txt* Table Mode for easy table formatting. v1.0 +*table-mode.txt* Table Mode for easy table formatting. v2.0 =============================================================================== Table Mode, THE AWESOME AUTOMATIC TABLE CREATOR & FORMATTER - VERSION 1.1 + VERSION 2.0 Author: Dhruva Sagar License: MIT diff --git a/plugin/table-mode.vim b/plugin/table-mode.vim index dfebf3e..751863d 100644 --- a/plugin/table-mode.vim +++ b/plugin/table-mode.vim @@ -1,23 +1,39 @@ " ============================================================================= -" File: table-mode.vim +" File: plugin/table-mode.vim " Description: Table mode for vim for creating neat tables. " Author: Dhruva Sagar " License: MIT (http://www.opensource.org/licenses/MIT) -" Notes: This was inspired by Tim Pope's cucumbertables.vim -" (https://gist.github.com/tpope/287147) +" Website: http://github.com/dhruvasagar/vim-table-mode +" Version: 2.0 +" Note: This plugin was heavily inspired by the 'CucumberTables.vim' +" (https://gist.github.com/tpope/287147) plugin by Tim Pope and +" uses a small amount of code from it. +" +" Copyright Notice: +" Permission is hereby granted to use and distribute this code, +" with or without modifications, provided that this copyright +" notice is copied with it. Like anything else that's free, +" taglist.vim is provided *as is* and comes with no warranty of +" any kind, either expressed or implied. In no event will the +" copyright holder be liable for any damamges resulting from the +" use of this software. " ============================================================================= +" Finish if already loaded {{{1 if exists('g:table_mode_loaded') finish endif let g:table_mode_loaded = 1 +"}}}1 -function! s:SetGlobalOptDefault(opt, val) +function! s:SetGlobalOptDefault(opt, val) "{{{1 if !exists('g:' . a:opt) let g:{a:opt} = a:val endif endfunction +" }}}1 +" Set Global Defaults {{{1 call s:SetGlobalOptDefault('table_mode_border', 1) call s:SetGlobalOptDefault('table_mode_corner', '+') call s:SetGlobalOptDefault('table_mode_separator', '|') @@ -26,144 +42,21 @@ call s:SetGlobalOptDefault('table_mode_toggle_map', 'tm') call s:SetGlobalOptDefault('table_mode_always_active', 0) call s:SetGlobalOptDefault('table_mode_delimiter', ',') call s:SetGlobalOptDefault('table_mode_tableize_map', 'T') +"}}}1 -function! s:SetBufferOptDefault(opt, val) - if !exists('b:' . a:opt) - let b:{a:opt} = a:val - endif -endfunction - -if g:table_mode_separator ==# '|' - let s:table_mode_separator_map = '' -else - let s:table_mode_separator_map = g:table_mode_separator -endif - -function! s:error(str) - echohl ErrorMsg - echomsg a:sr - echohl None - let v:errmsg = a:str -endfunction - -" For counting multibyte characters accurately, see :h strlen() for more -" details -function! s:strlen(text) - return strlen(substitute(a:text, '.', 'x', 'g')) -endfunction - -function! s:CountSeparator(line, separator) - return s:strlen(substitute(getline(a:line), '[^' . a:separator . ']', '', 'g')) -endfunction - -function! s:UpdateLineBorder(line) - let cline = a:line - let hf = '^\s*' . g:table_mode_corner . '[' . g:table_mode_corner . ' ' . g:table_mode_fillchar . ']*' . g:table_mode_corner . '\?\s*$' - let curr_line_count = s:CountSeparator(cline, g:table_mode_separator) - - if getline(cline-1) =~# hf - let prev_line_count = s:CountSeparator(cline-1, g:table_mode_corner) - if curr_line_count > prev_line_count - exec 'normal! kA' . repeat(g:table_mode_corner, curr_line_count - prev_line_count) . "\j" - endif - else - call append(cline-1, repeat(g:table_mode_corner, curr_line_count)) - let cline = a:line + 1 - endif - - if getline(cline+1) =~# hf - let next_line_count = s:CountSeparator(cline+1, g:table_mode_corner) - if curr_line_count > next_line_count - exec 'normal! jA' . repeat(g:table_mode_corner, curr_line_count - next_line_count) . "\k" - end - else - call append(cline, repeat(g:table_mode_corner, curr_line_count)) - endif -endfunction - -function! s:FillTableBorder() - let current_col = col('.') - let current_line = line('.') - execute 'silent! %s/' . g:table_mode_corner . ' \zs\([' . g:table_mode_fillchar . ' ]*\)\ze ' . g:table_mode_corner . '/\=repeat("' . g:table_mode_fillchar . '", s:strlen(submatch(0)))/g' - call cursor(current_line, current_col) -endfunction - -function! s:TableModeEnable() - let b:table_mode_active = 1 -endfunction - -function! s:TableModeDisable() - let b:table_mode_active = 0 -endfunction - -function! s:TableModeToggle() - if g:table_mode_always_active - return 1 - endif - - call s:SetBufferOptDefault('table_mode_active', 0) - let b:table_mode_active = !b:table_mode_active -endfunction - -function! s:IsTableModeActive() - if g:table_mode_always_active - return 1 - endif - - call s:SetBufferOptDefault('table_mode_active', 0) - return b:table_mode_active -endfunction - -function! s:ConvertDelimiterToSeparator(line) - execute 'silent! ' . a:line . 's/^\s*\zs\ze.\|' . g:table_mode_delimiter . '\|$/' . g:table_mode_separator . '/g' -endfunction - -function! s:Tableize() - if s:IsTableModeActive() && exists(':Tabularize') && getline('.') =~# ('^\s*' . g:table_mode_separator) - let column = s:strlen(substitute(getline('.')[0:col('.')], '[^' . g:table_mode_separator . ']', '', 'g')) - let position = s:strlen(matchstr(getline('.')[0:col('.')], '.*' . g:table_mode_separator . '\s*\zs.*')) - if g:table_mode_border - call s:UpdateLineBorder(line('.')) - endif - exec 'Tabularize/[' . g:table_mode_separator . g:table_mode_corner . ']/l1' - if g:table_mode_border - call s:FillTableBorder() - endif - normal! 0 - call search(repeat('[^' . g:table_mode_separator . ']*' . g:table_mode_separator, column) . '\s\{-\}' . repeat('.', position), 'ce', line('.')) - endif -endfunction - -function! s:Tableizeline(line) - call s:ConvertDelimiterToSeparator(a:line) - call s:UpdateLineBorder(a:line) - exec 'Tabularize/[' . g:table_mode_separator . g:table_mode_corner . ']/l1' -endfunction - -function! s:TableizeRange() range - call s:Tableizeline(a:firstline) - undojoin - " The first one causes 2 extra lines for top & bottom border while the - " following lines cause only 1 for the bottom border. - let lnum = a:firstline+3 - while lnum <= (a:firstline + (a:lastline - a:firstline+1)*2) - call s:Tableizeline(lnum) - undojoin - let lnum = lnum + 2 - endwhile - call s:FillTableBorder() -endfunction - +" Define Commands & Mappings {{{1 if !g:table_mode_always_active exec "nnoremap " . g:table_mode_toggle_map . - \ " :call TableModeToggle()" - command! -nargs=0 TableModeToggle call s:TableModeToggle() - command! -nargs=0 TableModeEnable call s:TableModeEnable() - command! -nargs=0 TableModeDisable call s:TableModeDisable() + \ " :call tablemode#TableModeToggle()" + command! -nargs=0 TableModeToggle call tablemode#TableModeToggle() + command! -nargs=0 TableModeEnable call tablemode#TableModeEnable() + command! -nargs=0 TableModeDisable call tablemode#TableModeDisable() endif -exec "inoremap " . s:table_mode_separator_map . ' ' . - \ s:table_mode_separator_map . ":call Tableize()a" -command! -nargs=0 -range Tableize ,call s:TableizeRange() +command! -nargs=0 -range Tableize ,call tablemode#TableizeRange() exec "xnoremap " . g:table_mode_tableize_map . " :Tableize" exec "nnoremap " . g:table_mode_tableize_map . " :Tableize" +"}}}1 + +" ModeLine {{{ +" vim:fdm=marker