plugins ohne plugin-manager
This commit is contained in:
parent
33a5f1d341
commit
fbeace99e5
260
.vim/doc/Tabular.txt
Normal file
260
.vim/doc/Tabular.txt
Normal file
|
|
@ -0,0 +1,260 @@
|
||||||
|
*Tabular.txt* Configurable, flexible, intuitive text aligning
|
||||||
|
|
||||||
|
*tabular* *tabular.vim*
|
||||||
|
|
||||||
|
#|#|#|#|#| #| #| ~
|
||||||
|
#| #|#|#| #|#|#| #| #| #| #|#|#| #| #|#| ~
|
||||||
|
#| #| #| #| #| #| #| #| #| #| #|#| ~
|
||||||
|
#| #| #| #| #| #| #| #| #| #| #| ~
|
||||||
|
#| #|#|#| #|#|#| #|#|#| #| #|#|#| #| ~
|
||||||
|
|
||||||
|
For Vim version 7.0 or newer
|
||||||
|
|
||||||
|
By Matt Wozniski
|
||||||
|
mjw@drexel.edu
|
||||||
|
|
||||||
|
Reference Manual ~
|
||||||
|
|
||||||
|
*tabular-toc*
|
||||||
|
|
||||||
|
1. Description |tabular-intro|
|
||||||
|
2. Walkthrough |tabular-walkthrough|
|
||||||
|
3. Scripting |tabular-scripting|
|
||||||
|
|
||||||
|
The functionality mentioned here is a plugin, see |add-plugin|.
|
||||||
|
You can avoid loading this plugin by setting the "Tabular_loaded" global
|
||||||
|
variable in your |vimrc| file: >
|
||||||
|
:let g:tabular_loaded = 1
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
1. Description *tabular-intro*
|
||||||
|
|
||||||
|
Sometimes, it's useful to line up text. Naturally, it's nicer to have the
|
||||||
|
computer do this for you, since aligning things by hand quickly becomes
|
||||||
|
unpleasant. While there are other plugins for aligning text, the ones I've
|
||||||
|
tried are either impossibly difficult to understand and use, or too simplistic
|
||||||
|
to handle complicated tasks. This plugin aims to make the easy things easy
|
||||||
|
and the hard things possible, without providing an unnecessarily obtuse
|
||||||
|
interface. It's still a work in progress, and criticisms are welcome.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
2. Walkthrough *tabular-walkthrough* *:Tabularize*
|
||||||
|
|
||||||
|
Tabular's commands are based largely on regular expressions. The basic
|
||||||
|
technique used by Tabular is taking some regex to match field delimiters,
|
||||||
|
splitting the input lines at those delimiters, trimming unnecessary spaces
|
||||||
|
from the non-delimiter parts, padding the non-delimiter parts of the lines
|
||||||
|
with spaces to make them the same length, and joining things back together
|
||||||
|
again.
|
||||||
|
|
||||||
|
For instance, consider starting with the following lines:
|
||||||
|
>
|
||||||
|
Some short phrase,some other phrase
|
||||||
|
A much longer phrase here,and another long phrase
|
||||||
|
<
|
||||||
|
Let's say we want to line these lines up at the commas. We can tell
|
||||||
|
Tabularize to do this by passing a pattern matching , to the Tabularize
|
||||||
|
command:
|
||||||
|
>
|
||||||
|
:Tabularize /,
|
||||||
|
|
||||||
|
Some short phrase , some other phrase
|
||||||
|
A much longer phrase here , and another long phrase
|
||||||
|
<
|
||||||
|
I encourage you to try copying those lines to another buffer and trying to
|
||||||
|
call :Tabularize. You'll want to take notice of two things quickly: First,
|
||||||
|
instead of requiring a range, Tabularize tries to figure out what you want to
|
||||||
|
happen. Since it knows that you want to act on lines matching a comma, it
|
||||||
|
will look upwards and downwards for lines around the current line that match a
|
||||||
|
comma, and consider all contiguous lines matching the pattern to be the range
|
||||||
|
to be acted upon. You can always override this by specifying a range, though.
|
||||||
|
|
||||||
|
The second thing you should notice is that you'll almost certainly be able to
|
||||||
|
abbreviate :Tabularize to :Tab - using this form in mappings and scripts is
|
||||||
|
discouraged as it will make conflicts with other scripts more likely, but for
|
||||||
|
interactive use it's a nice timesaver. Another convenience feature is that
|
||||||
|
running :Tabularize without providing a new pattern will cause it to reuse the
|
||||||
|
last pattern it was called with.
|
||||||
|
|
||||||
|
So, anyway, now the commas line up. Splitting the lines on commas, Tabular
|
||||||
|
realized that 'Some short phrase' would need to be padded with spaces to match
|
||||||
|
the length of 'A much longer phrase here', and it did that before joining the
|
||||||
|
lines back together. You'll also notice that, in addition to the spaces
|
||||||
|
inserting for padding, extra spaces were inserted between fields. That's
|
||||||
|
because by default, Tabular prints things left-aligned with one space between
|
||||||
|
fields. If you wanted to print things right-aligned with no spaces between
|
||||||
|
fields, you would provide a different format to the Tabularize command:
|
||||||
|
>
|
||||||
|
:Tabularize /,/r0
|
||||||
|
|
||||||
|
Some short phrase, some other phrase
|
||||||
|
A much longer phrase here,and another long phrase
|
||||||
|
<
|
||||||
|
A format specifier is either l, r, or c, followed by one or more digits. If
|
||||||
|
the letter is l, the field will be left aligned, similarly for r and right
|
||||||
|
aligning and c and center aligning. The number following the letter is the
|
||||||
|
number of spaces padding to insert before the start of the next field.
|
||||||
|
Multiple format specifiers can be added to the same command - each field will
|
||||||
|
be printed with the next format specifier in the list; when they all have been
|
||||||
|
used the first will be used again, and so on. So, the last command right
|
||||||
|
aligned every field, then inserted 0 spaces of padding before the next field.
|
||||||
|
What if we wanted to right align the text before the comma, and left align the
|
||||||
|
text after the comma? The command would look like this:
|
||||||
|
>
|
||||||
|
:Tabularize /,/r1c1l0
|
||||||
|
|
||||||
|
Some short phrase , some other phrase
|
||||||
|
A much longer phrase here , and another long phrase
|
||||||
|
<
|
||||||
|
That command would be read as "Align the matching text, splitting fields on
|
||||||
|
commas. Print everything before the first comma right aligned, then 1 space,
|
||||||
|
then the comma center aligned, then 1 space, then everything after the comma
|
||||||
|
left aligned." Notice that the alignment of the field the comma is in is
|
||||||
|
irrelevant - since it's only 1 cell wide, it looks the same whether it's right,
|
||||||
|
left, or center aligned. Also notice that the 0 padding spaces specified for
|
||||||
|
the 3rd field are unused - but they would be used if there were enough fields
|
||||||
|
to require looping through the fields again. For instance:
|
||||||
|
>
|
||||||
|
abc,def,ghi
|
||||||
|
a,b
|
||||||
|
a,b,c
|
||||||
|
|
||||||
|
:Tabularize /,/r1c1l0
|
||||||
|
|
||||||
|
abc , def, ghi
|
||||||
|
a , b
|
||||||
|
a , b , c
|
||||||
|
<
|
||||||
|
Notice that now, the format pattern has been reused; field 4 (the second comma)
|
||||||
|
is right aligned, field 5 is center aligned. No spaces were inserted between
|
||||||
|
the 3rd field (containing "def") and the 4th field (the second comma) because
|
||||||
|
the format specified 'l0'.
|
||||||
|
|
||||||
|
But, what if you only wanted to act on the first comma on the line, rather than
|
||||||
|
all of the commas on the line? Let's say we want everything before the first
|
||||||
|
comma right aligned, then the comma, then everything after the comma left
|
||||||
|
aligned:
|
||||||
|
>
|
||||||
|
abc,def,ghi
|
||||||
|
a,b
|
||||||
|
a,b,c
|
||||||
|
|
||||||
|
:Tabularize /^[^,]*\zs,/r0c0l0
|
||||||
|
|
||||||
|
abc,def,ghi
|
||||||
|
a,b
|
||||||
|
a,b,c
|
||||||
|
<
|
||||||
|
Here, we used a Vim regex that would only match the first comma on the line.
|
||||||
|
It matches the beginning of the line, followed by all the non-comma characters
|
||||||
|
up to the first comma, and then forgets about what it matched so far and
|
||||||
|
pretends that the match starts exactly at the comma.
|
||||||
|
|
||||||
|
But, now that this command does exactly what we want it to, it's become pretty
|
||||||
|
unwieldy. It would be unpleasant to need to type that more than once or
|
||||||
|
twice. The solution is to assign a name to it.
|
||||||
|
>
|
||||||
|
:AddTabularPattern first_comma /^[^,]*\zs,/r0c0l0
|
||||||
|
<
|
||||||
|
Now, typing ":Tabularize first_comma" will do the same thing as typing the
|
||||||
|
whole pattern out each time. Of course this is more useful if you store the
|
||||||
|
name in a file to be used later.
|
||||||
|
|
||||||
|
NOTE: In order to make these new commands available every time vim starts,
|
||||||
|
you'll need to put those new commands into a .vim file in a plugin directory
|
||||||
|
somewhere in your 'runtimepath'. In order to make sure that Tabular.vim has
|
||||||
|
already been loaded before your file tries to use :AddTabularPattern or
|
||||||
|
:AddTabularPipeline, the new file should be installed in an after/plugin
|
||||||
|
directory in 'runtimepath'. In general, it will be safe to find out where the
|
||||||
|
TabularMaps.vim plugin was installed, and place other files extending
|
||||||
|
Tabular.vim in the same directory as TabularMaps.vim. For more information,
|
||||||
|
and some suggested best practices, check out the |tabular-scripting| section.
|
||||||
|
|
||||||
|
Lastly, we'll approach the case where tabular cannot achieve your desired goal
|
||||||
|
just by splitting lines appart, trimming whitespace, padding with whitespace,
|
||||||
|
and rejoining the lines. As an example, consider the multiple_spaces command
|
||||||
|
from TabularMaps.vim. The goal is to split using two or more spaces as a
|
||||||
|
field delimiter, and join fields back together, properly lined up, with only
|
||||||
|
two spaces between the end of each field and the beginning of the next.
|
||||||
|
Unfortunately, Tabular can't do this with only the commands we know so far:
|
||||||
|
>
|
||||||
|
:Tabularize / /
|
||||||
|
<
|
||||||
|
The above function won't work, because it will consider "a b" as 5 fields
|
||||||
|
delimited by two pairs of 2 spaces ( 'a', ' ', '', ' ', 'b' ) instead of as
|
||||||
|
3 fields delimited by one set of 2 or more spaces ( 'a', ' ', 'b' ).
|
||||||
|
>
|
||||||
|
:Tabularize / \+/
|
||||||
|
<
|
||||||
|
The above function won't work either, because it will leave the delimiter as 4
|
||||||
|
spaces when used against "a b", meaning that we would fail at our goal of
|
||||||
|
collapsing everything down to two spaces between fields. So, we need a new
|
||||||
|
command to get around this:
|
||||||
|
>
|
||||||
|
:AddTabularPipeline multiple_spaces / \{2,}/
|
||||||
|
\ map(a:lines, "substitute(v:val, ' \{2,}', ' ', 'g')")
|
||||||
|
\ | tabular#TabularizeStrings(a:lines, ' ', 'l0')
|
||||||
|
<
|
||||||
|
Yeah. I know it looks complicated. Bear with me. I probably will try to add
|
||||||
|
in some shortcuts for this syntax, but this verbose will be guaranteed to
|
||||||
|
always work.
|
||||||
|
|
||||||
|
You should already recognize the name being assigned. The next thing to
|
||||||
|
happen is / \{2,}/ which is a pattern specifying which lines should
|
||||||
|
automatically be included in the range when no range is given. Without this,
|
||||||
|
there would be no pattern to use for extending the range. Everything after
|
||||||
|
that is a | separated list of expressions to be evaluated. In the context in
|
||||||
|
which they will be evaluated, a:lines will be set to a List of Strings
|
||||||
|
containing the text of the lines being filtered as they procede through the
|
||||||
|
pipeline you've set up. The \ at the start of the lines are just vim's line
|
||||||
|
continuation marker; you needn't worry much about them. So, the first
|
||||||
|
expression in the pipeline transforms each line by replacing every instance of
|
||||||
|
2 or more spaces with exactly two spaces. The second command in the pipeline
|
||||||
|
performs the equivalent of ":Tabularize / /l0"; the only difference is that
|
||||||
|
it is operating on a List of Strings rather than text in the buffer. At the
|
||||||
|
end of the pipeline, the Strings in the modified a:lines (or the return value
|
||||||
|
of the last expression in the pipeline, if it returns a List) will replace the
|
||||||
|
chosen range.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
3. Extending *tabular-scripting*
|
||||||
|
|
||||||
|
As mentioned above, the most important consideration when extending Tabular
|
||||||
|
with new maps or commands is that your plugin must be loaded after Tabular.vim
|
||||||
|
has finished loading, and only if Tabular.vim has loaded successfully. The
|
||||||
|
easiest approach to making sure it loads after Tabular.vim is simply putting
|
||||||
|
the new file (we'll call it "tabular_extra.vim" as an example) into an
|
||||||
|
"after/plugin/" directory in 'runtimepath', for instance:
|
||||||
|
>
|
||||||
|
~/.vim/after/plugin/tabular_extra.vim
|
||||||
|
<
|
||||||
|
The default set of mappings, found in "TabularMaps.vim", is installed in
|
||||||
|
the after/plugin/ subdirectory of whatever directory Tabular was installed to.
|
||||||
|
|
||||||
|
The other important consideration is making sure that your commands are only
|
||||||
|
called if Tabular.vim was actually loaded. The easiest way to do this is by
|
||||||
|
checking for the existence of the :Tabularize command at the start of your
|
||||||
|
plugin. A short example plugin would look like this:
|
||||||
|
>
|
||||||
|
" after/plugin/my_tabular_commands.vim
|
||||||
|
" Provides extra :Tabularize commands
|
||||||
|
|
||||||
|
if !exists(':Tabularize')
|
||||||
|
finish " Give up here; the Tabular plugin musn't have been loaded
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Make line wrapping possible by resetting the 'cpo' option, first saving it
|
||||||
|
let s:save_cpo = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
AddTabularPattern! asterisk /*/l1
|
||||||
|
|
||||||
|
AddTabularPipeline! remove_leading_spaces /^ /
|
||||||
|
\ map(a:lines, "substitute(v:val, '^ *', '', '')")
|
||||||
|
|
||||||
|
" Restore the saved value of 'cpo'
|
||||||
|
let &cpo = s:save_cpo
|
||||||
|
unlet s:save_cpo
|
||||||
|
<
|
||||||
|
==============================================================================
|
||||||
|
vim:tw=78:fo=tcq2:isk=!-~,^*,^\|,^\":ts=8:ft=help:norl:
|
||||||
789
.vim/ftplugin/markdown.vim
Normal file
789
.vim/ftplugin/markdown.vim
Normal file
|
|
@ -0,0 +1,789 @@
|
||||||
|
"TODO print messages when on visual mode. I only see VISUAL, not the messages.
|
||||||
|
|
||||||
|
" Function interface phylosophy:
|
||||||
|
"
|
||||||
|
" - functions take arbitrary line numbers as parameters.
|
||||||
|
" Current cursor line is only a suitable default parameter.
|
||||||
|
"
|
||||||
|
" - only functions that bind directly to user actions:
|
||||||
|
"
|
||||||
|
" - print error messages.
|
||||||
|
" All intermediate functions limit themselves return `0` to indicate an error.
|
||||||
|
"
|
||||||
|
" - move the cursor. All other functions do not move the cursor.
|
||||||
|
"
|
||||||
|
" This is how you should view headers for the header mappings:
|
||||||
|
"
|
||||||
|
" |BUFFER
|
||||||
|
" |
|
||||||
|
" |Outside any header
|
||||||
|
" |
|
||||||
|
" a-+# a
|
||||||
|
" |
|
||||||
|
" |Inside a
|
||||||
|
" |
|
||||||
|
" a-+
|
||||||
|
" b-+## b
|
||||||
|
" |
|
||||||
|
" |inside b
|
||||||
|
" |
|
||||||
|
" b-+
|
||||||
|
" c-+### c
|
||||||
|
" |
|
||||||
|
" |Inside c
|
||||||
|
" |
|
||||||
|
" c-+
|
||||||
|
" d-|# d
|
||||||
|
" |
|
||||||
|
" |Inside d
|
||||||
|
" |
|
||||||
|
" d-+
|
||||||
|
" e-|e
|
||||||
|
" |====
|
||||||
|
" |
|
||||||
|
" |Inside e
|
||||||
|
" |
|
||||||
|
" e-+
|
||||||
|
|
||||||
|
" For each level, contains the regexp that matches at that level only.
|
||||||
|
"
|
||||||
|
let s:levelRegexpDict = {
|
||||||
|
\ 1: '\v^(#[^#]@=|.+\n\=+$)',
|
||||||
|
\ 2: '\v^(##[^#]@=|.+\n-+$)',
|
||||||
|
\ 3: '\v^###[^#]@=',
|
||||||
|
\ 4: '\v^####[^#]@=',
|
||||||
|
\ 5: '\v^#####[^#]@=',
|
||||||
|
\ 6: '\v^######[^#]@='
|
||||||
|
\ }
|
||||||
|
|
||||||
|
" Maches any header level of any type.
|
||||||
|
"
|
||||||
|
" This could be deduced from `s:levelRegexpDict`, but it is more
|
||||||
|
" efficient to have a single regexp for this.
|
||||||
|
"
|
||||||
|
let s:headersRegexp = '\v^(#|.+\n(\=+|-+)$)'
|
||||||
|
|
||||||
|
" Returns the line number of the first header before `line`, called the
|
||||||
|
" current header.
|
||||||
|
"
|
||||||
|
" If there is no current header, return `0`.
|
||||||
|
"
|
||||||
|
" @param a:1 The line to look the header of. Default value: `getpos('.')`.
|
||||||
|
"
|
||||||
|
function! s:GetHeaderLineNum(...)
|
||||||
|
if a:0 == 0
|
||||||
|
let l:l = line('.')
|
||||||
|
else
|
||||||
|
let l:l = a:1
|
||||||
|
endif
|
||||||
|
while(l:l > 0)
|
||||||
|
if join(getline(l:l, l:l + 1), "\n") =~ s:headersRegexp
|
||||||
|
return l:l
|
||||||
|
endif
|
||||||
|
let l:l -= 1
|
||||||
|
endwhile
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" - if inside a header goes to it.
|
||||||
|
" Return its line number.
|
||||||
|
"
|
||||||
|
" - if on top level outside any headers,
|
||||||
|
" print a warning
|
||||||
|
" Return `0`.
|
||||||
|
"
|
||||||
|
function! s:MoveToCurHeader()
|
||||||
|
let l:lineNum = s:GetHeaderLineNum()
|
||||||
|
if l:lineNum != 0
|
||||||
|
call cursor(l:lineNum, 1)
|
||||||
|
else
|
||||||
|
echo 'outside any header'
|
||||||
|
"normal! gg
|
||||||
|
endif
|
||||||
|
return l:lineNum
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Move cursor to next header of any level.
|
||||||
|
"
|
||||||
|
" If there are no more headers, print a warning.
|
||||||
|
"
|
||||||
|
function! s:MoveToNextHeader()
|
||||||
|
if search(s:headersRegexp, 'W') == 0
|
||||||
|
"normal! G
|
||||||
|
echo 'no next header'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Move cursor to previous header (before current) of any level.
|
||||||
|
"
|
||||||
|
" If it does not exist, print a warning.
|
||||||
|
"
|
||||||
|
function! s:MoveToPreviousHeader()
|
||||||
|
let l:curHeaderLineNumber = s:GetHeaderLineNum()
|
||||||
|
let l:noPreviousHeader = 0
|
||||||
|
if l:curHeaderLineNumber <= 1
|
||||||
|
let l:noPreviousHeader = 1
|
||||||
|
else
|
||||||
|
let l:previousHeaderLineNumber = s:GetHeaderLineNum(l:curHeaderLineNumber - 1)
|
||||||
|
if l:previousHeaderLineNumber == 0
|
||||||
|
let l:noPreviousHeader = 1
|
||||||
|
else
|
||||||
|
call cursor(l:previousHeaderLineNumber, 1)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
if l:noPreviousHeader
|
||||||
|
echo 'no previous header'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" - if line is inside a header, return the header level (h1 -> 1, h2 -> 2, etc.).
|
||||||
|
"
|
||||||
|
" - if line is at top level outside any headers, return `0`.
|
||||||
|
"
|
||||||
|
function! s:GetHeaderLevel(...)
|
||||||
|
if a:0 == 0
|
||||||
|
let l:line = line('.')
|
||||||
|
else
|
||||||
|
let l:line = a:1
|
||||||
|
endif
|
||||||
|
let l:linenum = s:GetHeaderLineNum(l:line)
|
||||||
|
if l:linenum != 0
|
||||||
|
return s:GetLevelOfHeaderAtLine(l:linenum)
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Returns the level of the header at the given line.
|
||||||
|
"
|
||||||
|
" If there is no header at the given line, returns `0`.
|
||||||
|
"
|
||||||
|
function! s:GetLevelOfHeaderAtLine(linenum)
|
||||||
|
let l:lines = join(getline(a:linenum, a:linenum + 1), "\n")
|
||||||
|
for l:key in keys(s:levelRegexpDict)
|
||||||
|
if l:lines =~ get(s:levelRegexpDict, l:key)
|
||||||
|
return l:key
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Move cursor to parent header of the current header.
|
||||||
|
"
|
||||||
|
" If it does not exit, print a warning and do nothing.
|
||||||
|
"
|
||||||
|
function! s:MoveToParentHeader()
|
||||||
|
let l:linenum = s:GetParentHeaderLineNumber()
|
||||||
|
if l:linenum != 0
|
||||||
|
call cursor(l:linenum, 1)
|
||||||
|
else
|
||||||
|
echo 'no parent header'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Return the line number of the parent header of line `line`.
|
||||||
|
"
|
||||||
|
" If it has no parent, return `0`.
|
||||||
|
"
|
||||||
|
function! s:GetParentHeaderLineNumber(...)
|
||||||
|
if a:0 == 0
|
||||||
|
let l:line = line('.')
|
||||||
|
else
|
||||||
|
let l:line = a:1
|
||||||
|
endif
|
||||||
|
let l:level = s:GetHeaderLevel(l:line)
|
||||||
|
if l:level > 1
|
||||||
|
let l:linenum = s:GetPreviousHeaderLineNumberAtLevel(l:level - 1, l:line)
|
||||||
|
return l:linenum
|
||||||
|
endif
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Return the line number of the previous header of given level.
|
||||||
|
" in relation to line `a:1`. If not given, `a:1 = getline()`
|
||||||
|
"
|
||||||
|
" `a:1` line is included, and this may return the current header.
|
||||||
|
"
|
||||||
|
" If none return 0.
|
||||||
|
"
|
||||||
|
function! s:GetNextHeaderLineNumberAtLevel(level, ...)
|
||||||
|
if a:0 < 1
|
||||||
|
let l:line = line('.')
|
||||||
|
else
|
||||||
|
let l:line = a:1
|
||||||
|
endif
|
||||||
|
let l:l = l:line
|
||||||
|
while(l:l <= line('$'))
|
||||||
|
if join(getline(l:l, l:l + 1), "\n") =~ get(s:levelRegexpDict, a:level)
|
||||||
|
return l:l
|
||||||
|
endif
|
||||||
|
let l:l += 1
|
||||||
|
endwhile
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Return the line number of the previous header of given level.
|
||||||
|
" in relation to line `a:1`. If not given, `a:1 = getline()`
|
||||||
|
"
|
||||||
|
" `a:1` line is included, and this may return the current header.
|
||||||
|
"
|
||||||
|
" If none return 0.
|
||||||
|
"
|
||||||
|
function! s:GetPreviousHeaderLineNumberAtLevel(level, ...)
|
||||||
|
if a:0 == 0
|
||||||
|
let l:line = line('.')
|
||||||
|
else
|
||||||
|
let l:line = a:1
|
||||||
|
endif
|
||||||
|
let l:l = l:line
|
||||||
|
while(l:l > 0)
|
||||||
|
if join(getline(l:l, l:l + 1), "\n") =~ get(s:levelRegexpDict, a:level)
|
||||||
|
return l:l
|
||||||
|
endif
|
||||||
|
let l:l -= 1
|
||||||
|
endwhile
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Move cursor to next sibling header.
|
||||||
|
"
|
||||||
|
" If there is no next siblings, print a warning and don't move.
|
||||||
|
"
|
||||||
|
function! s:MoveToNextSiblingHeader()
|
||||||
|
let l:curHeaderLineNumber = s:GetHeaderLineNum()
|
||||||
|
let l:curHeaderLevel = s:GetLevelOfHeaderAtLine(l:curHeaderLineNumber)
|
||||||
|
let l:curHeaderParentLineNumber = s:GetParentHeaderLineNumber()
|
||||||
|
let l:nextHeaderSameLevelLineNumber = s:GetNextHeaderLineNumberAtLevel(l:curHeaderLevel, l:curHeaderLineNumber + 1)
|
||||||
|
let l:noNextSibling = 0
|
||||||
|
if l:nextHeaderSameLevelLineNumber == 0
|
||||||
|
let l:noNextSibling = 1
|
||||||
|
else
|
||||||
|
let l:nextHeaderSameLevelParentLineNumber = s:GetParentHeaderLineNumber(l:nextHeaderSameLevelLineNumber)
|
||||||
|
if l:curHeaderParentLineNumber == l:nextHeaderSameLevelParentLineNumber
|
||||||
|
call cursor(l:nextHeaderSameLevelLineNumber, 1)
|
||||||
|
else
|
||||||
|
let l:noNextSibling = 1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
if l:noNextSibling
|
||||||
|
echo 'no next sibling header'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Move cursor to previous sibling header.
|
||||||
|
"
|
||||||
|
" If there is no previous siblings, print a warning and do nothing.
|
||||||
|
"
|
||||||
|
function! s:MoveToPreviousSiblingHeader()
|
||||||
|
let l:curHeaderLineNumber = s:GetHeaderLineNum()
|
||||||
|
let l:curHeaderLevel = s:GetLevelOfHeaderAtLine(l:curHeaderLineNumber)
|
||||||
|
let l:curHeaderParentLineNumber = s:GetParentHeaderLineNumber()
|
||||||
|
let l:previousHeaderSameLevelLineNumber = s:GetPreviousHeaderLineNumberAtLevel(l:curHeaderLevel, l:curHeaderLineNumber - 1)
|
||||||
|
let l:noPreviousSibling = 0
|
||||||
|
if l:previousHeaderSameLevelLineNumber == 0
|
||||||
|
let l:noPreviousSibling = 1
|
||||||
|
else
|
||||||
|
let l:previousHeaderSameLevelParentLineNumber = s:GetParentHeaderLineNumber(l:previousHeaderSameLevelLineNumber)
|
||||||
|
if l:curHeaderParentLineNumber == l:previousHeaderSameLevelParentLineNumber
|
||||||
|
call cursor(l:previousHeaderSameLevelLineNumber, 1)
|
||||||
|
else
|
||||||
|
let l:noPreviousSibling = 1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
if l:noPreviousSibling
|
||||||
|
echo 'no previous sibling header'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Toc(...)
|
||||||
|
if a:0 > 0
|
||||||
|
let l:window_type = a:1
|
||||||
|
else
|
||||||
|
let l:window_type = 'vertical'
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
let l:bufnr = bufnr('%')
|
||||||
|
let l:cursor_line = line('.')
|
||||||
|
let l:cursor_header = 0
|
||||||
|
let l:fenced_block = 0
|
||||||
|
let l:front_matter = 0
|
||||||
|
let l:header_list = []
|
||||||
|
let l:header_max_len = 0
|
||||||
|
let l:vim_markdown_toc_autofit = get(g:, "vim_markdown_toc_autofit", 0)
|
||||||
|
let l:vim_markdown_frontmatter = get(g:, "vim_markdown_frontmatter", 0)
|
||||||
|
for i in range(1, line('$'))
|
||||||
|
let l:lineraw = getline(i)
|
||||||
|
let l:l1 = getline(i+1)
|
||||||
|
let l:line = substitute(l:lineraw, "#", "\\\#", "g")
|
||||||
|
if l:line =~ '````*' || l:line =~ '\~\~\~\~*'
|
||||||
|
if l:fenced_block == 0
|
||||||
|
let l:fenced_block = 1
|
||||||
|
elseif l:fenced_block == 1
|
||||||
|
let l:fenced_block = 0
|
||||||
|
endif
|
||||||
|
elseif l:vim_markdown_frontmatter == 1
|
||||||
|
if l:front_matter == 1
|
||||||
|
if l:line == '---'
|
||||||
|
let l:front_matter = 0
|
||||||
|
endif
|
||||||
|
elseif i == 1
|
||||||
|
if l:line == '---'
|
||||||
|
let l:front_matter = 1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
if l:line =~ '^#\+' || (l:l1 =~ '^=\+\s*$' || l:l1 =~ '^-\+\s*$') && l:line =~ '^\S'
|
||||||
|
let l:is_header = 1
|
||||||
|
else
|
||||||
|
let l:is_header = 0
|
||||||
|
endif
|
||||||
|
if l:is_header == 1 && l:fenced_block == 0 && l:front_matter == 0
|
||||||
|
" append line to location list
|
||||||
|
let l:item = {'lnum': i, 'text': l:line, 'valid': 1, 'bufnr': l:bufnr, 'col': 1}
|
||||||
|
let l:header_list = l:header_list + [l:item]
|
||||||
|
" set header number of the cursor position
|
||||||
|
if l:cursor_header == 0
|
||||||
|
if i == l:cursor_line
|
||||||
|
let l:cursor_header = len(l:header_list)
|
||||||
|
elseif i > l:cursor_line
|
||||||
|
let l:cursor_header = len(l:header_list) - 1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
" keep track of the longest header size (heading level + title)
|
||||||
|
let l:total_len = stridx(l:line, ' ') + strdisplaywidth(l:line)
|
||||||
|
if l:total_len > l:header_max_len
|
||||||
|
let l:header_max_len = l:total_len
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
call setloclist(0, l:header_list)
|
||||||
|
if len(l:header_list) == 0
|
||||||
|
echom "Toc: No headers."
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:window_type ==# 'horizontal'
|
||||||
|
lopen
|
||||||
|
elseif l:window_type ==# 'vertical'
|
||||||
|
vertical lopen
|
||||||
|
" auto-fit toc window when possible to shrink it
|
||||||
|
if (&columns/2) > l:header_max_len && l:vim_markdown_toc_autofit == 1
|
||||||
|
execute 'vertical resize ' . (l:header_max_len + 1)
|
||||||
|
else
|
||||||
|
execute 'vertical resize ' . (&columns/2)
|
||||||
|
endif
|
||||||
|
elseif l:window_type ==# 'tab'
|
||||||
|
tab lopen
|
||||||
|
else
|
||||||
|
lopen
|
||||||
|
endif
|
||||||
|
setlocal modifiable
|
||||||
|
for i in range(1, line('$'))
|
||||||
|
" this is the location-list data for the current item
|
||||||
|
let d = getloclist(0)[i-1]
|
||||||
|
" atx headers
|
||||||
|
if match(d.text, "^#") > -1
|
||||||
|
let l:level = len(matchstr(d.text, '#*', 'g'))-1
|
||||||
|
let d.text = substitute(d.text, '\v^#*[ ]*', '', '')
|
||||||
|
let d.text = substitute(d.text, '\v[ ]*#*$', '', '')
|
||||||
|
" setex headers
|
||||||
|
else
|
||||||
|
let l:next_line = getbufline(d.bufnr, d.lnum+1)
|
||||||
|
if match(l:next_line, "=") > -1
|
||||||
|
let l:level = 0
|
||||||
|
elseif match(l:next_line, "-") > -1
|
||||||
|
let l:level = 1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
call setline(i, repeat(' ', l:level). d.text)
|
||||||
|
endfor
|
||||||
|
setlocal nomodified
|
||||||
|
setlocal nomodifiable
|
||||||
|
execute 'normal! ' . l:cursor_header . 'G'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Convert Setex headers in range `line1 .. line2` to Atx.
|
||||||
|
"
|
||||||
|
" Return the number of conversions.
|
||||||
|
"
|
||||||
|
function! s:SetexToAtx(line1, line2)
|
||||||
|
let l:originalNumLines = line('$')
|
||||||
|
execute 'silent! ' . a:line1 . ',' . a:line2 . 'substitute/\v(.*\S.*)\n\=+$/# \1/'
|
||||||
|
execute 'silent! ' . a:line1 . ',' . a:line2 . 'substitute/\v(.*\S.*)\n-+$/## \1/'
|
||||||
|
return l:originalNumLines - line('$')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" If `a:1` is 0, decrease the level of all headers in range `line1 .. line2`.
|
||||||
|
"
|
||||||
|
" Otherwise, increase the level. `a:1` defaults to `0`.
|
||||||
|
"
|
||||||
|
function! s:HeaderDecrease(line1, line2, ...)
|
||||||
|
if a:0 > 0
|
||||||
|
let l:increase = a:1
|
||||||
|
else
|
||||||
|
let l:increase = 0
|
||||||
|
endif
|
||||||
|
if l:increase
|
||||||
|
let l:forbiddenLevel = 6
|
||||||
|
let l:replaceLevels = [5, 1]
|
||||||
|
let l:levelDelta = 1
|
||||||
|
else
|
||||||
|
let l:forbiddenLevel = 1
|
||||||
|
let l:replaceLevels = [2, 6]
|
||||||
|
let l:levelDelta = -1
|
||||||
|
endif
|
||||||
|
for l:line in range(a:line1, a:line2)
|
||||||
|
if join(getline(l:line, l:line + 1), "\n") =~ s:levelRegexpDict[l:forbiddenLevel]
|
||||||
|
echomsg 'There is an h' . l:forbiddenLevel . ' at line ' . l:line . '. Aborting.'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
let l:numSubstitutions = s:SetexToAtx(a:line1, a:line2)
|
||||||
|
let l:flags = (&gdefault ? '' : 'g')
|
||||||
|
for l:level in range(replaceLevels[0], replaceLevels[1], -l:levelDelta)
|
||||||
|
execute 'silent! ' . a:line1 . ',' . (a:line2 - l:numSubstitutions) . 'substitute/' . s:levelRegexpDict[l:level] . '/' . repeat('#', l:level + l:levelDelta) . '/' . l:flags
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Format table under cursor.
|
||||||
|
"
|
||||||
|
" Depends on Tabularize.
|
||||||
|
"
|
||||||
|
function! s:TableFormat()
|
||||||
|
let l:pos = getpos('.')
|
||||||
|
normal! {
|
||||||
|
" Search instead of `normal! j` because of the table at beginning of file edge case.
|
||||||
|
call search('|')
|
||||||
|
normal! j
|
||||||
|
" Remove everything that is not a pipe, colon or hyphen next to a colon othewise
|
||||||
|
" well formated tables would grow because of addition of 2 spaces on the separator
|
||||||
|
" line by Tabularize /|.
|
||||||
|
let l:flags = (&gdefault ? '' : 'g')
|
||||||
|
execute 's/\(:\@<!-:\@!\|[^|:-]\)//e' . l:flags
|
||||||
|
execute 's/--/-/e' . l:flags
|
||||||
|
Tabularize /|
|
||||||
|
" Move colons for alignment to left or right side of the cell.
|
||||||
|
execute 's/:\( \+\)|/\1:|/e' . l:flags
|
||||||
|
execute 's/|\( \+\):/|:\1/e' . l:flags
|
||||||
|
execute 's/ /-/' . l:flags
|
||||||
|
call setpos('.', l:pos)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Wrapper to do move commands in visual mode.
|
||||||
|
"
|
||||||
|
function! s:VisMove(f)
|
||||||
|
norm! gv
|
||||||
|
call function(a:f)()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Map in both normal and visual modes.
|
||||||
|
"
|
||||||
|
function! s:MapNormVis(rhs,lhs)
|
||||||
|
execute 'nn <buffer><silent> ' . a:rhs . ' :call ' . a:lhs . '()<cr>'
|
||||||
|
execute 'vn <buffer><silent> ' . a:rhs . ' <esc>:call <sid>VisMove(''' . a:lhs . ''')<cr>'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Parameters:
|
||||||
|
"
|
||||||
|
" - step +1 for right, -1 for left
|
||||||
|
"
|
||||||
|
" TODO: multiple lines.
|
||||||
|
"
|
||||||
|
function! s:FindCornerOfSyntax(lnum, col, step)
|
||||||
|
let l:col = a:col
|
||||||
|
let l:syn = synIDattr(synID(a:lnum, l:col, 1), 'name')
|
||||||
|
while synIDattr(synID(a:lnum, l:col, 1), 'name') ==# l:syn
|
||||||
|
let l:col += a:step
|
||||||
|
endwhile
|
||||||
|
return l:col - a:step
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Return the next position of the given syntax name,
|
||||||
|
" inclusive on the given position.
|
||||||
|
"
|
||||||
|
" TODO: multiple lines
|
||||||
|
"
|
||||||
|
function! s:FindNextSyntax(lnum, col, name)
|
||||||
|
let l:col = a:col
|
||||||
|
let l:step = 1
|
||||||
|
while synIDattr(synID(a:lnum, l:col, 1), 'name') !=# a:name
|
||||||
|
let l:col += l:step
|
||||||
|
endwhile
|
||||||
|
return [a:lnum, l:col]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:FindCornersOfSyntax(lnum, col)
|
||||||
|
return [<sid>FindLeftOfSyntax(a:lnum, a:col), <sid>FindRightOfSyntax(a:lnum, a:col)]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:FindRightOfSyntax(lnum, col)
|
||||||
|
return <sid>FindCornerOfSyntax(a:lnum, a:col, 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:FindLeftOfSyntax(lnum, col)
|
||||||
|
return <sid>FindCornerOfSyntax(a:lnum, a:col, -1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Returns:
|
||||||
|
"
|
||||||
|
" - a string with the the URL for the link under the cursor
|
||||||
|
" - an empty string if the cursor is not on a link
|
||||||
|
"
|
||||||
|
" TODO
|
||||||
|
"
|
||||||
|
" - multiline support
|
||||||
|
" - give an error if the separator does is not on a link
|
||||||
|
"
|
||||||
|
function! s:Markdown_GetUrlForPosition(lnum, col)
|
||||||
|
let l:lnum = a:lnum
|
||||||
|
let l:col = a:col
|
||||||
|
let l:syn = synIDattr(synID(l:lnum, l:col, 1), 'name')
|
||||||
|
|
||||||
|
if l:syn ==# 'mkdInlineURL' || l:syn ==# 'mkdURL' || l:syn ==# 'mkdLinkDefTarget'
|
||||||
|
" Do nothing.
|
||||||
|
elseif l:syn ==# 'mkdLink'
|
||||||
|
let [l:lnum, l:col] = <sid>FindNextSyntax(l:lnum, l:col, 'mkdURL')
|
||||||
|
let l:syn = 'mkdURL'
|
||||||
|
elseif l:syn ==# 'mkdDelimiter'
|
||||||
|
let l:line = getline(l:lnum)
|
||||||
|
let l:char = l:line[col - 1]
|
||||||
|
if l:char ==# '<'
|
||||||
|
let l:col += 1
|
||||||
|
elseif l:char ==# '>' || l:char ==# ')'
|
||||||
|
let l:col -= 1
|
||||||
|
elseif l:char ==# '[' || l:char ==# ']' || l:char ==# '('
|
||||||
|
let [l:lnum, l:col] = <sid>FindNextSyntax(l:lnum, l:col, 'mkdURL')
|
||||||
|
else
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
|
|
||||||
|
let [l:left, l:right] = <sid>FindCornersOfSyntax(l:lnum, l:col)
|
||||||
|
return getline(l:lnum)[l:left - 1 : l:right - 1]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Front end for GetUrlForPosition.
|
||||||
|
"
|
||||||
|
function! s:OpenUrlUnderCursor()
|
||||||
|
let l:url = s:Markdown_GetUrlForPosition(line('.'), col('.'))
|
||||||
|
if l:url != ''
|
||||||
|
call s:VersionAwareNetrwBrowseX(l:url)
|
||||||
|
else
|
||||||
|
echomsg 'The cursor is not on a link.'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" We need a definition guard because we invoke 'edit' which will reload this
|
||||||
|
" script while this function is running. We must not replace it.
|
||||||
|
if !exists('*s:EditUrlUnderCursor')
|
||||||
|
function s:EditUrlUnderCursor()
|
||||||
|
let l:url = s:Markdown_GetUrlForPosition(line('.'), col('.'))
|
||||||
|
if l:url != ''
|
||||||
|
if get(g:, 'vim_markdown_autowrite', 0)
|
||||||
|
write
|
||||||
|
endif
|
||||||
|
let l:anchor = ''
|
||||||
|
if get(g:, 'vim_markdown_follow_anchor', 0)
|
||||||
|
let l:parts = split(l:url, '#', 1)
|
||||||
|
if len(l:parts) == 2
|
||||||
|
let [l:url, l:anchor] = parts
|
||||||
|
let l:anchorexpr = get(g:, 'vim_markdown_anchorexpr', '')
|
||||||
|
if l:anchorexpr != ''
|
||||||
|
let l:anchor = eval(substitute(
|
||||||
|
\ l:anchorexpr, 'v:anchor',
|
||||||
|
\ escape('"'.l:anchor.'"', '"'), ''))
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
if l:url != ''
|
||||||
|
let l:ext = ''
|
||||||
|
if get(g:, 'vim_markdown_no_extensions_in_markdown', 0)
|
||||||
|
" use another file extension if preferred
|
||||||
|
if exists('g:vim_markdown_auto_extension_ext')
|
||||||
|
let l:ext = '.'.g:vim_markdown_auto_extension_ext
|
||||||
|
else
|
||||||
|
let l:ext = '.md'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
let l:url = fnameescape(fnamemodify(expand('%:h').'/'.l:url.l:ext, ':.'))
|
||||||
|
let l:editmethod = ''
|
||||||
|
" determine how to open the linked file (split, tab, etc)
|
||||||
|
if exists('g:vim_markdown_edit_url_in')
|
||||||
|
if g:vim_markdown_edit_url_in == 'tab'
|
||||||
|
let l:editmethod = 'tabnew'
|
||||||
|
elseif g:vim_markdown_edit_url_in == 'vsplit'
|
||||||
|
let l:editmethod = 'vsp'
|
||||||
|
elseif g:vim_markdown_edit_url_in == 'hsplit'
|
||||||
|
let l:editmethod = 'sp'
|
||||||
|
else
|
||||||
|
let l:editmethod = 'edit'
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
" default to current buffer
|
||||||
|
let l:editmethod = 'edit'
|
||||||
|
endif
|
||||||
|
execute l:editmethod l:url
|
||||||
|
endif
|
||||||
|
if l:anchor != ''
|
||||||
|
silent! execute '/'.l:anchor
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
echomsg 'The cursor is not on a link.'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! s:VersionAwareNetrwBrowseX(url)
|
||||||
|
if has('patch-7.4.567')
|
||||||
|
call netrw#BrowseX(a:url, 0)
|
||||||
|
else
|
||||||
|
call netrw#NetrwBrowseX(a:url, 0)
|
||||||
|
endif
|
||||||
|
endf
|
||||||
|
|
||||||
|
function! s:MapNotHasmapto(lhs, rhs)
|
||||||
|
if !hasmapto('<Plug>' . a:rhs)
|
||||||
|
execute 'nmap <buffer>' . a:lhs . ' <Plug>' . a:rhs
|
||||||
|
execute 'vmap <buffer>' . a:lhs . ' <Plug>' . a:rhs
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
call <sid>MapNormVis('<Plug>Markdown_MoveToNextHeader', '<sid>MoveToNextHeader')
|
||||||
|
call <sid>MapNormVis('<Plug>Markdown_MoveToPreviousHeader', '<sid>MoveToPreviousHeader')
|
||||||
|
call <sid>MapNormVis('<Plug>Markdown_MoveToNextSiblingHeader', '<sid>MoveToNextSiblingHeader')
|
||||||
|
call <sid>MapNormVis('<Plug>Markdown_MoveToPreviousSiblingHeader', '<sid>MoveToPreviousSiblingHeader')
|
||||||
|
call <sid>MapNormVis('<Plug>Markdown_MoveToParentHeader', '<sid>MoveToParentHeader')
|
||||||
|
call <sid>MapNormVis('<Plug>Markdown_MoveToCurHeader', '<sid>MoveToCurHeader')
|
||||||
|
nnoremap <Plug>Markdown_OpenUrlUnderCursor :call <sid>OpenUrlUnderCursor()<cr>
|
||||||
|
nnoremap <Plug>Markdown_EditUrlUnderCursor :call <sid>EditUrlUnderCursor()<cr>
|
||||||
|
|
||||||
|
if !get(g:, 'vim_markdown_no_default_key_mappings', 0)
|
||||||
|
call <sid>MapNotHasmapto(']]', 'Markdown_MoveToNextHeader')
|
||||||
|
call <sid>MapNotHasmapto('[[', 'Markdown_MoveToPreviousHeader')
|
||||||
|
call <sid>MapNotHasmapto('][', 'Markdown_MoveToNextSiblingHeader')
|
||||||
|
call <sid>MapNotHasmapto('[]', 'Markdown_MoveToPreviousSiblingHeader')
|
||||||
|
call <sid>MapNotHasmapto(']u', 'Markdown_MoveToParentHeader')
|
||||||
|
call <sid>MapNotHasmapto(']c', 'Markdown_MoveToCurHeader')
|
||||||
|
call <sid>MapNotHasmapto('gx', 'Markdown_OpenUrlUnderCursor')
|
||||||
|
call <sid>MapNotHasmapto('ge', 'Markdown_EditUrlUnderCursor')
|
||||||
|
endif
|
||||||
|
|
||||||
|
command! -buffer -range=% HeaderDecrease call s:HeaderDecrease(<line1>, <line2>)
|
||||||
|
command! -buffer -range=% HeaderIncrease call s:HeaderDecrease(<line1>, <line2>, 1)
|
||||||
|
command! -buffer -range=% SetexToAtx call s:SetexToAtx(<line1>, <line2>)
|
||||||
|
command! -buffer TableFormat call s:TableFormat()
|
||||||
|
command! -buffer Toc call s:Toc()
|
||||||
|
command! -buffer Toch call s:Toc('horizontal')
|
||||||
|
command! -buffer Tocv call s:Toc('vertical')
|
||||||
|
command! -buffer Toct call s:Toc('tab')
|
||||||
|
|
||||||
|
" Heavily based on vim-notes - http://peterodding.com/code/vim/notes/
|
||||||
|
if exists('g:vim_markdown_fenced_languages')
|
||||||
|
let s:filetype_dict = {}
|
||||||
|
for s:filetype in g:vim_markdown_fenced_languages
|
||||||
|
let key = matchstr(s:filetype, "[^=]*")
|
||||||
|
let val = matchstr(s:filetype, "[^=]*$")
|
||||||
|
let s:filetype_dict[key] = val
|
||||||
|
endfor
|
||||||
|
else
|
||||||
|
let s:filetype_dict = {
|
||||||
|
\ 'c++': 'cpp',
|
||||||
|
\ 'viml': 'vim',
|
||||||
|
\ 'bash': 'sh',
|
||||||
|
\ 'ini': 'dosini'
|
||||||
|
\ }
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! s:MarkdownHighlightSources(force)
|
||||||
|
" Syntax highlight source code embedded in notes.
|
||||||
|
" Look for code blocks in the current file
|
||||||
|
let filetypes = {}
|
||||||
|
for line in getline(1, '$')
|
||||||
|
let ft = matchstr(line, '```\s*\zs[0-9A-Za-z_+-]*')
|
||||||
|
if !empty(ft) && ft !~ '^\d*$' | let filetypes[ft] = 1 | endif
|
||||||
|
endfor
|
||||||
|
if !exists('b:mkd_known_filetypes')
|
||||||
|
let b:mkd_known_filetypes = {}
|
||||||
|
endif
|
||||||
|
if !exists('b:mkd_included_filetypes')
|
||||||
|
" set syntax file name included
|
||||||
|
let b:mkd_included_filetypes = {}
|
||||||
|
endif
|
||||||
|
if !a:force && (b:mkd_known_filetypes == filetypes || empty(filetypes))
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Now we're ready to actually highlight the code blocks.
|
||||||
|
let startgroup = 'mkdCodeStart'
|
||||||
|
let endgroup = 'mkdCodeEnd'
|
||||||
|
for ft in keys(filetypes)
|
||||||
|
if a:force || !has_key(b:mkd_known_filetypes, ft)
|
||||||
|
if has_key(s:filetype_dict, ft)
|
||||||
|
let filetype = s:filetype_dict[ft]
|
||||||
|
else
|
||||||
|
let filetype = ft
|
||||||
|
endif
|
||||||
|
let group = 'mkdSnippet' . toupper(substitute(filetype, "[+-]", "_", "g"))
|
||||||
|
if !has_key(b:mkd_included_filetypes, filetype)
|
||||||
|
let include = s:SyntaxInclude(filetype)
|
||||||
|
let b:mkd_included_filetypes[filetype] = 1
|
||||||
|
else
|
||||||
|
let include = '@' . toupper(filetype)
|
||||||
|
endif
|
||||||
|
let command = 'syntax region %s matchgroup=%s start="^\s*```\s*%s$" matchgroup=%s end="\s*```$" keepend contains=%s%s'
|
||||||
|
execute printf(command, group, startgroup, ft, endgroup, include, has('conceal') && get(g:, 'vim_markdown_conceal', 1) && get(g:, 'vim_markdown_conceal_code_blocks', 1) ? ' concealends' : '')
|
||||||
|
execute printf('syntax cluster mkdNonListItem add=%s', group)
|
||||||
|
|
||||||
|
let b:mkd_known_filetypes[ft] = 1
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:SyntaxInclude(filetype)
|
||||||
|
" Include the syntax highlighting of another {filetype}.
|
||||||
|
let grouplistname = '@' . toupper(a:filetype)
|
||||||
|
" Unset the name of the current syntax while including the other syntax
|
||||||
|
" because some syntax scripts do nothing when "b:current_syntax" is set
|
||||||
|
if exists('b:current_syntax')
|
||||||
|
let syntax_save = b:current_syntax
|
||||||
|
unlet b:current_syntax
|
||||||
|
endif
|
||||||
|
try
|
||||||
|
execute 'syntax include' grouplistname 'syntax/' . a:filetype . '.vim'
|
||||||
|
execute 'syntax include' grouplistname 'after/syntax/' . a:filetype . '.vim'
|
||||||
|
catch /E484/
|
||||||
|
" Ignore missing scripts
|
||||||
|
endtry
|
||||||
|
" Restore the name of the current syntax
|
||||||
|
if exists('syntax_save')
|
||||||
|
let b:current_syntax = syntax_save
|
||||||
|
elseif exists('b:current_syntax')
|
||||||
|
unlet b:current_syntax
|
||||||
|
endif
|
||||||
|
return grouplistname
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
function! s:MarkdownRefreshSyntax(force)
|
||||||
|
if &filetype =~ 'markdown' && line('$') > 1
|
||||||
|
call s:MarkdownHighlightSources(a:force)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:MarkdownClearSyntaxVariables()
|
||||||
|
if &filetype =~ 'markdown'
|
||||||
|
unlet! b:mkd_included_filetypes
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
augroup Mkd
|
||||||
|
autocmd! * <buffer>
|
||||||
|
autocmd BufWinEnter <buffer> call s:MarkdownRefreshSyntax(1)
|
||||||
|
autocmd BufUnload <buffer> call s:MarkdownClearSyntaxVariables()
|
||||||
|
autocmd BufWritePost <buffer> call s:MarkdownRefreshSyntax(0)
|
||||||
|
autocmd InsertEnter,InsertLeave <buffer> call s:MarkdownRefreshSyntax(0)
|
||||||
|
autocmd CursorHold,CursorHoldI <buffer> call s:MarkdownRefreshSyntax(0)
|
||||||
|
augroup END
|
||||||
346
.vim/plugin/Tabular.vim
Normal file
346
.vim/plugin/Tabular.vim
Normal file
|
|
@ -0,0 +1,346 @@
|
||||||
|
" Tabular: Align columnar data using regex-designated column boundaries
|
||||||
|
" Maintainer: Matthew Wozniski (godlygeek@gmail.com)
|
||||||
|
" Date: Thu, 03 May 2012 20:49:32 -0400
|
||||||
|
" Version: 1.0
|
||||||
|
"
|
||||||
|
" Long Description:
|
||||||
|
" Sometimes, it's useful to line up text. Naturally, it's nicer to have the
|
||||||
|
" computer do this for you, since aligning things by hand quickly becomes
|
||||||
|
" unpleasant. While there are other plugins for aligning text, the ones I've
|
||||||
|
" tried are either impossibly difficult to understand and use, or too simplistic
|
||||||
|
" to handle complicated tasks. This plugin aims to make the easy things easy
|
||||||
|
" and the hard things possible, without providing an unnecessarily obtuse
|
||||||
|
" interface. It's still a work in progress, and criticisms are welcome.
|
||||||
|
"
|
||||||
|
" License:
|
||||||
|
" Copyright (c) 2012, Matthew J. Wozniski
|
||||||
|
" All rights reserved.
|
||||||
|
"
|
||||||
|
" Redistribution and use in source and binary forms, with or without
|
||||||
|
" modification, are permitted provided that the following conditions are met:
|
||||||
|
" * Redistributions of source code must retain the above copyright notice,
|
||||||
|
" this list of conditions and the following disclaimer.
|
||||||
|
" * Redistributions in binary form must reproduce the above copyright
|
||||||
|
" notice, this list of conditions and the following disclaimer in the
|
||||||
|
" documentation and/or other materials provided with the distribution.
|
||||||
|
" * The names of the contributors may not be used to endorse or promote
|
||||||
|
" products derived from this software without specific prior written
|
||||||
|
" permission.
|
||||||
|
"
|
||||||
|
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
|
||||||
|
" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||||
|
" NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
" OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
" Abort if running in vi-compatible mode or the user doesn't want us.
|
||||||
|
if &cp || exists('g:tabular_loaded')
|
||||||
|
if &cp && &verbose
|
||||||
|
echo "Not loading Tabular in compatible mode."
|
||||||
|
endif
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
let g:tabular_loaded = 1
|
||||||
|
|
||||||
|
" Stupid vimscript crap {{{1
|
||||||
|
let s:savecpo = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
" Private Things {{{1
|
||||||
|
|
||||||
|
" Dictionary of command name to command
|
||||||
|
let s:TabularCommands = {}
|
||||||
|
|
||||||
|
" Generate tab completion list for :Tabularize {{{2
|
||||||
|
" Return a list of commands that match the command line typed so far.
|
||||||
|
" NOTE: Tries to handle commands with spaces in the name, but Vim doesn't seem
|
||||||
|
" to handle that terribly well... maybe I should give up on that.
|
||||||
|
function! s:CompleteTabularizeCommand(argstart, cmdline, cursorpos)
|
||||||
|
let names = keys(s:TabularCommands)
|
||||||
|
if exists("b:TabularCommands")
|
||||||
|
let names += keys(b:TabularCommands)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let cmdstart = substitute(a:cmdline, '^\s*\S\+\s*', '', '')
|
||||||
|
|
||||||
|
return filter(names, 'v:val =~# ''^\V'' . escape(cmdstart, ''\'')')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Choose the proper command map from the given command line {{{2
|
||||||
|
" Returns [ command map, command line with leading <buffer> removed ]
|
||||||
|
function! s:ChooseCommandMap(commandline)
|
||||||
|
let map = s:TabularCommands
|
||||||
|
let cmd = a:commandline
|
||||||
|
|
||||||
|
if cmd =~# '^<buffer>\s\+'
|
||||||
|
if !exists('b:TabularCommands')
|
||||||
|
let b:TabularCommands = {}
|
||||||
|
endif
|
||||||
|
let map = b:TabularCommands
|
||||||
|
let cmd = substitute(cmd, '^<buffer>\s\+', '', '')
|
||||||
|
endif
|
||||||
|
|
||||||
|
return [ map, cmd ]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Parse '/pattern/format' into separate pattern and format parts. {{{2
|
||||||
|
" If parsing fails, return [ '', '' ]
|
||||||
|
function! s:ParsePattern(string)
|
||||||
|
if a:string[0] != '/'
|
||||||
|
return ['','']
|
||||||
|
endif
|
||||||
|
|
||||||
|
let pat = '\\\@<!\%(\\\\\)\{-}\zs/' . tabular#ElementFormatPattern() . '*$'
|
||||||
|
let format = matchstr(a:string[1:-1], pat)
|
||||||
|
if !empty(format)
|
||||||
|
let format = format[1 : -1]
|
||||||
|
let pattern = a:string[1 : -len(format) - 2]
|
||||||
|
else
|
||||||
|
let pattern = a:string[1 : -1]
|
||||||
|
endif
|
||||||
|
|
||||||
|
return [pattern, format]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Split apart a list of | separated expressions. {{{2
|
||||||
|
function! s:SplitCommands(string)
|
||||||
|
if a:string =~ '^\s*$'
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
|
||||||
|
let end = match(a:string, "[\"'|]")
|
||||||
|
|
||||||
|
" Loop until we find a delimiting | or end-of-string
|
||||||
|
while end != -1 && (a:string[end] != '|' || a:string[end+1] == '|')
|
||||||
|
if a:string[end] == "'"
|
||||||
|
let end = match(a:string, "'", end+1) + 1
|
||||||
|
if end == 0
|
||||||
|
throw "No matching end single quote"
|
||||||
|
endif
|
||||||
|
elseif a:string[end] == '"'
|
||||||
|
" Find a " preceded by an even number of \ (or 0)
|
||||||
|
let pattern = '\%(\\\@<!\%(\\\\\)*\)\@<="'
|
||||||
|
let end = matchend(a:string, pattern, end+1) + 1
|
||||||
|
if end == 0
|
||||||
|
throw "No matching end double quote"
|
||||||
|
endif
|
||||||
|
else " Found ||
|
||||||
|
let end += 2
|
||||||
|
endif
|
||||||
|
|
||||||
|
let end = match(a:string, "[\"'|]", end)
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
if end == 0 || a:string[0 : end - (end > 0)] =~ '^\s*$'
|
||||||
|
throw "Empty element"
|
||||||
|
endif
|
||||||
|
|
||||||
|
if end == -1
|
||||||
|
let rv = [ a:string ]
|
||||||
|
else
|
||||||
|
let rv = [ a:string[0 : end-1] ] + s:SplitCommands(a:string[end+1 : -1])
|
||||||
|
endif
|
||||||
|
|
||||||
|
return rv
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Public Things {{{1
|
||||||
|
|
||||||
|
" Command associating a command name with a simple pattern command {{{2
|
||||||
|
" AddTabularPattern[!] [<buffer>] name /pattern[/format]
|
||||||
|
"
|
||||||
|
" If <buffer> is provided, the command will only be available in the current
|
||||||
|
" buffer, and will be used instead of any global command with the same name.
|
||||||
|
"
|
||||||
|
" If a command with the same name and scope already exists, it is an error,
|
||||||
|
" unless the ! is provided, in which case the existing command will be
|
||||||
|
" replaced.
|
||||||
|
"
|
||||||
|
" pattern is a regex describing the delimiter to be used.
|
||||||
|
"
|
||||||
|
" format describes the format pattern to be used. The default will be used if
|
||||||
|
" none is provided.
|
||||||
|
com! -nargs=+ -bang AddTabularPattern
|
||||||
|
\ call AddTabularPattern(<q-args>, <bang>0)
|
||||||
|
|
||||||
|
function! AddTabularPattern(command, force)
|
||||||
|
try
|
||||||
|
let [ commandmap, rest ] = s:ChooseCommandMap(a:command)
|
||||||
|
|
||||||
|
let name = matchstr(rest, '.\{-}\ze\s*/')
|
||||||
|
let pattern = substitute(rest, '.\{-}\s*\ze/', '', '')
|
||||||
|
|
||||||
|
let [ pattern, format ] = s:ParsePattern(pattern)
|
||||||
|
|
||||||
|
if empty(name) || empty(pattern)
|
||||||
|
throw "Invalid arguments!"
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !a:force && has_key(commandmap, name)
|
||||||
|
throw string(name) . " is already defined, use ! to overwrite."
|
||||||
|
endif
|
||||||
|
|
||||||
|
let command = "tabular#TabularizeStrings(a:lines, " . string(pattern)
|
||||||
|
|
||||||
|
if !empty(format)
|
||||||
|
let command .= ", " . string(format)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let command .= ")"
|
||||||
|
|
||||||
|
let commandmap[name] = { 'pattern' : pattern, 'commands' : [ command ] }
|
||||||
|
catch
|
||||||
|
echohl ErrorMsg
|
||||||
|
echomsg "AddTabularPattern: " . v:exception
|
||||||
|
echohl None
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Command associating a command name with a pipeline of functions {{{2
|
||||||
|
" AddTabularPipeline[!] [<buffer>] name /pattern/ func [ | func2 [ | func3 ] ]
|
||||||
|
"
|
||||||
|
" If <buffer> is provided, the command will only be available in the current
|
||||||
|
" buffer, and will be used instead of any global command with the same name.
|
||||||
|
"
|
||||||
|
" If a command with the same name and scope already exists, it is an error,
|
||||||
|
" unless the ! is provided, in which case the existing command will be
|
||||||
|
" replaced.
|
||||||
|
"
|
||||||
|
" pattern is a regex that will be used to determine which lines will be
|
||||||
|
" filtered. If the cursor line doesn't match the pattern, using the command
|
||||||
|
" will be a no-op, otherwise the cursor and all contiguous lines matching the
|
||||||
|
" pattern will be filtered.
|
||||||
|
"
|
||||||
|
" Each 'func' argument represents a function to be called. This function
|
||||||
|
" will have access to a:lines, a List containing one String per line being
|
||||||
|
" filtered.
|
||||||
|
com! -nargs=+ -bang AddTabularPipeline
|
||||||
|
\ call AddTabularPipeline(<q-args>, <bang>0)
|
||||||
|
|
||||||
|
function! AddTabularPipeline(command, force)
|
||||||
|
try
|
||||||
|
let [ commandmap, rest ] = s:ChooseCommandMap(a:command)
|
||||||
|
|
||||||
|
let name = matchstr(rest, '.\{-}\ze\s*/')
|
||||||
|
let pattern = substitute(rest, '.\{-}\s*\ze/', '', '')
|
||||||
|
|
||||||
|
let commands = matchstr(pattern, '^/.\{-}\\\@<!\%(\\\\\)\{-}/\zs.*')
|
||||||
|
let pattern = matchstr(pattern, '/\zs.\{-}\\\@<!\%(\\\\\)\{-}\ze/')
|
||||||
|
|
||||||
|
if empty(name) || empty(pattern)
|
||||||
|
throw "Invalid arguments!"
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !a:force && has_key(commandmap, name)
|
||||||
|
throw string(name) . " is already defined, use ! to overwrite."
|
||||||
|
endif
|
||||||
|
|
||||||
|
let commandlist = s:SplitCommands(commands)
|
||||||
|
|
||||||
|
if empty(commandlist)
|
||||||
|
throw "Must provide a list of functions!"
|
||||||
|
endif
|
||||||
|
|
||||||
|
let commandmap[name] = { 'pattern' : pattern, 'commands' : commandlist }
|
||||||
|
catch
|
||||||
|
echohl ErrorMsg
|
||||||
|
echomsg "AddTabularPipeline: " . v:exception
|
||||||
|
echohl None
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Tabularize /pattern[/format] {{{2
|
||||||
|
" Tabularize name
|
||||||
|
"
|
||||||
|
" Align text, either using the given pattern, or the command associated with
|
||||||
|
" the given name.
|
||||||
|
com! -nargs=* -range -complete=customlist,<SID>CompleteTabularizeCommand
|
||||||
|
\ Tabularize <line1>,<line2>call Tabularize(<q-args>)
|
||||||
|
|
||||||
|
function! Tabularize(command, ...) range
|
||||||
|
let piperange_opt = {}
|
||||||
|
if a:0
|
||||||
|
let piperange_opt = a:1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if empty(a:command)
|
||||||
|
if !exists("s:last_tabularize_command")
|
||||||
|
echohl ErrorMsg
|
||||||
|
echomsg "Tabularize hasn't been called yet; no pattern/command to reuse!"
|
||||||
|
echohl None
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
let s:last_tabularize_command = a:command
|
||||||
|
endif
|
||||||
|
|
||||||
|
let command = s:last_tabularize_command
|
||||||
|
|
||||||
|
let range = a:firstline . ',' . a:lastline
|
||||||
|
|
||||||
|
try
|
||||||
|
let [ pattern, format ] = s:ParsePattern(command)
|
||||||
|
|
||||||
|
if !empty(pattern)
|
||||||
|
let cmd = "tabular#TabularizeStrings(a:lines, " . string(pattern)
|
||||||
|
|
||||||
|
if !empty(format)
|
||||||
|
let cmd .= "," . string(format)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let cmd .= ")"
|
||||||
|
|
||||||
|
exe range . 'call tabular#PipeRangeWithOptions(pattern, [ cmd ], '
|
||||||
|
\ . 'piperange_opt)'
|
||||||
|
else
|
||||||
|
if exists('b:TabularCommands') && has_key(b:TabularCommands, command)
|
||||||
|
let usercmd = b:TabularCommands[command]
|
||||||
|
elseif has_key(s:TabularCommands, command)
|
||||||
|
let usercmd = s:TabularCommands[command]
|
||||||
|
else
|
||||||
|
throw "Unrecognized command " . string(command)
|
||||||
|
endif
|
||||||
|
|
||||||
|
exe range . 'call tabular#PipeRangeWithOptions(usercmd["pattern"], '
|
||||||
|
\ . 'usercmd["commands"], piperange_opt)'
|
||||||
|
endif
|
||||||
|
catch
|
||||||
|
echohl ErrorMsg
|
||||||
|
echomsg "Tabularize: " . v:exception
|
||||||
|
echohl None
|
||||||
|
return
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" GTabularize /pattern[/format] {{{2
|
||||||
|
" GTabularize name
|
||||||
|
"
|
||||||
|
" Align text on only matching lines, either using the given pattern, or the
|
||||||
|
" command associated with the given name. Mnemonically, this is similar to
|
||||||
|
" the :global command, which takes some action on all rows matching a pattern
|
||||||
|
" in a range. This command is different from normal :Tabularize in 3 ways:
|
||||||
|
" 1) If a line in the range does not match the pattern, it will be left
|
||||||
|
" unchanged, and not in any way affect the outcome of other lines in the
|
||||||
|
" range (at least, normally - but Pipelines can and will still look at
|
||||||
|
" non-matching rows unless they are specifically written to be aware of
|
||||||
|
" tabular#DoGTabularize() and handle it appropriately).
|
||||||
|
" 2) No automatic range determination - :Tabularize automatically expands
|
||||||
|
" a single-line range (or a call with no range) to include all adjacent
|
||||||
|
" matching lines. That behavior does not make sense for this command.
|
||||||
|
" 3) If called without a range, it will act on all lines in the buffer (like
|
||||||
|
" :global) rather than only a single line
|
||||||
|
com! -nargs=* -range=% -complete=customlist,<SID>CompleteTabularizeCommand
|
||||||
|
\ GTabularize <line1>,<line2>
|
||||||
|
\ call Tabularize(<q-args>, { 'mode': 'GTabularize' } )
|
||||||
|
|
||||||
|
" Stupid vimscript crap, part 2 {{{1
|
||||||
|
let &cpo = s:savecpo
|
||||||
|
unlet s:savecpo
|
||||||
|
|
||||||
|
" vim:set sw=2 sts=2 fdm=marker:
|
||||||
73
.vim/plugin/TabularMaps.vim
Normal file
73
.vim/plugin/TabularMaps.vim
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
" Copyright (c) 2016, Matthew J. Wozniski
|
||||||
|
" All rights reserved.
|
||||||
|
"
|
||||||
|
" Redistribution and use in source and binary forms, with or without
|
||||||
|
" modification, are permitted provided that the following conditions are met:
|
||||||
|
" * Redistributions of source code must retain the above copyright notice,
|
||||||
|
" this list of conditions and the following disclaimer.
|
||||||
|
" * Redistributions in binary form must reproduce the above copyright
|
||||||
|
" notice, this list of conditions and the following disclaimer in the
|
||||||
|
" documentation and/or other materials provided with the distribution.
|
||||||
|
" * The names of the contributors may not be used to endorse or promote
|
||||||
|
" products derived from this software without specific prior written
|
||||||
|
" permission.
|
||||||
|
"
|
||||||
|
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
|
||||||
|
" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||||
|
" NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
" OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
if !exists(':Tabularize') || get(g:, 'no_default_tabular_maps', 0)
|
||||||
|
finish " Tabular.vim wasn't loaded or the default maps are unwanted
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:save_cpo = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
AddTabularPattern! assignment /[|&+*/%<>=!~-]\@<!\([<>!=]=\|=\~\)\@![|&+*/%<>=!~-]*=/l1r1
|
||||||
|
AddTabularPattern! two_spaces / /l0
|
||||||
|
|
||||||
|
AddTabularPipeline! multiple_spaces / / map(a:lines, "substitute(v:val, ' *', ' ', 'g')") | tabular#TabularizeStrings(a:lines, ' ', 'l0')
|
||||||
|
|
||||||
|
AddTabularPipeline! argument_list /(.*)/ map(a:lines, 'substitute(v:val, ''\s*\([(,)]\)\s*'', ''\1'', ''g'')')
|
||||||
|
\ | tabular#TabularizeStrings(a:lines, '[(,)]', 'l0')
|
||||||
|
\ | map(a:lines, 'substitute(v:val, ''\(\s*\),'', '',\1 '', "g")')
|
||||||
|
\ | map(a:lines, 'substitute(v:val, ''\s*)'', ")", "g")')
|
||||||
|
|
||||||
|
function! SplitCDeclarations(lines)
|
||||||
|
let rv = []
|
||||||
|
for line in a:lines
|
||||||
|
" split the line into declaractions
|
||||||
|
let split = split(line, '\s*[,;]\s*')
|
||||||
|
" separate the type from the first declaration
|
||||||
|
let type = substitute(split[0], '\%(\%([&*]\s*\)*\)\=\k\+$', '', '')
|
||||||
|
" add the ; back on every declaration
|
||||||
|
call map(split, 'v:val . ";"')
|
||||||
|
" add the first element to the return as-is, and remove it from the list
|
||||||
|
let rv += [ remove(split, 0) ]
|
||||||
|
" transform the other elements by adding the type on at the beginning
|
||||||
|
call map(split, 'type . v:val')
|
||||||
|
" and add them all to the return
|
||||||
|
let rv += split
|
||||||
|
endfor
|
||||||
|
return rv
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
AddTabularPipeline! split_declarations /,.*;/ SplitCDeclarations(a:lines)
|
||||||
|
|
||||||
|
AddTabularPattern! ternary_operator /^.\{-}\zs?\|:/l1
|
||||||
|
|
||||||
|
AddTabularPattern! cpp_io /<<\|>>/l1
|
||||||
|
|
||||||
|
AddTabularPattern! pascal_assign /:=/l1
|
||||||
|
|
||||||
|
AddTabularPattern! trailing_c_comments /\/\*\|\*\/\|\/\//l1
|
||||||
|
|
||||||
|
let &cpo = s:save_cpo
|
||||||
|
unlet s:save_cpo
|
||||||
184
.vim/syntax/markdown.vim
Normal file
184
.vim/syntax/markdown.vim
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
" Vim syntax file
|
||||||
|
" Language: Markdown
|
||||||
|
" Maintainer: Ben Williams <benw@plasticboy.com>
|
||||||
|
" URL: http://plasticboy.com/markdown-vim-mode/
|
||||||
|
" Remark: Uses HTML syntax file
|
||||||
|
" TODO: Handle stuff contained within stuff (e.g. headings within blockquotes)
|
||||||
|
|
||||||
|
|
||||||
|
" Read the HTML syntax to start with
|
||||||
|
if version < 600
|
||||||
|
so <sfile>:p:h/html.vim
|
||||||
|
else
|
||||||
|
runtime! syntax/html.vim
|
||||||
|
|
||||||
|
if exists('b:current_syntax')
|
||||||
|
unlet b:current_syntax
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if version < 600
|
||||||
|
syntax clear
|
||||||
|
elseif exists("b:current_syntax")
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
" don't use standard HiLink, it will not work with included syntax files
|
||||||
|
if version < 508
|
||||||
|
command! -nargs=+ HtmlHiLink hi link <args>
|
||||||
|
else
|
||||||
|
command! -nargs=+ HtmlHiLink hi def link <args>
|
||||||
|
endif
|
||||||
|
|
||||||
|
syn spell toplevel
|
||||||
|
syn case ignore
|
||||||
|
syn sync linebreaks=1
|
||||||
|
|
||||||
|
let s:conceal = ''
|
||||||
|
let s:concealends = ''
|
||||||
|
let s:concealcode = ''
|
||||||
|
if has('conceal') && get(g:, 'vim_markdown_conceal', 1)
|
||||||
|
let s:conceal = ' conceal'
|
||||||
|
let s:concealends = ' concealends'
|
||||||
|
endif
|
||||||
|
if has('conceal') && get(g:, 'vim_markdown_conceal_code_blocks', 1)
|
||||||
|
let s:concealcode = ' concealends'
|
||||||
|
endif
|
||||||
|
|
||||||
|
" additions to HTML groups
|
||||||
|
if get(g:, 'vim_markdown_emphasis_multiline', 1)
|
||||||
|
let s:oneline = ''
|
||||||
|
else
|
||||||
|
let s:oneline = ' oneline'
|
||||||
|
endif
|
||||||
|
syn region mkdItalic matchgroup=mkdItalic start="\%(\*\|_\)" end="\%(\*\|_\)"
|
||||||
|
syn region mkdBold matchgroup=mkdBold start="\%(\*\*\|__\)" end="\%(\*\*\|__\)"
|
||||||
|
syn region mkdBoldItalic matchgroup=mkdBoldItalic start="\%(\*\*\*\|___\)" end="\%(\*\*\*\|___\)"
|
||||||
|
execute 'syn region htmlItalic matchgroup=mkdItalic start="\%(^\|\s\)\zs\*\ze[^\\\*\t ]\%(\%([^*]\|\\\*\|\n\)*[^\\\*\t ]\)\?\*\_W" end="[^\\\*\t ]\zs\*\ze\_W" keepend contains=@Spell' . s:oneline . s:concealends
|
||||||
|
execute 'syn region htmlItalic matchgroup=mkdItalic start="\%(^\|\s\)\zs_\ze[^\\_\t ]" end="[^\\_\t ]\zs_\ze\_W" keepend contains=@Spell' . s:oneline . s:concealends
|
||||||
|
execute 'syn region htmlBold matchgroup=mkdBold start="\%(^\|\s\)\zs\*\*\ze\S" end="\S\zs\*\*" keepend contains=@Spell' . s:oneline . s:concealends
|
||||||
|
execute 'syn region htmlBold matchgroup=mkdBold start="\%(^\|\s\)\zs__\ze\S" end="\S\zs__" keepend contains=@Spell' . s:oneline . s:concealends
|
||||||
|
execute 'syn region htmlBoldItalic matchgroup=mkdBoldItalic start="\%(^\|\s\)\zs\*\*\*\ze\S" end="\S\zs\*\*\*" keepend contains=@Spell' . s:oneline . s:concealends
|
||||||
|
execute 'syn region htmlBoldItalic matchgroup=mkdBoldItalic start="\%(^\|\s\)\zs___\ze\S" end="\S\zs___" keepend contains=@Spell' . s:oneline . s:concealends
|
||||||
|
|
||||||
|
" [link](URL) | [link][id] | [link][] | 
|
||||||
|
syn region mkdFootnotes matchgroup=mkdDelimiter start="\[^" end="\]"
|
||||||
|
execute 'syn region mkdID matchgroup=mkdDelimiter start="\[" end="\]" contained oneline' . s:conceal
|
||||||
|
execute 'syn region mkdURL matchgroup=mkdDelimiter start="(" end=")" contained oneline' . s:conceal
|
||||||
|
execute 'syn region mkdLink matchgroup=mkdDelimiter start="\\\@<!!\?\[\ze[^]\n]*\n\?[^]\n]*\][[(]" end="\]" contains=@mkdNonListItem,@Spell nextgroup=mkdURL,mkdID skipwhite' . s:concealends
|
||||||
|
|
||||||
|
" Autolink without angle brackets.
|
||||||
|
" mkd inline links: protocol optional user:pass@ sub/domain .com, .co.uk, etc optional port path/querystring/hash fragment
|
||||||
|
" ------------ _____________________ ----------------------------- _________________________ ----------------- __
|
||||||
|
syn match mkdInlineURL /https\?:\/\/\(\w\+\(:\w\+\)\?@\)\?\([A-Za-z0-9][-_0-9A-Za-z]*\.\)\{1,}\(\w\{2,}\.\?\)\{1,}\(:[0-9]\{1,5}\)\?\S*/
|
||||||
|
|
||||||
|
" Autolink with parenthesis.
|
||||||
|
syn region mkdInlineURL matchgroup=mkdDelimiter start="(\(https\?:\/\/\(\w\+\(:\w\+\)\?@\)\?\([A-Za-z0-9][-_0-9A-Za-z]*\.\)\{1,}\(\w\{2,}\.\?\)\{1,}\(:[0-9]\{1,5}\)\?\S*)\)\@=" end=")"
|
||||||
|
|
||||||
|
" Autolink with angle brackets.
|
||||||
|
syn region mkdInlineURL matchgroup=mkdDelimiter start="\\\@<!<\ze[a-z][a-z0-9,.-]\{1,22}:\/\/[^> ]*>" end=">"
|
||||||
|
|
||||||
|
" Link definitions: [id]: URL (Optional Title)
|
||||||
|
syn region mkdLinkDef matchgroup=mkdDelimiter start="^ \{,3}\zs\[\^\@!" end="]:" oneline nextgroup=mkdLinkDefTarget skipwhite
|
||||||
|
syn region mkdLinkDefTarget start="<\?\zs\S" excludenl end="\ze[>[:space:]\n]" contained nextgroup=mkdLinkTitle,mkdLinkDef skipwhite skipnl oneline
|
||||||
|
syn region mkdLinkTitle matchgroup=mkdDelimiter start=+"+ end=+"+ contained
|
||||||
|
syn region mkdLinkTitle matchgroup=mkdDelimiter start=+'+ end=+'+ contained
|
||||||
|
syn region mkdLinkTitle matchgroup=mkdDelimiter start=+(+ end=+)+ contained
|
||||||
|
|
||||||
|
"HTML headings
|
||||||
|
syn region htmlH1 matchgroup=mkdHeading start="^\s*#" end="$" contains=mkdLink,mkdInlineURL,@Spell
|
||||||
|
syn region htmlH2 matchgroup=mkdHeading start="^\s*##" end="$" contains=mkdLink,mkdInlineURL,@Spell
|
||||||
|
syn region htmlH3 matchgroup=mkdHeading start="^\s*###" end="$" contains=mkdLink,mkdInlineURL,@Spell
|
||||||
|
syn region htmlH4 matchgroup=mkdHeading start="^\s*####" end="$" contains=mkdLink,mkdInlineURL,@Spell
|
||||||
|
syn region htmlH5 matchgroup=mkdHeading start="^\s*#####" end="$" contains=mkdLink,mkdInlineURL,@Spell
|
||||||
|
syn region htmlH6 matchgroup=mkdHeading start="^\s*######" end="$" contains=mkdLink,mkdInlineURL,@Spell
|
||||||
|
syn match htmlH1 /^.\+\n=\+$/ contains=mkdLink,mkdInlineURL,@Spell
|
||||||
|
syn match htmlH2 /^.\+\n-\+$/ contains=mkdLink,mkdInlineURL,@Spell
|
||||||
|
|
||||||
|
"define Markdown groups
|
||||||
|
syn match mkdLineBreak / \+$/
|
||||||
|
syn region mkdBlockquote start=/^\s*>/ end=/$/ contains=mkdLink,mkdInlineURL,mkdLineBreak,@Spell
|
||||||
|
execute 'syn region mkdCode matchgroup=mkdCodeDelimiter start=/\(\([^\\]\|^\)\\\)\@<!`/ end=/`/' . s:concealcode
|
||||||
|
execute 'syn region mkdCode matchgroup=mkdCodeDelimiter start=/\(\([^\\]\|^\)\\\)\@<!``/ skip=/[^`]`[^`]/ end=/\(\([^\\]\|^\)\\\)\@<!``/' . s:concealcode
|
||||||
|
execute 'syn region mkdCode matchgroup=mkdCodeDelimiter start=/^\s*\z(`\{3,}\)[^`]*$/ end=/^\s*\z1`*\s*$/' . s:concealcode
|
||||||
|
execute 'syn region mkdCode matchgroup=mkdCodeDelimiter start=/\(\([^\\]\|^\)\\\)\@<!\~\~/ end=/\(\([^\\]\|^\)\\\)\@<!\~\~/' . s:concealcode
|
||||||
|
execute 'syn region mkdCode matchgroup=mkdCodeDelimiter start=/^\s*\z(\~\{3,}\)\s*[0-9A-Za-z_+-]*\s*$/ end=/^\s*\z1\~*\s*$/' . s:concealcode
|
||||||
|
execute 'syn region mkdCode matchgroup=mkdCodeDelimiter start="<pre[^>]*\\\@<!>" end="</pre>"' . s:concealcode
|
||||||
|
execute 'syn region mkdCode matchgroup=mkdCodeDelimiter start="<code[^>]*\\\@<!>" end="</code>"' . s:concealcode
|
||||||
|
syn region mkdFootnote start="\[^" end="\]"
|
||||||
|
syn match mkdCode /^\s*\n\(\(\s\{8,}[^ ]\|\t\t\+[^\t]\).*\n\)\+/
|
||||||
|
syn match mkdCode /\%^\(\(\s\{4,}[^ ]\|\t\+[^\t]\).*\n\)\+/
|
||||||
|
syn match mkdCode /^\s*\n\(\(\s\{4,}[^ ]\|\t\+[^\t]\).*\n\)\+/ contained
|
||||||
|
syn match mkdListItem /^\s*\%([-*+]\|\d\+\.\)\ze\s\+/ contained
|
||||||
|
syn region mkdListItemLine start="^\s*\%([-*+]\|\d\+\.\)\s\+" end="$" oneline contains=@mkdNonListItem,mkdListItem,@Spell
|
||||||
|
syn region mkdNonListItemBlock start="\(\%^\(\s*\([-*+]\|\d\+\.\)\s\+\)\@!\|\n\(\_^\_$\|\s\{4,}[^ ]\|\t+[^\t]\)\@!\)" end="^\(\s*\([-*+]\|\d\+\.\)\s\+\)\@=" contains=@mkdNonListItem,@Spell
|
||||||
|
syn match mkdRule /^\s*\*\s\{0,1}\*\s\{0,1}\*\(\*\|\s\)*$/
|
||||||
|
syn match mkdRule /^\s*-\s\{0,1}-\s\{0,1}-\(-\|\s\)*$/
|
||||||
|
syn match mkdRule /^\s*_\s\{0,1}_\s\{0,1}_\(_\|\s\)*$/
|
||||||
|
|
||||||
|
" YAML frontmatter
|
||||||
|
if get(g:, 'vim_markdown_frontmatter', 0)
|
||||||
|
syn include @yamlTop syntax/yaml.vim
|
||||||
|
syn region Comment matchgroup=mkdDelimiter start="\%^---$" end="^\(---\|\.\.\.\)$" contains=@yamlTop keepend
|
||||||
|
unlet! b:current_syntax
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(g:, 'vim_markdown_toml_frontmatter', 0)
|
||||||
|
try
|
||||||
|
syn include @tomlTop syntax/toml.vim
|
||||||
|
syn region Comment matchgroup=mkdDelimiter start="\%^+++$" end="^+++$" transparent contains=@tomlTop keepend
|
||||||
|
unlet! b:current_syntax
|
||||||
|
catch /E484/
|
||||||
|
syn region Comment matchgroup=mkdDelimiter start="\%^+++$" end="^+++$"
|
||||||
|
endtry
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(g:, 'vim_markdown_json_frontmatter', 0)
|
||||||
|
try
|
||||||
|
syn include @jsonTop syntax/json.vim
|
||||||
|
syn region Comment matchgroup=mkdDelimiter start="\%^{$" end="^}$" contains=@jsonTop keepend
|
||||||
|
unlet! b:current_syntax
|
||||||
|
catch /E484/
|
||||||
|
syn region Comment matchgroup=mkdDelimiter start="\%^{$" end="^}$"
|
||||||
|
endtry
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(g:, 'vim_markdown_math', 0)
|
||||||
|
syn include @tex syntax/tex.vim
|
||||||
|
syn region mkdMath start="\\\@<!\$" end="\$" skip="\\\$" contains=@tex keepend
|
||||||
|
syn region mkdMath start="\\\@<!\$\$" end="\$\$" skip="\\\$" contains=@tex keepend
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Strike through
|
||||||
|
if get(g:, 'vim_markdown_strikethrough', 0)
|
||||||
|
syn region mkdStrike matchgroup=mkdStrike start="\%(\~\~\)" end="\%(\~\~\)"
|
||||||
|
HtmlHiLink mkdStrike htmlStrike
|
||||||
|
endif
|
||||||
|
|
||||||
|
syn cluster mkdNonListItem contains=@htmlTop,htmlItalic,htmlBold,htmlBoldItalic,mkdFootnotes,mkdInlineURL,mkdLink,mkdLinkDef,mkdLineBreak,mkdBlockquote,mkdCode,mkdRule,htmlH1,htmlH2,htmlH3,htmlH4,htmlH5,htmlH6,mkdMath
|
||||||
|
|
||||||
|
"highlighting for Markdown groups
|
||||||
|
HtmlHiLink mkdString String
|
||||||
|
HtmlHiLink mkdCode String
|
||||||
|
HtmlHiLink mkdCodeDelimiter String
|
||||||
|
HtmlHiLink mkdCodeStart String
|
||||||
|
HtmlHiLink mkdCodeEnd String
|
||||||
|
HtmlHiLink mkdFootnote Comment
|
||||||
|
HtmlHiLink mkdBlockquote Comment
|
||||||
|
HtmlHiLink mkdListItem Identifier
|
||||||
|
HtmlHiLink mkdRule Identifier
|
||||||
|
HtmlHiLink mkdLineBreak Visual
|
||||||
|
HtmlHiLink mkdFootnotes htmlLink
|
||||||
|
HtmlHiLink mkdLink htmlLink
|
||||||
|
HtmlHiLink mkdURL htmlString
|
||||||
|
HtmlHiLink mkdInlineURL htmlLink
|
||||||
|
HtmlHiLink mkdID Identifier
|
||||||
|
HtmlHiLink mkdLinkDef mkdID
|
||||||
|
HtmlHiLink mkdLinkDefTarget mkdURL
|
||||||
|
HtmlHiLink mkdLinkTitle htmlString
|
||||||
|
HtmlHiLink mkdDelimiter Delimiter
|
||||||
|
|
||||||
|
let b:current_syntax = "mkd"
|
||||||
|
|
||||||
|
delcommand HtmlHiLink
|
||||||
|
" vim: ts=8
|
||||||
Loading…
Reference in New Issue
Block a user