diff --git a/README.md b/README.md index 679dfeb..0781025 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,42 @@ # vim-multimarkdown An extension of Ben Williams's markdown syntax file to accommodate Fletcher -Penney's multimarkdown. +Penney's [multimarkdown](http://fletcherpenney.net/multimarkdown/). + +## Table support + +This plugin allows you to add columns and rows to a table, change the +justification, and format the table so all columns have the same width. +The functions for this are as follows: + +| Operation | Command name | Default keybinding | +| :-------- | :------------ | :----------------- | +| Add a row above the current position | `:MmdTableAddRowAbove` | `to` | +| Add a row below the current position | `:MmdTableAddRowBelow` | `tO` | +| Add a column before the current position | `:MmdTableAddColBefore` | `ti` | +| Add a column after the current position | `:MmdTableAddColAfter` | `ta` | +| Remove the current table row | `:MmdTableDeleteRow` | `tdd` | +| Remove the current table column | `:MmdTableDeleteCol` | `tx` | +| Format the entire table | `:MmdTableFormat` | `tgq` | +| Set column to justify left | `:MmdLeftJustifyCol` | `tjl` | +| Set column to justify center | `:MmdCenterCol` | `tjc` | +| Set column to justify right | `:MmdRightJustifyCol` | `tjr` | +| Create a new table of the specified size | `:MmdTableCreate ` | none | +| Go to a specific cell | `:MmdTableCell ` | none | + +## Keybindings + +Because of the number of functions this plugin provides default keybindings. +If you don't want to use this then you can disable key mappings in your +`.vimrc` file like so: + +```VimL +let g:vim_multimarkdown_map_keys = 0 +``` + +and then map the keys yourself, for example: + +```VimL +nnoremap addcol :call g:AddTableColumnBefore() +``` -Still in early, halfhearted development. diff --git a/ftplugin/mmd/keybindings.vim b/ftplugin/mmd/keybindings.vim new file mode 100644 index 0000000..887be47 --- /dev/null +++ b/ftplugin/mmd/keybindings.vim @@ -0,0 +1,25 @@ + +if !exists('g:vim_multimarkdown_map_keys') + let g:vim_multimarkdown_map_keys = 1 +endif + +" --------------------- +" table stuff +" --------------------- + +if g:vim_multimarkdown_map_keys + " adding/removing cells + nnoremap ti :MmdTableAddColBefore + nnoremap ta :MmdTableAddColAfter + nnoremap tO :MmdTableAddRowAbove + nnoremap to :MmdTableAddRowBelow + nnoremap tdd :MmdTableDeleteRow + nnoremap tx :MmdTableDeleteCol + + " table formatting + nnoremap tgq :MmdTableFormat + nnoremap tjl :MmdLeftJustifyCol + nnoremap tjc :MmdCenterCol + nnoremap tjr :MmdRightJustifyCol +endif + diff --git a/ftplugin/mmd/tables.vim b/ftplugin/mmd/tables.vim new file mode 100644 index 0000000..e713f1f --- /dev/null +++ b/ftplugin/mmd/tables.vim @@ -0,0 +1,260 @@ + +" --------------------- +" internal module stuff +" --------------------- + +function! s:IsTableRow(line) + return a:line =~# "^\|.*\|$" +endfunction + +" clears out the contents of a row without affecting the columns +function! s:ClearRow(line) + return substitute(a:line, '[^|]', ' ', 'g') +endfunction + +" returns the line of the header of the table +function! s:HeaderLine() + let winview = winsaveview() + normal! { + let linenum = line(".") + 1 + call winrestview(winview) + return linenum +endfunction + +" returns the last line of the table +function! s:TableEndLine() + let winview = winsaveview() + normal! } + let linenum = line(".") - 1 + call winrestview(winview) + return linenum +endfunction + +function! s:TableNumRows() + return s:TableEndLine() - s:HeaderLine() + 1 +endfunction + +function! s:TableNumCols() + return strlen(substitute(getline('.'), '[^|]', '', 'g')) - 1 +endfunction + +" returns the current row relative to the beginning of the table +function! s:CurrentRow() + return line(".") - s:HeaderLine() + 1 +endfunction + +function! s:CurrentCol() + return strlen(substitute(getline('.')[0:col('.')], '[^|]', '', 'g')) +endfunction + +" returns the width of the column we are on +function! s:ColumnWidth() + let winview = winsaveview() + if getline('.')[col('.')-1] !=? '|' + normal! F| + endif + let colstart = col('.') + normal! f| + let colend = col('.') + call winrestview(winview) + return colend - colstart - 1 +endfunction + +" 1=left, 2=center, 3=right +function! s:ChangeJustification(col, justcode) + let winview = winsaveview() + call s:GotoCell(2, a:col) + let markerwidth = s:ColumnWidth() - 2 + if a:justcode == 1 + let juststr = ":" . repeat('-', markerwidth-1) + elseif a:justcode == 2 + let juststr = ":" . repeat('-', markerwidth-2) . ":" + elseif a:justcode == 3 + let juststr = repeat('-', markerwidth-1) . ":" + endif + execute "normal! ct| " . juststr . " " + call winrestview(winview) +endfunction + +" --------------------- +" public stuff +" --------------------- + +" creates a new table of the specified size +" there is 1 header row +function! s:CreateTable(numrows, numcols) + " create the header row + execute "normal! i" . repeat('| ', a:numcols) . "|" + normal! o + " just make everything left justified + execute "normal! i" . repeat('| :-- ', a:numcols) . "|" + "normal! o + " put in the rows + let i = 0 + while i < a:numrows + call s:AddTableRowBelow() + let i += 1 + endwhile +endfunction + +" goes to a specific cell +function! s:GotoCell(row, col) + if !s:IsTableRow(getline('.')) + return + endif + + " first move to the correct line + let destline = a:row + s:HeaderLine() - 1 + execute "normal! " . destline . "G" + normal! 0 + + " now we move to the correct cell + if a:col > 1 + execute "normal! " . (a:col-1) . "f|" + endif + normal! l +endfunction + +function! s:AddTableRowBelow() + if !s:IsTableRow(getline('.')) + return + endif + + normal! yyp + call setline('.', s:ClearRow(getline('.'))) +endfunction + +function! s:AddTableRowAbove() + if !s:IsTableRow(getline('.')) + return + endif + + normal! kyyp + call setline('.', s:ClearRow(getline('.'))) +endfunction + +function! s:AddTableColumnBefore() + if !s:IsTableRow(getline('.')) + return + endif + + let new_col = '|' . repeat(' ', s:ColumnWidth()) + let curcol = s:CurrentCol() + let curline = 1 + while curline <= s:TableNumRows() + call s:GotoCell(curline, curcol) + normal! F| + execute "normal! i" . new_col + let curline += 1 + endwhile +endfunction + +function! s:AddTableColumnAfter() + if !s:IsTableRow(getline('.')) + return + endif + + let new_col = repeat(' ', s:ColumnWidth()) . '|' + let curcol = s:CurrentCol() + let curline = 1 + while curline <= s:TableNumRows() + call s:GotoCell(curline, curcol) + normal! f| + execute "normal! a" . new_col + let curline += 1 + endwhile +endfunction + +function! s:DeleteTableRow() + if !s:IsTableRow(getline('.')) + return + endif + + normal! dd +endfunction + +function! s:DeleteTableColumn() + if !s:IsTableRow(getline('.')) + return + endif + + let curcol = s:CurrentCol() + let curline = 1 + while curline <= s:TableNumRows() + call s:GotoCell(curline, curcol) + normal! F| + normal! dt| + let curline += 1 + endwhile +endfunction + +function! s:FormatTable() + if !s:IsTableRow(getline('.')) + return + endif + " we need to figure out how many spaces are in each column + " and adjust all rows to contain that many spaces + let col = 1 + while col <= s:TableNumCols() + " first figure out the largest column + let line = 1 + let maxcolwidth = 0 + while line <= s:TableNumRows() + call s:GotoCell(line, col) + let w = s:ColumnWidth() + if w > maxcolwidth + let maxcolwidth = w + endif + let line += 1 + endwhile + " now pad each row in the column + let line = 1 + while line <= s:TableNumRows() + call s:GotoCell(line, col) + let padlen = maxcolwidth - s:ColumnWidth() + 1 + if padlen > 0 + normal! t| + execute "normal! ct|" . repeat(' ', padlen) + endif + let line += 1 + endwhile + let col += 1 + endwhile +endfunction + +" left justify the column we're in +function! s:LeftifyColumn() + call s:ChangeJustification(s:CurrentCol(), 1) +endfunction + +" center justify the column we're in +function! s:CenterColumn() + call s:ChangeJustification(s:CurrentCol(), 2) +endfunction + +" right justify the column we're in +function! s:RightifyColumn() + call s:ChangeJustification(s:CurrentCol(), 3) +endfunction + + +" --------------------- +" commands +" --------------------- + +command! -nargs=+ MmdTableCreate call s:CreateTable() +command! -nargs=+ MmdTableCell call s:GotoCell() +command! MmdTableFormat call s:FormatTable() + +command! MmdLeftJustifyCol call s:LeftifyColumn() +command! MmdRightJustifyCol call s:RightifyColumn() +command! MmdCenterCol call s:CenterColumn() + +command! MmdTableAddRowBelow call s:AddTableRowBelow() +command! MmdTableAddRowAbove call s:AddTableRowAbove() +command! MmdTableAddColBefore call s:AddTableColumnBefore() +command! MmdTableAddColAfter call s:AddTableColumnAfter() + +command! MmdTableDeleteRow call s:DeleteTableRow() +command! MmdTableDeleteCol call s:DeleteTableColumn() + diff --git a/syntax/mmd.vim b/syntax/mmd.vim index 1347072..4208152 100644 --- a/syntax/mmd.vim +++ b/syntax/mmd.vim @@ -63,6 +63,9 @@ syn match mmdFootnoteMarker "\[^\S\+\]" syn match mmdFootnoteIdentifier "\[^.\+\]:" contained syn region mmdFootnoteText start="^\s\{0,3\}\[^.\+\]:[ \t]" end="^$" contains=mmdFootnoteIdentifier +" mmd table support +syn region mmdTable start=/\v^\|.+\|$/ end=/\v^$/ + " Link definitions: [id]: URL (Optional Title) " TODO handle automatic links without colliding with htmlTag () "syn region mkdLinkDef matchgroup=mkdDelimiter start="^ \{,3}\zs\[[^^#]" end="]:" oneline nextgroup=mkdLinkDefTarget skipwhite @@ -162,6 +165,15 @@ HtmlHiLink mkdSourceDef Statement HtmlHiLink mkdSource String HtmlHiLink mkdLinkAttrib Function +<<<<<<< HEAD +======= +HtmlHiLink mmdEquation1 mmdMath +HtmlHiLink mmdEquation2 mmdMath +HtmlHiLink mmdMath Special + +HtmlHiLink mmdTable Comment + +>>>>>>> 1429db9... playing with syntax highlighting of tables HtmlHiLink mkdDelimiter Delimiter let b:current_syntax = "mmd"