1
0
Fork 0
mirror of synced 2024-12-23 23:33:21 -05:00

Updated plugins and added vim-markdown

This commit is contained in:
Amir Salihefendic 2018-02-04 12:35:08 +01:00
parent 2514de5b22
commit 8eeefe86c2
111 changed files with 6623 additions and 923 deletions

View file

@ -439,6 +439,14 @@ fu! ctrlp#addfile(ch, file)
cal s:BuildPrompt(1)
endf
fu! s:safe_printf(format, ...)
try
retu call('printf', [a:format] + a:000)
cat
retu a:format
endt
endf
fu! s:UserCmd(lscmd)
let [path, lscmd] = [s:dyncwd, a:lscmd]
let do_ign =
@ -461,9 +469,9 @@ fu! s:UserCmd(lscmd)
let g:ctrlp_allfiles = []
let s:job = job_start([&shell, &shellcmdflag, printf(lscmd, path)], {'callback': 'ctrlp#addfile'})
elsei has('patch-7.4-597') && !(has('win32') || has('win64'))
let g:ctrlp_allfiles = systemlist(printf(lscmd, path))
let g:ctrlp_allfiles = systemlist(s:safe_printf(lscmd, path))
el
let g:ctrlp_allfiles = split(system(printf(lscmd, path)), "\n")
let g:ctrlp_allfiles = split(system(s:safe_printf(lscmd, path)), "\n")
en
if exists('+ssl') && exists('ssl')
let &ssl = ssl

View file

@ -59,9 +59,11 @@ fu! ctrlp#line#accept(dict)
let bufnr = str2nr(get(info, 1))
if bufnr
cal ctrlp#acceptfile(mode, bufnr, get(info, 2))
let @/ = input
call search(input, 'c')
call histadd("search", input)
if !empty(input)
let @/ = input
call search(input, 'c')
call histadd("search", input)
en
en
endf

View file

@ -51,7 +51,7 @@ landscape is my colorscheme, which is a high-contrast cui-supported colorscheme,
+ [vim-airline](https://github.com/vim-airline/vim-airline) is a nice plugin, but it uses too much functions of other plugins, which should be done by users in `.vimrc`.
## Spirit of this plugin
+ Minimalism. The core script is very small to achive enough functions as a statusline plugin.
+ Minimalism. The core script is very small to achieve enough functions as a statusline plugin.
+ Configurability. You can create your own component and easily add to the statusline and the tabline.
+ Orthogonality. The plugin does not rely on the implementation of other plugins. Such plugin crossing settings should be configured by users.
@ -110,7 +110,7 @@ if !has('gui_running')
endif
```
Your statusline appears to work correctly? If yes, great, thanks for choosing lightline.vim! If no, please file a issue report to the [issue tracker](https://github.com/itchyny/lightline.vim/issues).
Your statusline appears to work correctly? If yes, great, thanks for choosing lightline.vim! If no, please file an issue report to the [issue tracker](https://github.com/itchyny/lightline.vim/issues).
By the way, `-- INSERT --` is unnecessary anymore because the mode information is displayed in the statusline.
![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/13.png)

View file

@ -2,7 +2,7 @@
" Filename: autoload/lightline.vim
" Author: itchyny
" License: MIT License
" Last Change: 2017/11/11 13:29:26.
" Last Change: 2017/12/31 15:55:00.
" =============================================================================
let s:save_cpo = &cpo
@ -84,20 +84,20 @@ endfunction
let s:_lightline = {
\ 'active': {
\ 'left': [ [ 'mode', 'paste' ], [ 'readonly', 'filename', 'modified' ] ],
\ 'right': [ [ 'lineinfo' ], [ 'percent' ], [ 'fileformat', 'fileencoding', 'filetype' ] ]
\ 'left': [['mode', 'paste'], ['readonly', 'filename', 'modified']],
\ 'right': [['lineinfo'], ['percent'], ['fileformat', 'fileencoding', 'filetype']]
\ },
\ 'inactive': {
\ 'left': [ [ 'filename' ] ],
\ 'right': [ [ 'lineinfo' ], [ 'percent' ] ]
\ 'left': [['filename']],
\ 'right': [['lineinfo'], ['percent']]
\ },
\ 'tabline': {
\ 'left': [ [ 'tabs' ] ],
\ 'right': [ [ 'close' ] ]
\ 'left': [['tabs']],
\ 'right': [['close']]
\ },
\ 'tab': {
\ 'active': [ 'tabnum', 'filename', 'modified' ],
\ 'inactive': [ 'tabnum', 'filename', 'modified' ]
\ 'active': ['tabnum', 'filename', 'modified'],
\ 'inactive': ['tabnum', 'filename', 'modified']
\ },
\ 'component': {
\ 'mode': '%{lightline#mode()}',
@ -295,7 +295,7 @@ function! lightline#highlight(...) abort
endfunction
function! s:subseparator(components, subseparator, expanded) abort
let [a, c, f, v, u ] = [ a:components, s:lightline.component, s:lightline.component_function, s:lightline.component_visible_condition, s:lightline.component_function_visible_condition ]
let [a, c, f, v, u] = [a:components, s:lightline.component, s:lightline.component_function, s:lightline.component_visible_condition, s:lightline.component_function_visible_condition]
let xs = map(range(len(a:components)), 'a:expanded[v:val] ? "1" :
\ has_key(f, a[v:val]) ? (has_key(u, a[v:val]) ? "(".u[a[v:val]].")" : (exists("*".f[a[v:val]]) ? "" : "exists(\"*".f[a[v:val]]."\")&&").f[a[v:val]]."()!=#\"\"") :
\ has_key(v, a[v:val]) ? "(".v[a[v:val]].")" : has_key(c, a[v:val]) ? "1" : "0"')

View file

@ -0,0 +1,40 @@
" =============================================================================
" Filename: autoload/lightline/colorscheme/deus.vim
" Author: nikersify
" License: MIT License
" Last Change: 2018/01/24 13:26:00
" =============================================================================
let s:term_red = 204
let s:term_green = 114
let s:term_yellow = 180
let s:term_blue = 39
let s:term_purple = 170
let s:term_white = 145
let s:term_black = 235
let s:term_grey = 236
let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}}
let s:p.normal.left = [ [ '#292c33', '#98c379', s:term_black, s:term_green, 'bold' ], [ '#98c379', '#292c33', s:term_green, s:term_black ] ]
let s:p.normal.right = [ [ '#292c33', '#98c379', s:term_black, s:term_green ], [ '#abb2bf', '#3e4452', s:term_white, s:term_grey ], [ '#98c379', '#292c33', s:term_green, s:term_black ] ]
let s:p.inactive.right = [ [ '#292c33', '#61afef', s:term_black, s:term_blue], [ '#abb2bf', '#3e4452', s:term_white, s:term_grey ] ]
let s:p.inactive.left = s:p.inactive.right[1:]
" her
let s:p.insert.left = [ [ '#292c33', '#61afef', s:term_black, s:term_blue, 'bold' ], [ '#61afef', '#292c33', s:term_blue, s:term_black ] ]
let s:p.insert.right = [ [ '#292c33', '#61afef', s:term_black, s:term_blue ], [ '#ABB2BF', '#3E4452', s:term_white, s:term_grey ], [ '#61afef', '#292c33', s:term_blue, s:term_black ] ]
let s:p.replace.left = [ [ '#292c33', '#e06c75', s:term_black, s:term_red, 'bold' ], [ '#e06c75', '#292c33', s:term_red, s:term_black ] ]
let s:p.replace.right = [ [ '#292c33', '#e06c75', s:term_black, s:term_red, 'bold' ], s:p.normal.right[1], [ '#e06c75', '#292c33', s:term_red, s:term_black ] ]
let s:p.visual.left = [ [ '#292c33', '#c678dd', s:term_black, s:term_purple, 'bold' ], [ '#c678dd', '#292c33', s:term_purple, s:term_black ] ]
let s:p.visual.right = [ [ '#292c33', '#c678dd', s:term_black, s:term_purple, 'bold' ], s:p.normal.right[1], [ '#c678dd', '#292c33', s:term_purple, s:term_black ] ]
let s:p.normal.middle = [ [ '#abb2bf', '#292c33', s:term_white, s:term_black ] ]
let s:p.insert.middle = s:p.normal.middle
let s:p.replace.middle = s:p.normal.middle
let s:p.tabline.left = [ s:p.normal.left[1] ]
let s:p.tabline.tabsel = [ s:p.normal.left[0] ]
let s:p.tabline.middle = s:p.normal.middle
let s:p.tabline.right = [ s:p.normal.left[1] ]
let s:p.normal.error = [ [ '#292c33', '#e06c75', s:term_black, s:term_red ] ]
let s:p.normal.warning = [ [ '#292c33', '#e5c07b', s:term_black, s:term_yellow ] ]
let g:lightline#colorscheme#deus#palette = lightline#colorscheme#fill(s:p)

View file

@ -4,7 +4,7 @@ Version: 0.1
Author: itchyny (https://github.com/itchyny)
License: MIT License
Repository: https://github.com/itchyny/lightline.vim
Last Change: 2017/11/18 20:07:05.
Last Change: 2017/12/24 21:34:15.
CONTENTS *lightline-contents*
@ -29,7 +29,7 @@ The *lightline* plugin is a light and configurable statusline/tabline for Vim.
SPIRIT *lightline-spirit*
Minimalism
The core script is very small to achive enough functions as a
The core script is very small to achieve enough functions as a
statusline plugin.
Configurability
@ -157,7 +157,7 @@ OPTIONS *lightline-option*
A dictionary to store the visible conditions of the function
components. Each expression should correspond to the condition
each component is not empty. This configuration is used to
control the visibility of the subseparators. You can use this
control the visibility of the sub-separators. You can use this
configuration to reduce the number of function calls for
performance improvement by setting the value 1 (to tell lightline
that the component is always visible).
@ -229,7 +229,8 @@ OPTIONS *lightline-option*
Currently, wombat, solarized, powerline, jellybeans, Tomorrow,
Tomorrow_Night, Tomorrow_Night_Blue, Tomorrow_Night_Eighties,
PaperColor, seoul256, landscape, one, Dracula, darcula,
molokai, materia, material, OldHope, nord and 16color are available.
molokai, materia, material, OldHope, nord, 16color and deus
are available.
The default value is:
>
let g:lightline.colorscheme = 'default'
@ -1200,7 +1201,7 @@ Problem 11: *lightline-problem-11*
Problem 12: *lightline-problem-12*
How to make the plus sign red like |powerline|?
Use the following setings.
Use the following settings.
>
let g:lightline = {
\ 'component': {

View file

@ -21,7 +21,7 @@ Installation
git clone https://github.com/scrooloose/nerdtree.git ~/.vim/bundle/nerdtree
Then reload Vim, run `:helptags ~/.vim/bundle/nerdtree/doc/`, and check out `:help NERDTree.txt`.
Then reload Vim, run `:helptags ~/.vim/bundle/nerdtree/doc/` or `:Helptags`, and check out `:help NERDTree.txt`.
#### [apt-vim](https://github.com/egalpin/apt-vim)

View file

@ -261,62 +261,50 @@ function! s:displayHelp()
call b:NERDTree.ui.centerView()
endfunction
" FUNCTION: s:findAndRevealPath(path) {{{1
function! s:findAndRevealPath(path)
let l:path = a:path
" FUNCTION: s:findAndRevealPath(pathStr) {{{1
function! s:findAndRevealPath(pathStr)
let l:pathStr = !empty(a:pathStr) ? a:pathStr : expand('%:p')
if empty(l:path)
let l:path = expand('%:p')
if empty(l:pathStr)
call nerdtree#echoWarning('no file for the current buffer')
return
endif
try
let p = g:NERDTreePath.New(l:path)
let l:pathObj = g:NERDTreePath.New(l:pathStr)
catch /^NERDTree.InvalidArgumentsError/
call nerdtree#echo("no file for the current buffer")
call nerdtree#echoWarning('invalid path')
return
endtry
if p.isUnixHiddenPath()
let showhidden=g:NERDTreeShowHidden
let g:NERDTreeShowHidden = 1
endif
if !g:NERDTree.ExistsForTab()
try
let cwd = g:NERDTreePath.New(getcwd())
let l:cwd = g:NERDTreePath.New(getcwd())
catch /^NERDTree.InvalidArgumentsError/
call nerdtree#echo("current directory does not exist.")
let cwd = p.getParent()
call nerdtree#echo('current directory does not exist.')
let l:cwd = l:pathObj.getParent()
endtry
if p.isUnder(cwd)
call g:NERDTreeCreator.CreateTabTree(cwd.str())
if l:pathObj.isUnder(l:cwd)
call g:NERDTreeCreator.CreateTabTree(l:cwd.str())
else
call g:NERDTreeCreator.CreateTabTree(p.getParent().str())
call g:NERDTreeCreator.CreateTabTree(l:pathObj.getParent().str())
endif
else
if !p.isUnder(g:NERDTreeFileNode.GetRootForTab().path)
if !g:NERDTree.IsOpen()
call g:NERDTreeCreator.ToggleTabTree('')
else
call g:NERDTree.CursorToTreeWin()
endif
call b:NERDTree.ui.setShowHidden(g:NERDTreeShowHidden)
call s:chRoot(g:NERDTreeDirNode.New(p.getParent(), b:NERDTree))
else
if !g:NERDTree.IsOpen()
call g:NERDTreeCreator.ToggleTabTree("")
endif
NERDTreeFocus
if !l:pathObj.isUnder(b:NERDTree.root.path)
call s:chRoot(g:NERDTreeDirNode.New(l:pathObj.getParent(), b:NERDTree))
endif
endif
call g:NERDTree.CursorToTreeWin()
let node = b:NERDTree.root.reveal(p)
call b:NERDTree.render()
call node.putCursorHere(1,0)
if p.isUnixHiddenFile()
let g:NERDTreeShowHidden = showhidden
if l:pathObj.isHiddenUnder(b:NERDTree.root.path)
call b:NERDTree.ui.setShowHidden(1)
endif
let l:node = b:NERDTree.root.reveal(l:pathObj)
call b:NERDTree.render()
call l:node.putCursorHere(1, 0)
endfunction
"FUNCTION: s:handleLeftClick() {{{1

View file

@ -126,20 +126,20 @@ The following features and functionality are provided by the NERD tree:
Changes made to one tree are reflected in both as they are actually the
same buffer.
If only one other NERD tree exists, that tree is automatically mirrored. If
more than one exists, the script will ask which tree to mirror.
If only one other NERD tree exists, that tree is automatically mirrored.
If more than one exists, the script will ask which tree to mirror.
:NERDTreeClose *:NERDTreeClose*
Close the NERD tree in this tab.
:NERDTreeFind *:NERDTreeFind*
Find the current file in the tree.
:NERDTreeFind [<path>] *:NERDTreeFind*
Without the optional argument, find and reveal the file for the active
buffer in the NERDTree window. With the <path> argument, find and
reveal the specified path.
If no tree exists and the current file is under vim's CWD, then init a
tree at the CWD and reveal the file. Otherwise init a tree in the current
file's directory.
In any case, the current file is revealed and the cursor is placed on it.
Focus will be shifted to the NERDTree window, and the cursor will be
placed on the tree node for the determined path. If a NERDTree for the
current tab does not exist, a new one will be initialized.
:NERDTreeCWD *:NERDTreeCWD*
Change tree root to current directory. If no NERD tree exists for this
@ -996,17 +996,16 @@ Other examples: >
------------------------------------------------------------------------------
*'NERDTreeStatusline'*
Values: Any valid statusline setting.
Default: %{b:NERDTree.root.path.strForOS(0)}
Values: Any valid |'statusline'| setting.
Default: %{exists('b:NERDTree')?b:NERDTree.root.path.str():''}
Tells the script what to use as the |'statusline'| setting for NERD tree
windows.
Defines the value for the |'statusline'| setting in NERDTree windows.
Note that the statusline is set using |:let-&| not |:set| so escaping spaces
isn't necessary.
Note: The setting is actually applied using |:let-&|, not |:set|, so
escaping spaces is not necessary.
Setting this option to -1 will will deactivate it so that your global
statusline setting is used instead.
|'statusline'| setting is used.
------------------------------------------------------------------------------
*'NERDTreeWinPos'*
@ -1128,13 +1127,12 @@ NERDTreeAddKeyMap({options}) *NERDTreeAddKeyMap()*
Additionally, a "scope" argument may be supplied. This constrains the
mapping so that it is only activated if the cursor is on a certain object.
That object is then passed into the handling method. Possible values are:
"FileNode" - a file node
"DirNode" - a directory node
"Node" - a file or directory node
"Bookmark" - A bookmark
"all" - the keymap is not constrained to any scope (default). When
thei is used, the handling function is not passed any arguments.
"FileNode" .... a file node
"DirNode" ..... a directory node
"Node" ........ a file node OR a directory node
"Bookmark" .... a bookmark
"all" ......... global scope; handler receives no arguments (default)
Example: >
call NERDTreeAddKeyMap({

View file

@ -54,3 +54,5 @@ function! s:FlagSet.renderToString()
return '[' . flagstring . ']'
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View file

@ -38,17 +38,26 @@ function! s:NERDTree.Close()
endif
if winnr("$") != 1
" Use the window ID to identify the currently active window or fall
" back on the buffer ID if win_getid/win_gotoid are not available, in
" which case we'll focus an arbitrary window showing the buffer.
let l:useWinId = exists('*win_getid') && exists('*win_gotoid')
if winnr() == s:NERDTree.GetWinNum()
call nerdtree#exec("wincmd p")
let bufnr = bufnr("")
let l:activeBufOrWin = l:useWinId ? win_getid() : bufnr("")
call nerdtree#exec("wincmd p")
else
let bufnr = bufnr("")
let l:activeBufOrWin = l:useWinId ? win_getid() : bufnr("")
endif
call nerdtree#exec(s:NERDTree.GetWinNum() . " wincmd w")
close
call nerdtree#exec(bufwinnr(bufnr) . " wincmd w")
if l:useWinId
call nerdtree#exec("call win_gotoid(" . l:activeBufOrWin . ")")
else
call nerdtree#exec(bufwinnr(l:activeBufOrWin) . " wincmd w")
endif
else
close
endif
@ -195,3 +204,5 @@ endfunction
function! s:NERDTree.render()
call self.ui.render()
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View file

@ -32,4 +32,3 @@ function! s:Notifier.GetListenersForEvent(name)
endfunction
let g:NERDTreePathNotifier = deepcopy(s:Notifier)

View file

@ -14,21 +14,23 @@ lockvar s:NERDTreeSortStarIndex
let s:Path = {}
let g:NERDTreePath = s:Path
" FUNCTION: Path.AbsolutePathFor(str) {{{1
function! s:Path.AbsolutePathFor(str)
let prependCWD = 0
" FUNCTION: Path.AbsolutePathFor(pathStr) {{{1
function! s:Path.AbsolutePathFor(pathStr)
let l:prependWorkingDir = 0
if nerdtree#runningWindows()
let prependCWD = a:str !~# '^.:\(\\\|\/\)' && a:str !~# '^\(\\\\\|\/\/\)'
let l:prependWorkingDir = a:pathStr !~# '^.:\(\\\|\/\)' && a:pathStr !~# '^\(\\\\\|\/\/\)'
else
let prependCWD = a:str !~# '^/'
let l:prependWorkingDir = a:pathStr !~# '^/'
endif
let toReturn = a:str
if prependCWD
let toReturn = getcwd() . s:Path.Slash() . a:str
let l:result = a:pathStr
if l:prependWorkingDir
let l:result = getcwd() . s:Path.Slash() . a:pathStr
endif
return toReturn
return l:result
endfunction
" FUNCTION: Path.bookmarkNames() {{{1
@ -405,6 +407,25 @@ function! s:Path.getSortKey()
return self._sortKey
endfunction
" FUNCTION: Path.isHiddenUnder(path) {{{1
function! s:Path.isHiddenUnder(path)
if !self.isUnder(a:path)
return 0
endif
let l:startIndex = len(a:path.pathSegments)
let l:segments = self.pathSegments[l:startIndex : ]
for l:segment in l:segments
if l:segment =~# '^\.'
return 1
endif
endfor
return 0
endfunction
" FUNCTION: Path.isUnixHiddenFile() {{{1
" check for unix hidden files
@ -522,17 +543,16 @@ function! s:Path.equals(path)
return self.str() ==# a:path.str()
endfunction
" FUNCTION: Path.New() {{{1
" The Constructor for the Path object
function! s:Path.New(path)
let newPath = copy(self)
" FUNCTION: Path.New(pathStr) {{{1
function! s:Path.New(pathStr)
let l:newPath = copy(self)
call newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:path))
call l:newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:pathStr))
let newPath.cachedDisplayString = ""
let newPath.flagSet = g:NERDTreeFlagSet.New()
let l:newPath.cachedDisplayString = ''
let l:newPath.flagSet = g:NERDTreeFlagSet.New()
return newPath
return l:newPath
endfunction
" FUNCTION: Path.Slash() {{{1

View file

@ -1,22 +1,25 @@
"CLASS: TreeFileNode
"This class is the parent of the TreeDirNode class and is the
"'Component' part of the composite design pattern between the treenode
"classes.
"============================================================
" ============================================================================
" CLASS: TreeFileNode
"
" This class is the parent of the "TreeDirNode" class and is the "Component"
" part of the composite design pattern between the NERDTree node classes.
" ============================================================================
let s:TreeFileNode = {}
let g:NERDTreeFileNode = s:TreeFileNode
"FUNCTION: TreeFileNode.activate(...) {{{1
" FUNCTION: TreeFileNode.activate(...) {{{1
function! s:TreeFileNode.activate(...)
call self.open(a:0 ? a:1 : {})
endfunction
"FUNCTION: TreeFileNode.bookmark(name) {{{1
"bookmark this node with a:name
" FUNCTION: TreeFileNode.bookmark(name) {{{1
" bookmark this node with a:name
function! s:TreeFileNode.bookmark(name)
"if a bookmark exists with the same name and the node is cached then save
"it so we can update its display string
" if a bookmark exists with the same name and the node is cached then save
" it so we can update its display string
let oldMarkedNode = {}
try
let oldMarkedNode = g:NERDTreeBookmark.GetNodeForName(a:name, 1, self.getNerdtree())
@ -33,8 +36,8 @@ function! s:TreeFileNode.bookmark(name)
endif
endfunction
"FUNCTION: TreeFileNode.cacheParent() {{{1
"initializes self.parent if it isnt already
" FUNCTION: TreeFileNode.cacheParent() {{{1
" initializes self.parent if it isnt already
function! s:TreeFileNode.cacheParent()
if empty(self.parent)
let parentPath = self.path.getParent()
@ -45,7 +48,7 @@ function! s:TreeFileNode.cacheParent()
endif
endfunction
"FUNCTION: TreeFileNode.clearBookmarks() {{{1
" FUNCTION: TreeFileNode.clearBookmarks() {{{1
function! s:TreeFileNode.clearBookmarks()
for i in g:NERDTreeBookmark.Bookmarks()
if i.path.equals(self.path)
@ -55,7 +58,7 @@ function! s:TreeFileNode.clearBookmarks()
call self.path.cacheDisplayString()
endfunction
"FUNCTION: TreeFileNode.copy(dest) {{{1
" FUNCTION: TreeFileNode.copy(dest) {{{1
function! s:TreeFileNode.copy(dest)
call self.path.copy(a:dest)
let newPath = g:NERDTreePath.New(a:dest)
@ -68,44 +71,44 @@ function! s:TreeFileNode.copy(dest)
endif
endfunction
"FUNCTION: TreeFileNode.delete {{{1
"Removes this node from the tree and calls the Delete method for its path obj
" FUNCTION: TreeFileNode.delete {{{1
" Removes this node from the tree and calls the Delete method for its path obj
function! s:TreeFileNode.delete()
call self.path.delete()
call self.parent.removeChild(self)
endfunction
"FUNCTION: TreeFileNode.displayString() {{{1
" FUNCTION: TreeFileNode.displayString() {{{1
"
"Returns a string that specifies how the node should be represented as a
"string
" Returns a string that specifies how the node should be represented as a
" string
"
"Return:
"a string that can be used in the view to represent this node
" Return:
" a string that can be used in the view to represent this node
function! s:TreeFileNode.displayString()
return self.path.flagSet.renderToString() . self.path.displayString()
endfunction
"FUNCTION: TreeFileNode.equals(treenode) {{{1
" FUNCTION: TreeFileNode.equals(treenode) {{{1
"
"Compares this treenode to the input treenode and returns 1 if they are the
"same node.
" Compares this treenode to the input treenode and returns 1 if they are the
" same node.
"
"Use this method instead of == because sometimes when the treenodes contain
"many children, vim seg faults when doing ==
" Use this method instead of == because sometimes when the treenodes contain
" many children, vim seg faults when doing ==
"
"Args:
"treenode: the other treenode to compare to
" Args:
" treenode: the other treenode to compare to
function! s:TreeFileNode.equals(treenode)
return self.path.str() ==# a:treenode.path.str()
endfunction
"FUNCTION: TreeFileNode.findNode(path) {{{1
"Returns self if this node.path.Equals the given path.
"Returns {} if not equal.
" FUNCTION: TreeFileNode.findNode(path) {{{1
" Returns self if this node.path.Equals the given path.
" Returns {} if not equal.
"
"Args:
"path: the path object to compare against
" Args:
" path: the path object to compare against
function! s:TreeFileNode.findNode(path)
if a:path.equals(self.path)
return self
@ -113,18 +116,18 @@ function! s:TreeFileNode.findNode(path)
return {}
endfunction
"FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{1
" FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{1
"
"Finds the next sibling for this node in the indicated direction. This sibling
"must be a directory and may/may not have children as specified.
" Finds the next sibling for this node in the indicated direction. This sibling
" must be a directory and may/may not have children as specified.
"
"Args:
"direction: 0 if you want to find the previous sibling, 1 for the next sibling
" Args:
" direction: 0 if you want to find the previous sibling, 1 for the next sibling
"
"Return:
"a treenode object or {} if no appropriate sibling could be found
" Return:
" a treenode object or {} if no appropriate sibling could be found
function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction)
"if we have no parent then we can have no siblings
" if we have no parent then we can have no siblings
if self.parent != {}
let nextSibling = self.findSibling(a:direction)
@ -139,37 +142,37 @@ function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction)
return {}
endfunction
"FUNCTION: TreeFileNode.findSibling(direction) {{{1
" FUNCTION: TreeFileNode.findSibling(direction) {{{1
"
"Finds the next sibling for this node in the indicated direction
" Finds the next sibling for this node in the indicated direction
"
"Args:
"direction: 0 if you want to find the previous sibling, 1 for the next sibling
" Args:
" direction: 0 if you want to find the previous sibling, 1 for the next sibling
"
"Return:
"a treenode object or {} if no sibling could be found
" Return:
" a treenode object or {} if no sibling could be found
function! s:TreeFileNode.findSibling(direction)
"if we have no parent then we can have no siblings
" if we have no parent then we can have no siblings
if self.parent != {}
"get the index of this node in its parents children
" get the index of this node in its parents children
let siblingIndx = self.parent.getChildIndex(self.path)
if siblingIndx != -1
"move a long to the next potential sibling node
" move a long to the next potential sibling node
let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1
"keep moving along to the next sibling till we find one that is valid
" keep moving along to the next sibling till we find one that is valid
let numSiblings = self.parent.getChildCount()
while siblingIndx >= 0 && siblingIndx < numSiblings
"if the next node is not an ignored node (i.e. wont show up in the
"view) then return it
" if the next node is not an ignored node (i.e. wont show up in the
" view) then return it
if self.parent.children[siblingIndx].path.ignore(self.getNerdtree()) ==# 0
return self.parent.children[siblingIndx]
endif
"go to next node
" go to next node
let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1
endwhile
endif
@ -178,13 +181,13 @@ function! s:TreeFileNode.findSibling(direction)
return {}
endfunction
"FUNCTION: TreeFileNode.getNerdtree(){{{1
" FUNCTION: TreeFileNode.getNerdtree(){{{1
function! s:TreeFileNode.getNerdtree()
return self._nerdtree
endfunction
"FUNCTION: TreeFileNode.GetRootForTab(){{{1
"get the root node for this tab
" FUNCTION: TreeFileNode.GetRootForTab(){{{1
" get the root node for this tab
function! s:TreeFileNode.GetRootForTab()
if g:NERDTree.ExistsForTab()
return getbufvar(t:NERDTreeBufName, 'NERDTree').root
@ -192,28 +195,32 @@ function! s:TreeFileNode.GetRootForTab()
return {}
endfunction
"FUNCTION: TreeFileNode.GetSelected() {{{1
"gets the treenode that the cursor is currently over
" FUNCTION: TreeFileNode.GetSelected() {{{1
" If the cursor is currently positioned on a tree node, return the node.
" Otherwise, return the empty dictionary.
function! s:TreeFileNode.GetSelected()
try
let path = b:NERDTree.ui.getPath(line("."))
if path ==# {}
let l:path = b:NERDTree.ui.getPath(line('.'))
if empty(l:path)
return {}
endif
return b:NERDTree.root.findNode(path)
return b:NERDTree.root.findNode(l:path)
catch /^NERDTree/
return {}
endtry
endfunction
"FUNCTION: TreeFileNode.isVisible() {{{1
"returns 1 if this node should be visible according to the tree filters and
"hidden file filters (and their on/off status)
" FUNCTION: TreeFileNode.isVisible() {{{1
" returns 1 if this node should be visible according to the tree filters and
" hidden file filters (and their on/off status)
function! s:TreeFileNode.isVisible()
return !self.path.ignore(self.getNerdtree())
endfunction
"FUNCTION: TreeFileNode.isRoot() {{{1
" FUNCTION: TreeFileNode.isRoot() {{{1
function! s:TreeFileNode.isRoot()
if !g:NERDTree.ExistsForBuf()
throw "NERDTree.NoTreeError: No tree exists for the current buffer"
@ -222,12 +229,12 @@ function! s:TreeFileNode.isRoot()
return self.equals(self.getNerdtree().root)
endfunction
"FUNCTION: TreeFileNode.New(path, nerdtree) {{{1
"Returns a new TreeNode object with the given path and parent
" FUNCTION: TreeFileNode.New(path, nerdtree) {{{1
" Returns a new TreeNode object with the given path and parent
"
"Args:
"path: file/dir that the node represents
"nerdtree: the tree the node belongs to
" Args:
" path: file/dir that the node represents
" nerdtree: the tree the node belongs to
function! s:TreeFileNode.New(path, nerdtree)
if a:path.isDirectory
return g:NERDTreeDirNode.New(a:path, a:nerdtree)
@ -240,40 +247,40 @@ function! s:TreeFileNode.New(path, nerdtree)
endif
endfunction
"FUNCTION: TreeFileNode.open() {{{1
" FUNCTION: TreeFileNode.open() {{{1
function! s:TreeFileNode.open(...)
let opts = a:0 ? a:1 : {}
let opener = g:NERDTreeOpener.New(self.path, opts)
call opener.open(self)
endfunction
"FUNCTION: TreeFileNode.openSplit() {{{1
"Open this node in a new window
" FUNCTION: TreeFileNode.openSplit() {{{1
" Open this node in a new window
function! s:TreeFileNode.openSplit()
call nerdtree#deprecated('TreeFileNode.openSplit', 'is deprecated, use .open() instead.')
call self.open({'where': 'h'})
endfunction
"FUNCTION: TreeFileNode.openVSplit() {{{1
"Open this node in a new vertical window
" FUNCTION: TreeFileNode.openVSplit() {{{1
" Open this node in a new vertical window
function! s:TreeFileNode.openVSplit()
call nerdtree#deprecated('TreeFileNode.openVSplit', 'is deprecated, use .open() instead.')
call self.open({'where': 'v'})
endfunction
"FUNCTION: TreeFileNode.openInNewTab(options) {{{1
" FUNCTION: TreeFileNode.openInNewTab(options) {{{1
function! s:TreeFileNode.openInNewTab(options)
echomsg 'TreeFileNode.openInNewTab is deprecated'
call self.open(extend({'where': 't'}, a:options))
endfunction
"FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{1
"Places the cursor on the line number this node is rendered on
" FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{1
" Places the cursor on the line number this node is rendered on
"
"Args:
"isJump: 1 if this cursor movement should be counted as a jump by vim
"recurseUpward: try to put the cursor on the parent if the this node isnt
"visible
" Args:
" isJump: 1 if this cursor movement should be counted as a jump by vim
" recurseUpward: try to put the cursor on the parent if the this node isnt
" visible
function! s:TreeFileNode.putCursorHere(isJump, recurseUpward)
let ln = self.getNerdtree().ui.getLineNum(self)
if ln != -1
@ -294,18 +301,18 @@ function! s:TreeFileNode.putCursorHere(isJump, recurseUpward)
endif
endfunction
"FUNCTION: TreeFileNode.refresh() {{{1
" FUNCTION: TreeFileNode.refresh() {{{1
function! s:TreeFileNode.refresh()
call self.path.refresh(self.getNerdtree())
endfunction
"FUNCTION: TreeFileNode.refreshFlags() {{{1
" FUNCTION: TreeFileNode.refreshFlags() {{{1
function! s:TreeFileNode.refreshFlags()
call self.path.refreshFlags(self.getNerdtree())
endfunction
"FUNCTION: TreeFileNode.rename() {{{1
"Calls the rename method for this nodes path obj
" FUNCTION: TreeFileNode.rename() {{{1
" Calls the rename method for this nodes path obj
function! s:TreeFileNode.rename(newName)
let newName = substitute(a:newName, '\(\\\|\/\)$', '', '')
call self.path.rename(newName)
@ -320,17 +327,17 @@ function! s:TreeFileNode.rename(newName)
endif
endfunction
"FUNCTION: TreeFileNode.renderToString {{{1
"returns a string representation for this tree to be rendered in the view
" FUNCTION: TreeFileNode.renderToString {{{1
" returns a string representation for this tree to be rendered in the view
function! s:TreeFileNode.renderToString()
return self._renderToString(0, 0)
endfunction
"Args:
"depth: the current depth in the tree for this call
"drawText: 1 if we should actually draw the line for this node (if 0 then the
"child nodes are rendered only)
"for each depth in the tree
" Args:
" depth: the current depth in the tree for this call
" drawText: 1 if we should actually draw the line for this node (if 0 then the
" child nodes are rendered only)
" for each depth in the tree
function! s:TreeFileNode._renderToString(depth, drawText)
let output = ""
if a:drawText ==# 1
@ -346,7 +353,7 @@ function! s:TreeFileNode._renderToString(depth, drawText)
let output = output . line . "\n"
endif
"if the node is an open dir, draw its children
" if the node is an open dir, draw its children
if self.path.isDirectory ==# 1 && self.isOpen ==# 1
let childNodesToDraw = self.getVisibleChildren()

View file

@ -1,11 +1,14 @@
"CLASS: UI
"============================================================
" ============================================================================
" CLASS: UI
" ============================================================================
let s:UI = {}
let g:NERDTreeUI = s:UI
"FUNCTION: s:UI.centerView() {{{2
"centers the nerd tree window around the cursor (provided the nerd tree
"options permit)
" FUNCTION: s:UI.centerView() {{{2
" centers the nerd tree window around the cursor (provided the nerd tree
" options permit)
function! s:UI.centerView()
if g:NERDTreeAutoCenter
let current_line = winline()
@ -17,8 +20,8 @@ function! s:UI.centerView()
endif
endfunction
"FUNCTION: s:UI._dumpHelp {{{1
"prints out the quick help
" FUNCTION: s:UI._dumpHelp {{{1
" prints out the quick help
function! s:UI._dumpHelp()
if self.getShowHelp()
let help = "\" NERDTree (" . nerdtree#version() . ") quickhelp~\n"
@ -93,7 +96,7 @@ function! s:UI._dumpHelp()
let help .= "\" ". g:NERDTreeMapToggleFiles .": files (" . (self.getShowFiles() ? "on" : "off") . ")\n"
let help .= "\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (self.getShowBookmarks() ? "on" : "off") . ")\n"
"add quickhelp entries for each custom key map
" add quickhelp entries for each custom key map
let help .= "\"\n\" ----------------------------\n"
let help .= "\" Custom mappings~\n"
for i in g:NERDTreeKeyMap.All()
@ -124,7 +127,7 @@ function! s:UI._dumpHelp()
endfunction
"FUNCTION: s:UI.new(nerdtree) {{{1
" FUNCTION: s:UI.new(nerdtree) {{{1
function! s:UI.New(nerdtree)
let newObj = copy(self)
let newObj.nerdtree = a:nerdtree
@ -137,22 +140,16 @@ function! s:UI.New(nerdtree)
return newObj
endfunction
"FUNCTION: s:UI.getPath(ln) {{{1
"Gets the full path to the node that is rendered on the given line number
"
"Args:
"ln: the line number to get the path for
"
"Return:
"A path if a node was selected, {} if nothing is selected.
"If the 'up a dir' line was selected then the path to the parent of the
"current root is returned
" FUNCTION: s:UI.getPath(ln) {{{1
" Return the "Path" object for the node that is rendered on the given line
" number. If the "up a dir" line is selected, return the "Path" object for
" the parent of the root. Return the empty dictionary if the given line
" does not reference a tree node.
function! s:UI.getPath(ln)
let line = getline(a:ln)
let rootLine = self.getRootLineNum()
"check to see if we have the root node
if a:ln == rootLine
return self.nerdtree.root.path
endif
@ -161,9 +158,13 @@ function! s:UI.getPath(ln)
return self.nerdtree.root.path.getParent()
endif
if a:ln < rootLine
return {}
endif
let indent = self._indentLevelFor(line)
"remove the tree parts and the leading space
" remove the tree parts and the leading space
let curFile = self._stripMarkup(line)
let dir = ""
@ -173,7 +174,7 @@ function! s:UI.getPath(ln)
let curLine = getline(lnum)
let curLineStripped = self._stripMarkup(curLine)
"have we reached the top of the tree?
" have we reached the top of the tree?
if lnum == rootLine
let dir = self.nerdtree.root.path.str({'format': 'UI'}) . dir
break
@ -193,19 +194,19 @@ function! s:UI.getPath(ln)
return toReturn
endfunction
"FUNCTION: s:UI.getLineNum(file_node){{{1
"returns the line number this node is rendered on, or -1 if it isnt rendered
" FUNCTION: s:UI.getLineNum(file_node){{{1
" returns the line number this node is rendered on, or -1 if it isnt rendered
function! s:UI.getLineNum(file_node)
"if the node is the root then return the root line no.
" if the node is the root then return the root line no.
if a:file_node.isRoot()
return self.getRootLineNum()
endif
let totalLines = line("$")
"the path components we have matched so far
" the path components we have matched so far
let pathcomponents = [substitute(self.nerdtree.root.path.str({'format': 'UI'}), '/ *$', '', '')]
"the index of the component we are searching for
" the index of the component we are searching for
let curPathComponent = 1
let fullpath = a:file_node.path.str({'format': 'UI'})
@ -213,7 +214,7 @@ function! s:UI.getLineNum(file_node)
let lnum = self.getRootLineNum()
while lnum > 0
let lnum = lnum + 1
"have we reached the bottom of the tree?
" have we reached the bottom of the tree?
if lnum ==# totalLines+1
return -1
endif
@ -241,8 +242,8 @@ function! s:UI.getLineNum(file_node)
return -1
endfunction
"FUNCTION: s:UI.getRootLineNum(){{{1
"gets the line number of the root node
" FUNCTION: s:UI.getRootLineNum(){{{1
" gets the line number of the root node
function! s:UI.getRootLineNum()
let rootLine = 1
while getline(rootLine) !~# '^\(/\|<\)'
@ -251,29 +252,29 @@ function! s:UI.getRootLineNum()
return rootLine
endfunction
"FUNCTION: s:UI.getShowBookmarks() {{{1
" FUNCTION: s:UI.getShowBookmarks() {{{1
function! s:UI.getShowBookmarks()
return self._showBookmarks
endfunction
"FUNCTION: s:UI.getShowFiles() {{{1
" FUNCTION: s:UI.getShowFiles() {{{1
function! s:UI.getShowFiles()
return self._showFiles
endfunction
"FUNCTION: s:UI.getShowHelp() {{{1
" FUNCTION: s:UI.getShowHelp() {{{1
function! s:UI.getShowHelp()
return self._showHelp
endfunction
"FUNCTION: s:UI.getShowHidden() {{{1
" FUNCTION: s:UI.getShowHidden() {{{1
function! s:UI.getShowHidden()
return self._showHidden
endfunction
"FUNCTION: s:UI._indentLevelFor(line) {{{1
" FUNCTION: s:UI._indentLevelFor(line) {{{1
function! s:UI._indentLevelFor(line)
"have to do this work around because match() returns bytes, not chars
" have to do this work around because match() returns bytes, not chars
let numLeadBytes = match(a:line, '\M\[^ '.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.']')
" The next line is a backward-compatible workaround for strchars(a:line(0:numLeadBytes-1]). strchars() is in 7.3+
let leadChars = len(split(a:line[0:numLeadBytes-1], '\zs'))
@ -281,27 +282,27 @@ function! s:UI._indentLevelFor(line)
return leadChars / s:UI.IndentWid()
endfunction
"FUNCTION: s:UI.IndentWid() {{{1
" FUNCTION: s:UI.IndentWid() {{{1
function! s:UI.IndentWid()
return 2
endfunction
"FUNCTION: s:UI.isIgnoreFilterEnabled() {{{1
" FUNCTION: s:UI.isIgnoreFilterEnabled() {{{1
function! s:UI.isIgnoreFilterEnabled()
return self._ignoreEnabled == 1
endfunction
"FUNCTION: s:UI.isMinimal() {{{1
" FUNCTION: s:UI.isMinimal() {{{1
function! s:UI.isMinimal()
return g:NERDTreeMinimalUI
endfunction
"FUNCTION: s:UI.MarkupReg() {{{1
" FUNCTION: s:UI.MarkupReg() {{{1
function! s:UI.MarkupReg()
return '^\(['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+\)'
endfunction
"FUNCTION: s:UI._renderBookmarks {{{1
" FUNCTION: s:UI._renderBookmarks {{{1
function! s:UI._renderBookmarks()
if !self.isMinimal()
@ -322,12 +323,12 @@ function! s:UI._renderBookmarks()
call cursor(line(".")+1, col("."))
endfunction
"FUNCTION: s:UI.restoreScreenState() {{{1
" FUNCTION: s:UI.restoreScreenState() {{{1
"
"Sets the screen state back to what it was when nerdtree#saveScreenState was last
"called.
" Sets the screen state back to what it was when nerdtree#saveScreenState was last
" called.
"
"Assumes the cursor is in the NERDTree window
" Assumes the cursor is in the NERDTree window
function! s:UI.restoreScreenState()
if !has_key(self, '_screenState')
return
@ -342,9 +343,9 @@ function! s:UI.restoreScreenState()
let &scrolloff=old_scrolloff
endfunction
"FUNCTION: s:UI.saveScreenState() {{{1
"Saves the current cursor position in the current buffer and the window
"scroll position
" FUNCTION: s:UI.saveScreenState() {{{1
" Saves the current cursor position in the current buffer and the window
" scroll position
function! s:UI.saveScreenState()
let win = winnr()
call g:NERDTree.CursorToTreeWin()
@ -355,31 +356,31 @@ function! s:UI.saveScreenState()
call nerdtree#exec(win . "wincmd w")
endfunction
"FUNCTION: s:UI.setShowHidden(val) {{{1
" FUNCTION: s:UI.setShowHidden(val) {{{1
function! s:UI.setShowHidden(val)
let self._showHidden = a:val
endfunction
"FUNCTION: s:UI._stripMarkup(line){{{1
"returns the given line with all the tree parts stripped off
" FUNCTION: s:UI._stripMarkup(line){{{1
" returns the given line with all the tree parts stripped off
"
"Args:
"line: the subject line
" Args:
" line: the subject line
function! s:UI._stripMarkup(line)
let line = a:line
"remove the tree parts and the leading space
" remove the tree parts and the leading space
let line = substitute (line, g:NERDTreeUI.MarkupReg(),"","")
"strip off any read only flag
" strip off any read only flag
let line = substitute (line, ' \['.g:NERDTreeGlyphReadOnly.'\]', "","")
"strip off any bookmark flags
" strip off any bookmark flags
let line = substitute (line, ' {[^}]*}', "","")
"strip off any executable flags
" strip off any executable flags
let line = substitute (line, '*\ze\($\| \)', "","")
"strip off any generic flags
" strip off any generic flags
let line = substitute (line, '\[[^]]*\]', "","")
let line = substitute (line,' -> .*',"","") " remove link to
@ -387,22 +388,22 @@ function! s:UI._stripMarkup(line)
return line
endfunction
"FUNCTION: s:UI.render() {{{1
" FUNCTION: s:UI.render() {{{1
function! s:UI.render()
setlocal modifiable
"remember the top line of the buffer and the current line so we can
"restore the view exactly how it was
" remember the top line of the buffer and the current line so we can
" restore the view exactly how it was
let curLine = line(".")
let curCol = col(".")
let topLine = line("w0")
"delete all lines in the buffer (being careful not to clobber a register)
" delete all lines in the buffer (being careful not to clobber a register)
silent 1,$delete _
call self._dumpHelp()
"delete the blank line before the help and add one after it
" delete the blank line before the help and add one after it
if !self.isMinimal()
call setline(line(".")+1, "")
call cursor(line(".")+1, col("."))
@ -412,24 +413,24 @@ function! s:UI.render()
call self._renderBookmarks()
endif
"add the 'up a dir' line
" add the 'up a dir' line
if !self.isMinimal()
call setline(line(".")+1, s:UI.UpDirLine())
call cursor(line(".")+1, col("."))
endif
"draw the header line
" draw the header line
let header = self.nerdtree.root.path.str({'format': 'UI', 'truncateTo': winwidth(0)})
call setline(line(".")+1, header)
call cursor(line(".")+1, col("."))
"draw the tree
" draw the tree
silent put =self.nerdtree.root.renderToString()
"delete the blank line at the top of the buffer
" delete the blank line at the top of the buffer
silent 1,1delete _
"restore the view
" restore the view
let old_scrolloff=&scrolloff
let &scrolloff=0
call cursor(topLine, 1)
@ -441,14 +442,14 @@ function! s:UI.render()
endfunction
"FUNCTION: UI.renderViewSavingPosition {{{1
"Renders the tree and ensures the cursor stays on the current node or the
"current nodes parent if it is no longer available upon re-rendering
" FUNCTION: UI.renderViewSavingPosition {{{1
" Renders the tree and ensures the cursor stays on the current node or the
" current nodes parent if it is no longer available upon re-rendering
function! s:UI.renderViewSavingPosition()
let currentNode = g:NERDTreeFileNode.GetSelected()
"go up the tree till we find a node that will be visible or till we run
"out of nodes
" go up the tree till we find a node that will be visible or till we run
" out of nodes
while currentNode != {} && !currentNode.isVisible() && !currentNode.isRoot()
let currentNode = currentNode.parent
endwhile
@ -460,7 +461,7 @@ function! s:UI.renderViewSavingPosition()
endif
endfunction
"FUNCTION: s:UI.toggleHelp() {{{1
" FUNCTION: s:UI.toggleHelp() {{{1
function! s:UI.toggleHelp()
let self._showHelp = !self._showHelp
endfunction
@ -515,7 +516,9 @@ function! s:UI.toggleZoom()
endif
endfunction
"FUNCTION: s:UI.UpDirLine() {{{1
" FUNCTION: s:UI.UpDirLine() {{{1
function! s:UI.UpDirLine()
return '.. (up a dir)'
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View file

@ -335,4 +335,5 @@ function! NERDTreeExecuteFile()
call system("open '" . treenode.path.str() . "'")
endif
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View file

@ -69,8 +69,9 @@ MATLAB, Mercury, NASM, Nix, Objective-C, Objective-C++, OCaml, Perl, Perl
NG, reStructuredText, RPM spec, Ruby, SASS/SCSS, Scala, Slim, SML, Solidity,
Sphinx, SQL, Stylus, Tcl, TeX, Texinfo, Twig, TypeScript, Vala, Verilog, VHDL,
Vim help, VimL, Vue.js, xHtml, XML, XSLT, XQuery, YACC, YAML, YANG data models,
z80, Zope page templates, and Zsh. See the [manual][checkers] for details about
the corresponding supported checkers (`:help syntastic-checkers` in Vim).
YARA rules, z80, Zope page templates, and Zsh. See the [manual][checkers] for
details about the corresponding supported checkers (`:help syntastic-checkers`
in Vim).
A number of third-party Vim plugins also provide checkers for syntastic, for
example: [merlin][merlin], [omnisharp-vim][omnisharp], [rust.vim][rust],

View file

@ -634,17 +634,27 @@ endfunction " }}}2
function! syntastic#preprocess#mypy(errors) abort " {{{2
let out = []
for e in a:errors
" new format
let parts = matchlist(e, '\v^(.{-1,}):(\d+): error: (.+)')
if len(parts) > 3
call add(out, join(parts[1:3], ':'))
" column numbers
let parts = matchlist(e, '\v^(.{-1,}):(\d+):(\d+): ([ew])%(rror|arning): (.+)')
if len(parts) > 5
let parts[3] += 1
call add(out, join(parts[1:5], ':'))
continue
endif
" old format
" no column numbers
let parts = matchlist(e, '\v^(.{-1,}):(\d+): ([ew])%(rror|arning): (.+)')
if len(parts) > 4
call add(out, join(parts[1:4], ':'))
continue
endif
" obsolete format
let parts = matchlist(e, '\v^(.{-1,}), line (\d+): (.+)')
if len(parts) > 3
call add(out, join(parts[1:3], ':'))
let parts[4] = parts[3]
let parts[3] = 'e'
call add(out, join(parts[1:4], ':'))
endif
endfor
return out

View file

@ -132,6 +132,7 @@ SYNTAX CHECKERS BY LANGUAGE *syntastic-checkers-lang*
YACC.....................................|syntastic-checkers-yacc|
YAML.....................................|syntastic-checkers-yaml|
YANG.....................................|syntastic-checkers-yang|
YARA.....................................|syntastic-checkers-yara|
Z80......................................|syntastic-checkers-z80|
Zope Page Templates......................|syntastic-checkers-zpt|
@ -1119,7 +1120,7 @@ one option per line (cf. |syntastic-config-files|).
Note~
By default you can set "ClangTidy" parameters in
'g:syntastic_ppc_clang_tidy_args', and compilation parameters (defines,
'g:syntastic_cpp_clang_tidy_args', and compilation parameters (defines,
optimisation flags, etc.) in the configuration file.
If you want "ClangTidy" to use compilation databases
@ -7629,6 +7630,36 @@ You probably also need a plugin to set |filetype| for YANG files, such as
https://github.com/nathanalderson/yang.vim
==============================================================================
SYNTAX CHECKERS FOR YARA *syntastic-checkers-yara*
The following checkers are available for YARA rule files (filetype "yara"):
1. yarac....................|syntastic-yara-yarac|
------------------------------------------------------------------------------
1. yarac *syntastic-yara-yarac*
Name: yarac
Maintainer: Albert Song <albb@teamt5.org>
"yarac" is the official compiler for YARA rule files. See the project's page
at GitHub for more information:
https://github.com/VirusTotal/yara
Checker options~
This checker is initialised using the "makeprgBuild()" function and thus it
accepts the standard options described at |syntastic-config-makeprg|.
Note~
You probably also need a plugin to set |filetype| for YARA rule files, such as
"vim-yara":
https://github.com/yaunj/vim-yara
==============================================================================
SYNTAX CHECKERS FOR Z80 *syntastic-checkers-z80*

View file

@ -19,7 +19,7 @@ if has('reltime')
lockvar! g:_SYNTASTIC_START
endif
let g:_SYNTASTIC_VERSION = '3.8.0-97'
let g:_SYNTASTIC_VERSION = '3.8.0-101'
lockvar g:_SYNTASTIC_VERSION
" Sanity checks {{{1

View file

@ -112,6 +112,7 @@ let s:_DEFAULT_CHECKERS = {
\ 'yacc': ['bison'],
\ 'yaml': ['jsyaml'],
\ 'yang': ['pyang'],
\ 'yara': ['yarac'],
\ 'z80': ['z80syntaxchecker'],
\ 'zpt': ['zptlint'],
\ 'zsh': ['zsh'],

View file

@ -69,6 +69,7 @@ rebar_opts(RebarFile) ->
Dir = get_root(filename:dirname(RebarFile)),
case file:consult(RebarFile) of
{ok, Terms} ->
%% Add deps for a rebar (version < 3) project
RebarLibDirs = proplists:get_value(lib_dirs, Terms, []),
lists:foreach(
fun(LibDir) ->
@ -76,8 +77,14 @@ rebar_opts(RebarFile) ->
end, RebarLibDirs),
RebarDepsDir = proplists:get_value(deps_dir, Terms, "deps"),
code:add_pathsa(filelib:wildcard(RebarDepsDir ++ "/*/ebin")),
IncludeDeps = {i, filename:join(Dir, RebarDepsDir)},
proplists:get_value(erl_opts, Terms, []) ++ [IncludeDeps];
%% Add deps for rebar 3
code:add_pathsa(filelib:wildcard(Dir ++ "/_build/default/lib/*/ebin")),
%% Add include dependencies
IncludeDeps = [{i, IPath} || IPath <- filelib:wildcard(Dir ++ "/_build/default/lib/*")] ++
[{i, filename:join(Dir, RebarDepsDir)}, %% rebar 2 dependencies
{i, filename:join(Dir, "apps")}], %% rebar 3 multi-apps
proplists:get_value(erl_opts, Terms, []) ++ IncludeDeps;
{error, _} when RebarFile == "rebar.config" ->
fallback_opts();
{error, _} ->
@ -258,12 +265,19 @@ apps_dir_from_src(SrcFile) ->
SrcDir = filename:dirname(SrcFile),
filename:join(SrcDir, "../../ebin").
%% Find the root directory of the project
get_root(Dir) ->
Path = filename:split(filename:absname(Dir)),
filename:join(get_root(lists:reverse(Path), Path)).
get_root([], Path) ->
Path;
%% Strip off /apps/<appname>/src from the end of the path
%% (rebar 3 multi-app project)
get_root(["src", _Appname, "apps" | Tail], _Path) ->
lists:reverse(Tail);
%% Strip off /src or /test from the end of the path
%% (single-app project)
get_root(["src" | Tail], _Path) ->
lists:reverse(Tail);
get_root(["test" | Tail], _Path) ->

View file

@ -14,14 +14,21 @@ let s:save_cpo = &cpo
set cpo&vim
function! SyntaxCheckers_python_mypy_GetLocList() dict
let makeprg = self.makeprgBuild({})
if !exists('s:mypy_new')
" creative versioning: version string has changed from v0.4.6 to v0.470
" XXX the test should be fine for now, since 470 > 4
let s:mypy_new = syntastic#util#versionIsAtLeast(self.getVersion(), [0, 4, 5])
endif
let errorformat = '%f:%l:%m'
let makeprg = self.makeprgBuild({ 'args_after': (s:mypy_new ? '--show-column-numbers' : '') })
let errorformat =
\ '%f:%l:%c:%t:%m,' .
\ '%f:%l:%t:%m'
return SyntasticMake({
\ 'makeprg': makeprg,
\ 'errorformat': errorformat,
\ 'defaults': { 'type': 'E' },
\ 'returns': [0, 1],
\ 'preprocess': 'mypy' })
endfunction

View file

@ -0,0 +1,41 @@
"============================================================================
"File: yara.vim
"Description: Syntax checking plugin for syntastic
"Maintainer: Albert Song (albb@teamt5.org)
"License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
"
"============================================================================
if exists('g:loaded_syntastic_yara_yarac_checker')
finish
endif
let g:loaded_syntastic_yara_yarac_checker = 1
let s:save_cpo = &cpo
set cpo&vim
function! SyntaxCheckers_yara_yarac_GetLocList() dict
let makeprg = self.makeprgBuild({ 'fname_after' : syntastic#util#DevNull() })
let errorformat =
\ '%f(%l): %trror: %m,' .
\ '%f(%l): %tarning: %m,' .
\ '%f(%l): %m'
return SyntasticMake({
\ 'makeprg': makeprg,
\ 'errorformat': errorformat })
endfunction
call g:SyntasticRegistry.CreateAndRegisterChecker({
\ 'filetype': 'yara',
\ 'name': 'yarac'})
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: set sw=4 sts=4 et fdm=marker:

View file

@ -77,17 +77,17 @@ that are part of Git repositories).
*fugitive-:Gmerge*
:Gmerge [args] Calls git-merge and loads errors and conflicted files
into the quickfix list. Opens a |:Gcommit| style
into the |quickfix| list. Opens a |:Gcommit| style
split window for the commit message if the merge
succeeds. If called during a merge conflict, the
conflicted files from the current index are loaded
into the quickfix list.
into the |quickfix| list.
*fugitive-:Gpull*
:Gpull [args] Like |:Gmerge|, but for git-pull.
*fugitive-:Gpush*
:Gpush [args] Invoke git-push, load the results into the quickfix
:Gpush [args] Invoke git-push, load the results into the |quickfix|
list, and invoke |:cwindow| to reveal any errors.
|:Dispatch| is used if available for asynchronous
invocation.
@ -103,20 +103,20 @@ that are part of Git repositories).
*fugitive-:Glog*
:Glog [args] Load all previous revisions of the current file into
the quickfix list. Additional git-log arguments can
the |quickfix| list. Additional git-log arguments can
be given (for example, --reverse). If "--" appears as
an argument, no file specific filtering is done, and
previous commits rather than previous file revisions
are loaded.
:{range}Glog [args] Use git-log -L to load previous revisions of the given
range of the current file into the quickfix list. The
cursor is positioned on the first line of the first
diff hunk for each commit.
range of the current file into the |quickfix| list.
The cursor is positioned on the first line of the
first diff hunk for each commit.
*fugitive-:Gllog*
:Gllog [args] Like |:Glog|, but use the location list instead of the
quickfix list.
|quickfix| list.
*fugitive-:Gedit* *fugitive-:Ge*
:Gedit [revision] |:edit| a |fugitive-revision|.

View file

@ -2749,6 +2749,8 @@ function! s:BufReadObject() abort
endif
endtry
return ''
catch /^fugitive: rev-parse/
return ''
catch /^fugitive:/
return 'echoerr v:errmsg'

View file

@ -88,7 +88,10 @@ function! gitgutter#diff#run_diff(realtime, preserve_full_diff) abort
let op_mark_start = getpos("'[")
let op_mark_end = getpos("']")
let current_buffer = bufnr('')
execute 'buffer '.bufnr
execute 'keepalt noautocmd silent write!' buff_file
execute 'buffer '.current_buffer
call setbufvar(bufnr, "&mod", modified)
call setpos("'[", op_mark_start)

View file

@ -1 +1,2 @@
.local/
.git/

View file

@ -1,5 +1,75 @@
## unplanned
IMPROVEMENTS:
* Add descriptions to neosnippet abbrevations.
[[GH-1639]](https://github.com/fatih/vim-go/pull/1639)
* Show messages in the location list instead of the quickfix list when
`gometalinter` is run automatically when saving a buffer. Whether the
location list or quickfix list is used can be customized in the usual ways.
[[GH-1652]](https://github.com/fatih/vim-go/pull/1652)
BUG FIXES:
* Create quickfix list correctly when tests timeout.
[[GH-1633]](https://github.com/fatih/vim-go/pull/1633)
* Apply `g:go_test_timeout` when running `:GoTestFunc`.
[[GH-1631]](https://github.com/fatih/vim-go/pull/1631)
* The user's configured `g:go_doc_url` variable wasn't working correctly in the
case when the "gogetdoc" command isn't installed.
[[GH-1629]](https://github.com/fatih/vim-go/pull/1629)
* Highlight format specifiers with an index (e.g. `%[2]d`).
[[GH-1634]](https://github.com/fatih/vim-go/pull/1634)
* Respect `g:go_test_show_name` change for `:GoTest` when it changes during a
Vim session.
[[GH-1641]](https://github.com/fatih/vim-go/pull/1641)
* Show `g:go_test_show_name` value for `:GoTest` failures if it's available.
[[GH-1641]](https://github.com/fatih/vim-go/pull/1641)
* Make sure linter errors for the file being saved are shown in vim74 and nvim.
[[GH-1640]](https://github.com/fatih/vim-go/pull/1640)
* Make sure only linter errors for the file being saved are shown in vim8.
Previously, all linter errors for all files in the current file's directory
were being shown.
[[GH-1640]](https://github.com/fatih/vim-go/pull/1640)
* Make sure gometalinter is run on the given directories when arguments are
given to :GoMetaLinter.
[[GH-1640]](https://github.com/fatih/vim-go/pull/1640)
* Do not run disabled linters with `gometalinter`.
[[GH-1648]](https://github.com/fatih/vim-go/pull/1648)
* Do not prompt user to press enter after when `gometalinter` is called in
autosave mode.
[[GH-1654]](https://github.com/fatih/vim-go/pull/1654)
* Fix potential race conditions when using vim8 jobs.
[[GH-1656]](https://github.com/fatih/vim-go/pull/1656)
* Treat `'autowriteall'` the same as `'autowrite'` when determining whether to
write a buffer before calling some commands.
[[GH-1653]](https://github.com/fatih/vim-go/pull/1653)
* Show the file location of test errors when the message is empty or begins
with a newline.
[[GH-1664]](https://github.com/fatih/vim-go/pull/1664)
BACKWARDS INCOMPATIBILITIES:
* Highlighting function and method declarations/calls is fixed. To fix it we
had to remove the meaning of the previous settings. The following setting is
removed:
* `go_highlight_methods`
in favor of the following settings and changes:
* `go_highlight_functions`: This highlights now all function and method
declarations (whereas previously it would also highlight function and
method calls, not anymore)
* `go_highlight_function_calls`: This higlights now all all function and
method calls.
[[GH-1557]](https://github.com/fatih/vim-go/pull/1557)
* Rename g`g:go_metalinter_excludes` to `g:go_metalinter_disabled`.
[[GH-1648]](https://github.com/fatih/vim-go/pull/1648)
## 1.16 - (December 29, 2017)
FEATURES:
* Add `g:go_doc_url` to change the `godoc` server from `godoc.org` to a custom
@ -61,6 +131,11 @@ BUG FIXES:
[[GH-1587]](https://github.com/fatih/vim-go/pull/1587).
* Fix installation of `gocode` on MS-Windows.
[[GH-1606]](https://github.com/fatih/vim-go/pull/1606).
* Fix template creation for files in directories that don't exist yet.
[[GH-1618]](https://github.com/fatih/vim-go/pull/1618).
* Fix behavior of terminal windows and resize terminal windows correctly for
all valid `g:go_term_mode` values.
[[GH-1611]](https://github.com/fatih/vim-go/pull/1611).
BACKWARDS INCOMPATIBILITIES:
@ -76,6 +151,11 @@ BACKWARDS INCOMPATIBILITIES:
changed for all commands run from Vim.
[[GH-1461]](https://github.com/fatih/vim-go/pull/1461) and
[[GH-1525]](https://github.com/fatih/vim-go/pull/1525).
* Update `:GoFillStruct` to check the current line (vs. the exact cursor
position) for a struct literal to fill. To support this, fillstruct made
[backwards imcompatible
changes](https://github.com/davidrjenni/reftools/pull/8).
[[GH-1607]](https://github.com/fatih/vim-go/pull/1607).
## 1.15 - (October 3, 2017)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 747 KiB

View file

@ -1,5 +1,5 @@
function! go#cmd#autowrite() abort
if &autowrite == 1
if &autowrite == 1 || &autowriteall == 1
silent! wall
endif
endfunction
@ -269,7 +269,7 @@ function s:cmd_job(args) abort
" autowrite is not enabled for jobs
call go#cmd#autowrite()
function! s:error_info_cb(job, exit_status, data) closure abort
function! s:complete(job, exit_status, data) closure abort
let status = {
\ 'desc': 'last status',
\ 'type': a:args.cmd[1],
@ -288,12 +288,13 @@ function s:cmd_job(args) abort
call go#statusline#Update(status_dir, status)
endfunction
let a:args.error_info_cb = funcref('s:error_info_cb')
let a:args.complete = funcref('s:complete')
let callbacks = go#job#Spawn(a:args)
let start_options = {
\ 'callback': callbacks.callback,
\ 'exit_cb': callbacks.exit_cb,
\ 'close_cb': callbacks.close_cb,
\ }
" pre start

View file

@ -51,7 +51,7 @@ function! go#coverage#Buffer(bang, ...) abort
if go#util#has_job()
call s:coverage_job({
\ 'cmd': ['go', 'test', '-coverprofile', l:tmpname] + a:000,
\ 'custom_cb': function('s:coverage_callback', [l:tmpname]),
\ 'complete': function('s:coverage_callback', [l:tmpname]),
\ 'bang': a:bang,
\ 'for': 'GoTest',
\ })
@ -107,7 +107,7 @@ function! go#coverage#Browser(bang, ...) abort
if go#util#has_job()
call s:coverage_job({
\ 'cmd': ['go', 'test', '-coverprofile', l:tmpname],
\ 'custom_cb': function('s:coverage_browser_callback', [l:tmpname]),
\ 'complete': function('s:coverage_browser_callback', [l:tmpname]),
\ 'bang': a:bang,
\ 'for': 'GoTest',
\ })
@ -278,7 +278,8 @@ function s:coverage_job(args)
call go#cmd#autowrite()
let status_dir = expand('%:p:h')
function! s:error_info_cb(job, exit_status, data) closure
let Complete = a:args.complete
function! s:complete(job, exit_status, data) closure
let status = {
\ 'desc': 'last status',
\ 'type': "coverage",
@ -290,14 +291,16 @@ function s:coverage_job(args)
endif
call go#statusline#Update(status_dir, status)
return Complete(a:job, a:exit_status, a:data)
endfunction
let a:args.error_info_cb = funcref('s:error_info_cb')
let a:args.complete = funcref('s:complete')
let callbacks = go#job#Spawn(a:args)
let start_options = {
\ 'callback': callbacks.callback,
\ 'exit_cb': callbacks.exit_cb,
\ 'close_cb': callbacks.close_cb,
\ }
" pre start

View file

@ -53,7 +53,7 @@ function! go#def#Jump(mode) abort
if go#util#has_job()
let l:spawn_args = {
\ 'cmd': cmd,
\ 'custom_cb': function('s:jump_to_declaration_cb', [a:mode, bin_name]),
\ 'complete': function('s:jump_to_declaration_cb', [a:mode, bin_name]),
\ }
if &modified
@ -292,16 +292,12 @@ function! go#def#Stack(...) abort
endfunction
function s:def_job(args) abort
function! s:error_info_cb(job, exit_status, data) closure
" do not print anything during async definition search&jump
endfunction
let a:args.error_info_cb = funcref('s:error_info_cb')
let callbacks = go#job#Spawn(a:args)
let start_options = {
\ 'callback': callbacks.callback,
\ 'exit_cb': callbacks.exit_cb,
\ 'close_cb': callbacks.close_cb,
\ }
if &modified

View file

@ -29,18 +29,7 @@ function! go#doc#OpenBrowser(...) abort
let name = out["name"]
let decl = out["decl"]
let godoc_url = get(g:, 'go_doc_url', 'https://godoc.org')
if godoc_url isnot 'https://godoc.org'
" strip last '/' character if available
let last_char = strlen(godoc_url) - 1
if godoc_url[last_char] == '/'
let godoc_url = strpart(godoc_url, 0, last_char)
endif
" custom godoc installations expects it
let godoc_url .= "/pkg"
endif
let godoc_url = s:custom_godoc_url()
let godoc_url .= "/" . import
if decl !~ "^package"
let godoc_url .= "#" . name
@ -61,7 +50,7 @@ function! go#doc#OpenBrowser(...) abort
let exported_name = pkgs[1]
" example url: https://godoc.org/github.com/fatih/set#Set
let godoc_url = "https://godoc.org/" . pkg . "#" . exported_name
let godoc_url = s:custom_godoc_url() . "/" . pkg . "#" . exported_name
call go#tool#OpenBrowser(godoc_url)
endfunction
@ -217,13 +206,18 @@ function! s:godocWord(args) abort
return [pkg, exported_name]
endfunction
function! s:godocNotFound(content) abort
if len(a:content) == 0
return 1
function! s:custom_godoc_url() abort
let godoc_url = get(g:, 'go_doc_url', 'https://godoc.org')
if godoc_url isnot 'https://godoc.org'
" strip last '/' character if available
let last_char = strlen(godoc_url) - 1
if godoc_url[last_char] == '/'
let godoc_url = strpart(godoc_url, 0, last_char)
endif
" custom godoc installations expect /pkg before package names
let godoc_url .= "/pkg"
endif
return a:content =~# '^.*: no such file or directory\n$'
return godoc_url
endfunction
" vim: sw=2 ts=2 et

View file

@ -1,7 +1,8 @@
function! go#fillstruct#FillStruct() abort
let l:cmd = ['fillstruct',
\ '-file', bufname(''),
\ '-offset', go#util#OffsetCursor()]
\ '-offset', go#util#OffsetCursor(),
\ '-line', line('.')]
" Read from stdin if modified.
if &modified
@ -23,27 +24,36 @@ function! go#fillstruct#FillStruct() abort
return
endtry
let l:code = split(l:json['code'], "\n")
" Output is array:
"[
" {"start": 92, "end": 106, "code": "mail.Address{\n\tName: \"\",\n\tAddress: \"\",\n}"},
" {...second struct...}
" ]
let l:pos = getpos('.')
try
" Add any code before/after the struct.
exe l:json['start'] . 'go'
let l:code[0] = getline('.')[:col('.')-1] . l:code[0]
exe l:json['end'] . 'go'
let l:code[len(l:code)-1] .= getline('.')[col('.'):]
for l:struct in l:json
let l:code = split(l:struct['code'], "\n")
" Indent every line except the first one; makes it look nice.
let l:indent = repeat("\t", indent('.') / &ts)
for i in range(1, len(l:code)-1)
let l:code[l:i] = l:indent . l:code[i]
" Add any code before/after the struct.
exe l:struct['start'] . 'go'
let l:code[0] = getline('.')[:col('.')-1] . l:code[0]
exe l:struct['end'] . 'go'
let l:code[len(l:code)-1] .= getline('.')[col('.'):]
" Indent every line except the first one; makes it look nice.
let l:indent = repeat("\t", indent('.') / &tabstop)
for l:i in range(1, len(l:code)-1)
let l:code[l:i] = l:indent . l:code[l:i]
endfor
" Out with the old ...
exe 'normal! ' . l:struct['start'] . 'gov' . l:struct['end'] . 'gox'
" ... in with the new.
call setline('.', l:code[0])
call append('.', l:code[1:])
endfor
" Out with the old ...
exe 'normal! ' . l:json['start'] . 'gov' . l:json['end'] . 'gox'
" ... in with the new.
call setline('.', l:code[0])
call append('.', l:code[1:])
finally
call setpos('.', l:pos)
endtry

View file

@ -3,7 +3,7 @@ func! Test_fillstruct() abort
let l:tmp = gotest#write_file('a/a.go', [
\ 'package a',
\ 'import "net/mail"',
\ 'var addr = mail.Address{}'])
\ "var addr = mail.\x1fAddress{}"])
call go#fillstruct#FillStruct()
call gotest#assert_buffer(1, [
@ -16,4 +16,75 @@ func! Test_fillstruct() abort
endtry
endfunc
func! Test_fillstruct_line() abort
try
let l:tmp = gotest#write_file('a/a.go', [
\ 'package a',
\ 'import "net/mail"',
\ "\x1f" . 'var addr = mail.Address{}'])
call go#fillstruct#FillStruct()
call gotest#assert_buffer(1, [
\ 'var addr = mail.Address{',
\ '\tName: "",',
\ '\tAddress: "",',
\ '}'])
finally
call delete(l:tmp, 'rf')
endtry
endfunc
func! Test_fillstruct_two_line() abort
try
let l:tmp = gotest#write_file('a/a.go', [
\ 'package a',
\ 'import (',
\ '"fmt"',
\ '"net/mail"',
\ ')',
\ "\x1f" . 'func x() { fmt.Println(mail.Address{}, mail.Address{}) }'])
call go#fillstruct#FillStruct()
call gotest#assert_buffer(1, [
\ 'import (',
\ '"fmt"',
\ '"net/mail"',
\ ')',
\ 'func x() { fmt.Println(mail.Address{',
\ '\tName: "",',
\ '\tAddress: "",',
\ '}, mail.Address{',
\ '\tName: "",',
\ '\tAddress: "",',
\ '}) }'])
finally
"call delete(l:tmp, 'rf')
endtry
endfunc
func! Test_fillstruct_two_cursor() abort
try
let l:tmp = gotest#write_file('a/a.go', [
\ 'package a',
\ 'import (',
\ '"fmt"',
\ '"net/mail"',
\ ')',
\ "func x() { fmt.Println(mail.Address{}, mail.Ad\x1fdress{}) }"])
call go#fillstruct#FillStruct()
call gotest#assert_buffer(1, [
\ 'import (',
\ '"fmt"',
\ '"net/mail"',
\ ')',
\ 'func x() { fmt.Println(mail.Address{}, mail.Address{',
\ '\tName: "",',
\ '\tAddress: "",',
\ '}) }'])
finally
call delete(l:tmp, 'rf')
endtry
endfunc
" vim: sw=2 ts=2 et

View file

@ -153,8 +153,7 @@ function! go#fmt#update_file(source, target)
endfunction
" run runs the gofmt/goimport command for the given source file and returns
" the the output of the executed command. Target is the real file to be
" formated.
" the output of the executed command. Target is the real file to be formatted.
function! go#fmt#run(bin_name, source, target)
let cmd = s:fmt_cmd(a:bin_name, a:source, a:target)
if empty(cmd)

View file

@ -162,8 +162,12 @@ function! s:async_guru(args) abort
let status = {}
let exitval = 0
let closed = 0
let exited = 0
function! s:exit_cb(job, exitval) closure
let exited = 1
let status = {
\ 'desc': 'last status',
\ 'type': statusline_type,
@ -176,9 +180,21 @@ function! s:async_guru(args) abort
endif
call go#statusline#Update(status_dir, status)
if closed
call s:complete()
endif
endfunction
function! s:close_cb(ch) closure
let closed = 1
if exited
call s:complete()
endif
endfunction
function! s:complete() closure
let out = join(messages, "\n")
if has_key(a:args, 'custom_parse')
@ -597,11 +613,9 @@ function! s:parse_guru_output(exit_val, output, title) abort
return
endif
let old_errorformat = &errorformat
let errformat = "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m"
let l:listtype = go#list#Type("_guru")
call go#list#ParseFormat(l:listtype, errformat, a:output, a:title)
let &errorformat = old_errorformat
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))

View file

@ -1,44 +1,78 @@
" Spawn returns callbacks to be used with job_start. It's abstracted to be
" used with various go command, such as build, test, install, etc.. This avoid
" us to write the same callback over and over for some commands. It's fully
" customizable so each command can change it to it's own logic.
" Spawn returns callbacks to be used with job_start. It is abstracted to be
" used with various go commands, such as build, test, install, etc.. This
" allows us to avoid writing the same callback over and over for some
" commands. It's fully customizable so each command can change it to it's own
" logic.
"
" args is a dictionary with the these keys:
" 'cmd':
" The value to pass to job_start().
" 'bang':
" Set to 0 to jump to the first error in the error list.
" Defaults to 0.
" 'for':
" The g:go_list_type_command key to use to get the error list type to use.
" Defaults to '_job'
" 'complete':
" A function to call after the job exits and the channel is closed. The
" function will be passed three arguments: the job, its exit code, and the
" list of messages received from the channel. The default value will
" process the messages and manage the error list after the job exits and
" the channel is closed.
" 'callback':
" A function to call when there is a message to read from the job's
" channel. The function will be passed two arguments: the channel and a
" message. See job-callback.
" The return value is a dictionary with these keys:
" 'callback':
" A function suitable to be passed as a job callback handler. See
" job-callback.
" 'exit_cb':
" A function suitable to be passed as a job exit_cb handler. See
" job-exit_cb.
" 'close_cb':
" A function suitable to be passed as a job close_cb handler. See
" job-close_cb.
function go#job#Spawn(args)
let cbs = {
\ 'winnr': winnr(),
\ 'dir': getcwd(),
\ 'jobdir': fnameescape(expand("%:p:h")),
\ 'messages': [],
\ 'args': a:args.cmd,
\ 'bang': 0,
\ 'for': "_job",
\ }
let cbs = {}
let winnr = winnr()
let dir = getcwd()
let jobdir = fnameescape(expand("%:p:h"))
let messages = []
let args = a:args.cmd
let bang = 0
let for = "_job"
if has_key(a:args, 'bang')
let cbs.bang = a:args.bang
let l:bang = a:args.bang
endif
if has_key(a:args, 'for')
let cbs.for = a:args.for
let l:for = a:args.for
endif
" add final callback to be called if async job is finished
" The signature should be in form: func(job, exit_status, messages)
if has_key(a:args, 'custom_cb')
let cbs.custom_cb = a:args.custom_cb
endif
let l:exited = 0
let l:exit_status = 0
let l:closed = 0
if has_key(a:args, 'error_info_cb')
let cbs.error_info_cb = a:args.error_info_cb
endif
function cbs.callback(chan, msg) dict
call add(self.messages, a:msg)
function! s:NopComplete(job, exit_status, data)
endfunction
function cbs.exit_cb(job, exitval) dict
if has_key(self, 'error_info_cb')
call self.error_info_cb(a:job, a:exitval, self.messages)
endif
let Complete = funcref('s:NopComplete')
if has_key(a:args, 'complete')
let Complete = a:args.complete
endif
function cbs.callback(chan, msg) dict closure
call add(messages, a:msg)
endfunction
function cbs.exit_cb(job, exitval) dict closure
let exit_status = a:exitval
let exited = 1
if get(g:, 'go_echo_command_info', 1)
if a:exitval == 0
@ -48,55 +82,62 @@ function go#job#Spawn(args)
endif
endif
if has_key(self, 'custom_cb')
call self.custom_cb(a:job, a:exitval, self.messages)
if closed
call Complete(a:job, exit_status, messages)
call s:show_errors(a:job, exit_status, messages)
endif
endfunction
let l:listtype = go#list#Type(self.for)
if a:exitval == 0
function cbs.close_cb(ch) dict closure
let closed = 1
if exited
let job = ch_getjob(a:ch)
call Complete(job, exit_status, messages)
call s:show_errors(job, exit_status, messages)
endif
endfunction
function! s:show_errors(job, exit_status, data) closure
let l:listtype = go#list#Type(for)
if a:exit_status == 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
return
endif
call self.show_errors(l:listtype)
endfunction
function cbs.show_errors(listtype) dict
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
try
execute cd self.jobdir
let errors = go#tool#ParseErrors(self.messages)
let errors = go#tool#FilterValids(errors)
finally
execute cd . fnameescape(self.dir)
endtry
if !len(errors)
" failed to parse errors, output the original content
call go#util#EchoError(self.messages + [self.dir])
let l:listtype = go#list#Type(for)
if len(a:data) == 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
return
endif
if self.winnr == winnr()
call go#list#Populate(a:listtype, errors, join(self.args))
call go#list#Window(a:listtype, len(errors))
if !empty(errors) && !self.bang
call go#list#JumpToFirst(a:listtype)
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
try
execute cd jobdir
let errors = go#tool#ParseErrors(a:data)
let errors = go#tool#FilterValids(errors)
finally
execute cd . fnameescape(dir)
endtry
if empty(errors)
" failed to parse errors, output the original content
call go#util#EchoError(messages + [dir])
return
endif
if winnr == winnr()
call go#list#Populate(l:listtype, errors, join(args))
call go#list#Window(l:listtype, len(errors))
if !bang
call go#list#JumpToFirst(l:listtype)
endif
endif
endfunction
" override callback handler if user provided it
if has_key(a:args, 'callback')
let cbs.callback = a:args.callback
endif
" override exit callback handler if user provided it
if has_key(a:args, 'exit_cb')
let cbs.exit_cb = a:args.exit_cb
endif
return cbs
endfunction
" vim: sw=2 ts=2 et

View file

@ -10,8 +10,8 @@ if !exists("g:go_metalinter_enabled")
let g:go_metalinter_enabled = ['vet', 'golint', 'errcheck']
endif
if !exists("g:go_metalinter_excludes")
let g:go_metalinter_excludes = []
if !exists("g:go_metalinter_disabled")
let g:go_metalinter_disabled = []
endif
if !exists("g:go_golint_bin")
@ -24,9 +24,9 @@ endif
function! go#lint#Gometa(autosave, ...) abort
if a:0 == 0
let goargs = shellescape(expand('%:p:h'))
let goargs = [expand('%:p:h')]
else
let goargs = go#util#Shelljoin(a:000)
let goargs = a:000
endif
let bin_path = go#path#CheckBinPath("gometalinter")
@ -44,8 +44,8 @@ function! go#lint#Gometa(autosave, ...) abort
let cmd += ["--enable=".linter]
endfor
for exclude in g:go_metalinter_excludes
let cmd += ["--exclude=".exclude]
for linter in g:go_metalinter_disabled
let cmd += ["--disable=".linter]
endfor
" gometalinter has a --tests flag to tell its linters whether to run
@ -54,14 +54,20 @@ function! go#lint#Gometa(autosave, ...) abort
" test files. One example of a linter that will not run against tests if
" we do not specify this flag is errcheck.
let cmd += ["--tests"]
" path
let cmd += [expand('%:p:h')]
else
" the user wants something else, let us use it.
let cmd += split(g:go_metalinter_command, " ")
endif
if a:autosave
" redraw so that any messages that were displayed while writing the file
" will be cleared
redraw
" Include only messages for the active buffer for autosave.
let cmd += [printf('--include=^%s:.*$', fnamemodify(expand('%:p'), ":."))]
endif
" gometalinter has a default deadline of 5 seconds.
"
" For async mode (s:lint_job), we want to override the default deadline only
@ -78,27 +84,26 @@ function! go#lint#Gometa(autosave, ...) abort
let cmd += ["--deadline=" . deadline]
endif
call s:lint_job({'cmd': cmd})
let cmd += goargs
call s:lint_job({'cmd': cmd}, a:autosave)
return
endif
" We're calling gometalinter synchronously.
let cmd += ["--deadline=" . get(g:, 'go_metalinter_deadline', "5s")]
let cmd += goargs
let [l:out, l:err] = go#util#Exec(cmd)
if a:autosave
" include only messages for the active buffer
let cmd += ["--include='^" . expand('%:p') . ".*$'"]
let l:listtype = go#list#Type("GoMetaLinterAutoSave")
else
let l:listtype = go#list#Type("GoMetaLinter")
endif
let meta_command = join(cmd, " ")
let out = go#util#System(meta_command)
let l:listtype = go#list#Type("GoMetaLinter")
if go#util#ShellError() == 0
redraw | echo
if l:err == 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
echon "vim-go: " | echohl Function | echon "[metalinter] PASS" | echohl None
@ -240,7 +245,7 @@ function! go#lint#ToggleMetaLinterAutoSave() abort
call go#util#EchoProgress("auto metalinter enabled")
endfunction
function s:lint_job(args)
function! s:lint_job(args, autosave)
let status_dir = expand('%:p:h')
let started_at = reltime()
@ -253,29 +258,28 @@ function s:lint_job(args)
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let l:listtype = go#list#Type("GoMetaLinter")
if a:autosave
let l:listtype = go#list#Type("GoMetaLinterAutoSave")
else
let l:listtype = go#list#Type("GoMetaLinter")
endif
let l:errformat = '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m'
let l:messages = []
let l:exited = 0
let l:closed = 0
let l:exit_status = 0
let l:winnr = winnr()
function! s:callback(chan, msg) closure
let old_errorformat = &errorformat
let &errorformat = l:errformat
if l:listtype == "locationlist"
lad a:msg
elseif l:listtype == "quickfix"
caddexpr a:msg
endif
let &errorformat = old_errorformat
" TODO(jinleileiking): give a configure to jump or not
let l:winnr = winnr()
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
exe l:winnr . "wincmd w"
call add(messages, a:msg)
endfunction
function! s:exit_cb(job, exitval) closure
let exited = 1
let exit_status = a:exitval
let status = {
\ 'desc': 'last status',
\ 'type': "gometaliner",
@ -293,16 +297,33 @@ function s:lint_job(args)
call go#statusline#Update(status_dir, status)
let errors = go#list#Get(l:listtype)
if empty(errors)
call go#list#Window(l:listtype, len(errors))
elseif has("patch-7.4.2200")
if l:listtype == 'quickfix'
call setqflist([], 'a', {'title': 'GoMetaLinter'})
else
call setloclist(0, [], 'a', {'title': 'GoMetaLinter'})
endif
if closed
call s:show_errors()
endif
endfunction
function! s:close_cb(ch) closure
let closed = 1
if exited
call s:show_errors()
endif
endfunction
function! s:show_errors() closure
" make sure the current window is the window from which gometalinter was
" run when the listtype is locationlist so that the location list for the
" correct window will be populated.
if l:listtype == 'locationlist'
exe l:winnr . "wincmd w"
endif
let l:errorformat = '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m'
call go#list#ParseFormat(l:listtype, l:errorformat, messages, 'GoMetaLinter')
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
if get(g:, 'go_echo_command_info', 1)
call go#util#EchoSuccess("linting finished")
@ -312,12 +333,11 @@ function s:lint_job(args)
let start_options = {
\ 'callback': funcref("s:callback"),
\ 'exit_cb': funcref("s:exit_cb"),
\ 'close_cb': funcref("s:close_cb"),
\ }
call job_start(a:args.cmd, start_options)
call go#list#Clean(l:listtype)
if get(g:, 'go_echo_command_info', 1)
call go#util#EchoProgress("linting started ...")
endif

View file

@ -0,0 +1,105 @@
func! Test_Gometa() abort
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
let expected = [
\ {'lnum': 5, 'bufnr': 3, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'}
\ ]
" clear the quickfix lists
call setqflist([], 'r')
" call go#lint#ToggleMetaLinterAutoSave from lint.vim so that the file will
" be autoloaded and the default for g:go_metalinter_enabled will be set so
" we can capture it to restore it after the test is run.
call go#lint#ToggleMetaLinterAutoSave()
" And restore it back to its previous value
call go#lint#ToggleMetaLinterAutoSave()
let orig_go_metalinter_enabled = g:go_metalinter_enabled
let g:go_metalinter_enabled = ['golint']
call go#lint#Gometa(0, $GOPATH . '/src/foo')
let actual = getqflist()
let start = reltime()
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
sleep 100m
let actual = getqflist()
endwhile
call gotest#assert_quickfix(actual, expected)
let g:go_metalinter_enabled = orig_go_metalinter_enabled
endfunc
func! Test_GometaWithDisabled() abort
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
let expected = [
\ {'lnum': 5, 'bufnr': 3, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'}
\ ]
" clear the quickfix lists
call setqflist([], 'r')
" call go#lint#ToggleMetaLinterAutoSave from lint.vim so that the file will
" be autoloaded and the default for g:go_metalinter_disabled will be set so
" we can capture it to restore it after the test is run.
call go#lint#ToggleMetaLinterAutoSave()
" And restore it back to its previous value
call go#lint#ToggleMetaLinterAutoSave()
let orig_go_metalinter_disabled = g:go_metalinter_disabled
let g:go_metalinter_disabled = ['vet']
call go#lint#Gometa(0, $GOPATH . '/src/foo')
let actual = getqflist()
let start = reltime()
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
sleep 100m
let actual = getqflist()
endwhile
call gotest#assert_quickfix(actual, expected)
let g:go_metalinter_disabled = orig_go_metalinter_disabled
endfunc
func! Test_GometaAutoSave() abort
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
let expected = [
\ {'lnum': 5, 'bufnr': 2, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported (golint)'}
\ ]
let winnr = winnr()
" clear the location lists
call setloclist(l:winnr, [], 'r')
" call go#lint#ToggleMetaLinterAutoSave from lint.vim so that the file will
" be autoloaded and the default for g:go_metalinter_autosave_enabled will be
" set so we can capture it to restore it after the test is run.
call go#lint#ToggleMetaLinterAutoSave()
" And restore it back to its previous value
call go#lint#ToggleMetaLinterAutoSave()
let orig_go_metalinter_autosave_enabled = g:go_metalinter_autosave_enabled
let g:go_metalinter_autosave_enabled = ['golint']
call go#lint#Gometa(1)
let actual = getloclist(l:winnr)
let start = reltime()
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
sleep 100m
let actual = getloclist(l:winnr)
endwhile
call gotest#assert_quickfix(actual, expected)
let g:go_metalinter_autosave_enabled = orig_go_metalinter_autosave_enabled
endfunc
" vim: sw=2 ts=2 et

View file

@ -78,16 +78,18 @@ function! go#list#ParseFormat(listtype, errformat, items, title) abort
" parse and populate the location list
let &errorformat = a:errformat
if a:listtype == "locationlist"
lgetexpr a:items
if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
else
cgetexpr a:items
if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif
endif
"restore back
let &errorformat = old_errorformat
try
if a:listtype == "locationlist"
lgetexpr a:items
if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
else
cgetexpr a:items
if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif
endif
finally
"restore back
let &errorformat = old_errorformat
endtry
endfunction
" Parse parses the given items based on the global errorformat and
@ -135,21 +137,22 @@ endfunction
" single file or buffer. Keys that begin with an underscore are not supported
" in g:go_list_type_commands.
let s:default_list_type_commands = {
\ "GoBuild": "quickfix",
\ "GoErrCheck": "quickfix",
\ "GoFmt": "locationlist",
\ "GoGenerate": "quickfix",
\ "GoInstall": "quickfix",
\ "GoLint": "quickfix",
\ "GoMetaLinter": "quickfix",
\ "GoModifyTags": "locationlist",
\ "GoRename": "quickfix",
\ "GoRun": "quickfix",
\ "GoTest": "quickfix",
\ "GoVet": "quickfix",
\ "_guru": "locationlist",
\ "_term": "locationlist",
\ "_job": "locationlist",
\ "GoBuild": "quickfix",
\ "GoErrCheck": "quickfix",
\ "GoFmt": "locationlist",
\ "GoGenerate": "quickfix",
\ "GoInstall": "quickfix",
\ "GoLint": "quickfix",
\ "GoMetaLinter": "quickfix",
\ "GoMetaLinterAutoSave": "locationlist",
\ "GoModifyTags": "locationlist",
\ "GoRename": "quickfix",
\ "GoRun": "quickfix",
\ "GoTest": "quickfix",
\ "GoVet": "quickfix",
\ "_guru": "locationlist",
\ "_term": "locationlist",
\ "_job": "locationlist",
\ }
function! go#list#Type(for) abort

View file

@ -45,9 +45,9 @@ function! go#path#Default() abort
return $GOPATH
endfunction
" HasPath checks whether the given path exists in GOPATH environment variable
" s:HasPath checks whether the given path exists in GOPATH environment variable
" or not
function! go#path#HasPath(path) abort
function! s:HasPath(path) abort
let go_paths = split(go#path#Default(), go#util#PathListSep())
let last_char = strlen(a:path) - 1
@ -94,11 +94,11 @@ function! go#path#Detect() abort
" gb vendor plugin
" (https://github.com/constabulary/gb/tree/master/cmd/gb-vendor)
let gb_vendor_root = src_path . "vendor" . go#util#PathSep()
if isdirectory(gb_vendor_root) && !go#path#HasPath(gb_vendor_root)
if isdirectory(gb_vendor_root) && !s:HasPath(gb_vendor_root)
let gopath = gb_vendor_root . go#util#PathListSep() . gopath
endif
if !go#path#HasPath(src_path)
if !s:HasPath(src_path)
let gopath = src_path . go#util#PathListSep() . gopath
endif
endif
@ -108,7 +108,7 @@ function! go#path#Detect() abort
if !empty(godeps_root)
let godeps_path = join([fnamemodify(godeps_root, ':p:h:h'), "Godeps", "_workspace" ], go#util#PathSep())
if !go#path#HasPath(godeps_path)
if !s:HasPath(godeps_path)
let gopath = godeps_path . go#util#PathListSep() . gopath
endif
endif
@ -164,7 +164,7 @@ function! go#path#CheckBinPath(binpath) abort
let $PATH = old_path
if go#util#IsUsingCygwinShell() == 1
return go#path#CygwinPath(binpath)
return s:CygwinPath(binpath)
endif
return binpath
@ -183,13 +183,13 @@ function! go#path#CheckBinPath(binpath) abort
let $PATH = old_path
if go#util#IsUsingCygwinShell() == 1
return go#path#CygwinPath(a:binpath)
return s:CygwinPath(a:binpath)
endif
return go_bin_path . go#util#PathSep() . basename
endfunction
function! go#path#CygwinPath(path)
function! s:CygwinPath(path)
return substitute(a:path, '\\', '/', "g")
endfunction

View file

@ -72,7 +72,11 @@ function! go#rename#Rename(bang, ...) abort
endfunction
function s:rename_job(args)
let exited = 0
let closed = 0
let exitval = 0
let messages = []
function! s:callback(chan, msg) closure
call add(messages, a:msg)
endfunction
@ -80,6 +84,9 @@ function s:rename_job(args)
let status_dir = expand('%:p:h')
function! s:exit_cb(job, exitval) closure
let exited = 1
let exitval = a:exitval
let status = {
\ 'desc': 'last status',
\ 'type': "gorename",
@ -92,12 +99,23 @@ function s:rename_job(args)
call go#statusline#Update(status_dir, status)
call s:parse_errors(a:exitval, a:args.bang, messages)
if closed
call s:parse_errors(a:exitval, a:args.bang, messages)
endif
endfunction
function! s:close_cb(ch) closure
let closed = 1
if exited
call s:parse_errors(exitval, a:args.bang, messages)
endif
endfunction
let start_options = {
\ 'callback': funcref("s:callback"),
\ 'exit_cb': funcref("s:exit_cb"),
\ 'close_cb': funcref("s:close_cb"),
\ }
call go#statusline#Update(status_dir, {

View file

@ -6,9 +6,12 @@ function! go#template#create() abort
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
execute cd . fnameescape(expand("%:p:h"))
let l:package_name = -1
let l:package_name = go#tool#PackageName()
if isdirectory(expand('%:p:h'))
execute cd . fnameescape(expand('%:p:h'))
let l:package_name = go#tool#PackageName()
endif
" if we can't figure out any package name(no Go files or non Go package
" files) from the directory create the template or use the cwd

View file

@ -44,10 +44,6 @@ function! go#term#newmode(bang, cmd, mode) abort
let id = termopen(a:cmd, job)
if l:winnr !=# winnr()
exe l:winnr . "wincmd w"
endif
execute cd . fnameescape(dir)
let job.id = id
@ -58,12 +54,13 @@ function! go#term#newmode(bang, cmd, mode) abort
let height = get(g:, 'go_term_height', winheight(0))
let width = get(g:, 'go_term_width', winwidth(0))
" we are careful how to resize. for example it's vertical we don't change
" we are careful how to resize. for example it's vsplit we don't change
" the height. The below command resizes the buffer
if a:mode == "split"
exe 'resize ' . height
elseif a:mode == "vertical"
if mode =~ "vertical" || mode =~ "vsplit" || mode =~ "vnew"
exe 'vertical resize ' . width
elseif mode =~ "split" || mode =~ "new"
exe 'resize ' . height
endif
" we also need to resize the pty, so there you go...
@ -71,6 +68,11 @@ function! go#term#newmode(bang, cmd, mode) abort
let s:jobs[id] = job
stopinsert
if l:winnr !=# winnr()
exe l:winnr . "wincmd w"
endif
return id
endfunction

View file

@ -0,0 +1,7 @@
package foo
import "fmt"
func MissingFooDoc() {
fmt.Println("missing doc")
}

View file

@ -0,0 +1,7 @@
package lint
import "fmt"
func MissingDoc() {
fmt.Println("missing doc")
}

View file

@ -0,0 +1,7 @@
package lint
import "fmt"
func AlsoMissingDoc() {
fmt.Println("missing doc")
}

View file

@ -0,0 +1 @@
/pkg

View file

@ -0,0 +1,7 @@
package main
import "fmt"
func main() {
fmt.Println("vim-go"
}

View file

@ -0,0 +1,7 @@
package mock
import "testing"
func Fail(t *testing.T) {
t.Fatal("another package badness")
}

View file

@ -0,0 +1,59 @@
package play
import (
"sync"
"testing"
"play/mock"
)
func TestTopSubHelper(t *testing.T) {
t.Run("sub", func(t *testing.T) {
t.Log("log message")
t.Error("sub badness")
})
t.Error("badness")
helper(t)
}
func TestMultiline(t *testing.T) {
t.Error("this is an error\nand a second line, too")
t.Error("\nthis is another error")
}
func TestSub(t *testing.T) {
t.Run("indented", func(t *testing.T) {
t.Error("this is a sub-test error\nand a second line, too")
})
}
func TestOK(t *testing.T) {
t.Run("log", func(t *testing.T) {
t.Log("goodness")
})
}
// TestMocked tests behavior similar to what users may experience when using
// github.com/golang/mock/gomock.
func TestMocked(t *testing.T) {
mock.Fail(t)
}
func TestPanic(t *testing.T) {
panic("worst ever")
}
func TestConcurrentPanic(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
panic("concurrent fail")
wg.Done()
}()
wg.Wait()
}
func helper(t *testing.T) {
t.Helper()
t.Fatal("helper badness")
}

View file

@ -0,0 +1,11 @@
package main
import "testing"
func TestHelloWorld(t *testing.T) {
t.Error("so long")
t.Run("sub", func(t *testing.T) {
t.Error("thanks for all the fish")
})
}

View file

@ -0,0 +1,47 @@
// Run a few parallel tests, all in parallel, using multiple techniques for
// causing the test to take a while so that the stacktraces resulting from a
// test timeout will contain several goroutines to avoid giving a false sense
// of confidence or creating error formats that don't account for the more
// complex scenarios that can occur with timeouts.
package main
import (
"testing"
"time"
)
func TestSleep(t *testing.T) {
t.Parallel()
time.Sleep(15 * time.Second)
t.Log("expected panic if run with timeout < 15s")
}
func TestRunning(t *testing.T) {
t.Parallel()
c := time.After(15 * time.Second)
Loop:
for {
select {
case <-c:
break Loop
default:
}
}
t.Log("expected panic if run with timeout < 15s")
}
func TestRunningAlso(t *testing.T) {
t.Parallel()
c := time.After(15 * time.Second)
Loop:
for {
select {
case <-c:
break Loop
default:
}
}
t.Log("expected panic if run with timeout < 15s")
}

View file

@ -1,6 +1,6 @@
" Test runs `go test` in the current directory. If compile is true, it'll
" compile the tests instead of running them (useful to catch errors in the
" test files). Any other argument is appendend to the final `go test` command
" test files). Any other argument is appended to the final `go test` command.
function! go#test#Test(bang, compile, ...) abort
let args = ["test"]
@ -72,6 +72,8 @@ function! go#test#Test(bang, compile, ...) abort
let command = "go " . join(args, ' ')
let out = go#tool#ExecuteInDir(command)
" TODO(bc): When the output is JSON, the JSON should be run through a
" filter to produce lines that are more easily described by errorformat.
let l:listtype = go#list#Type("GoTest")
@ -80,10 +82,8 @@ function! go#test#Test(bang, compile, ...) abort
execute cd fnameescape(expand("%:p:h"))
if go#util#ShellError() != 0
let errors = s:parse_errors(split(out, '\n'))
let errors = go#tool#FilterValids(errors)
call go#list#Populate(l:listtype, errors, command)
call go#list#ParseFormat(l:listtype, s:errorformat(), split(out, '\n'), command)
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:bang
call go#list#JumpToFirst(l:listtype)
@ -129,12 +129,16 @@ function! go#test#Func(bang, ...) abort
if a:0
call extend(args, a:000)
else
" only add this if no custom flags are passed
let timeout = get(g:, 'go_test_timeout', '10s')
call add(args, printf("-timeout=%s", timeout))
endif
call call('go#test#Test', args)
endfunction
function s:test_job(args) abort
function! s:test_job(args) abort
let status_dir = expand('%:p:h')
let started_at = reltime()
@ -153,12 +157,19 @@ function s:test_job(args) abort
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let l:exited = 0
let l:closed = 0
let l:exitval = 0
let messages = []
function! s:callback(chan, msg) closure
call add(messages, a:msg)
endfunction
function! s:exit_cb(job, exitval) closure
let exited = 1
let exitval = a:exitval
let status = {
\ 'desc': 'last status',
\ 'type': "test",
@ -192,19 +203,23 @@ function s:test_job(args) abort
call go#statusline#Update(status_dir, status)
let l:listtype = go#list#Type("GoTest")
if a:exitval == 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
return
if closed
call s:show_errors(a:args, l:exitval, messages)
endif
endfunction
call s:show_errors(a:args, a:exitval, messages)
function! s:close_cb(ch) closure
let closed = 1
if exited
call s:show_errors(a:args, l:exitval, messages)
endif
endfunction
let start_options = {
\ 'callback': funcref("s:callback"),
\ 'exit_cb': funcref("s:exit_cb"),
\ 'close_cb': funcref("s:close_cb"),
\ }
" pre start
@ -223,13 +238,23 @@ endfunction
" a quickfix compatible list of errors. It's intended to be used only for go
" test output.
function! s:show_errors(args, exit_val, messages) abort
let l:listtype = go#list#Type("GoTest")
if a:exit_val == 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
return
endif
" TODO(bc): When messages is JSON, the JSON should be run through a
" filter to produce lines that are more easily described by errorformat.
let l:listtype = go#list#Type("GoTest")
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
try
execute cd a:args.jobdir
let errors = s:parse_errors(a:messages)
let errors = go#tool#FilterValids(errors)
call go#list#ParseFormat(l:listtype, s:errorformat(), a:messages, join(a:args.cmd))
let errors = go#list#Get(l:listtype)
finally
execute cd . fnameescape(a:args.dir)
endtry
@ -242,7 +267,6 @@ function! s:show_errors(args, exit_val, messages) abort
endif
if a:args.winnr == winnr()
call go#list#Populate(l:listtype, errors, join(a:args.cmd))
call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:args.bang
call go#list#JumpToFirst(l:listtype)
@ -250,100 +274,152 @@ function! s:show_errors(args, exit_val, messages) abort
endif
endfunction
function! s:parse_errors(lines) abort
let errors = []
let paniced = 0 " signals whether all remaining lines should be included in errors.
let test = ''
" NOTE(arslan): once we get JSON output everything will be easier :)
" https://github.com/golang/go/issues/2981
for line in a:lines
let fatalerrors = matchlist(line, '^\(\(fatal error\|panic\):.*\)$')
if !empty(fatalerrors)
let paniced = 1
call add(errors, {"text": line})
continue
endif
let s:efm= ""
let s:go_test_show_name=0
if !paniced
" Matches failure lines. These lines always have zero or more leading spaces followed by '-- FAIL: ', following by the test name followed by a space the duration of the test in parentheses
" e.g.:
" '--- FAIL: TestSomething (0.00s)'
let failure = matchlist(line, '^ *--- FAIL: \(.*\) (.*)$')
if get(g:, 'go_test_prepend_name', 0)
if !empty(failure)
let test = failure[1] . ': '
continue
endif
endif
endif
function! s:errorformat() abort
" NOTE(arslan): once we get JSON output everything will be easier :).
" TODO(bc): When the output is JSON, the JSON should be run through a
" filter to produce lines that are more easily described by errorformat.
" https://github.com/golang/go/issues/2981.
let goroot = go#util#goroot()
let tokens = []
if paniced
" Matches lines in stacktraces produced by panic. The lines always have
" one or more leading tabs, followed by the path to the file. The file
" path is followed by a colon and then the line number within the file
" where the panic occurred. After that there's a space and hexadecimal
" number.
"
" e.g.:
" '\t/usr/local/go/src/time.go:1313 +0x5d'
let tokens = matchlist(line, '^\t\+\(.\{-}\.go\):\(\d\+\) \(+0x.*\)')
else
" Matches lines produced by `go test`. When the test binary cannot be
" compiled, the errors will be a filename, followed by a colon, followed
" by the line number, followed by another colon, a space, and then the
" compiler error.
" e.g.:
" 'quux.go:123: undefined: foo'
"
" When the test binary can be successfully compiled, but tests fail, all
" lines produced by `go test` that we're interested in start with zero
" or more spaces (increasing depth of subtests is represented by a
" similar increase in the number of spaces at the start of output lines.
" Top level tests start with zero leading spaces). Lines that indicate
" test status (e.g. RUN, FAIL, PASS) start after the spaces. Lines that
" indicate test failure location or test log message location (e.g.
" "testing.T".Log) begin with the appropriate number of spaces for the
" current test level, followed by a tab, a filename , a colon, the line
" number, another colon, a space, and the failure or log message.
"
" e.g.:
" '\ttime_test.go:30: Likely problem: the time zone files have not been installed.'
let tokens = matchlist(line, '^\%( *\t\+\)\?\(.\{-}\.go\):\(\d\+\):\s*\(.*\)')
endif
let show_name=get(g:, 'go_test_show_name', 0)
if s:efm != "" && s:go_test_show_name == show_name
return s:efm
endif
let s:go_test_show_name = show_name
if !empty(tokens) " Check whether the line may refer to a file.
" strip endlines of form ^M
let out = substitute(tokens[3], '\r$', '', '')
let file = fnamemodify(tokens[1], ':p')
" each level of test indents the test output 4 spaces. Capturing groups
" (e.g. \(\)) cannot be used in an errorformat, but non-capturing groups can
" (e.g. \%(\)).
let indent = '%\\%( %\\)%#'
" Preserve the line when the filename is not readable. This is an
" unusual case, but possible; any test that produces lines that match
" the pattern used in the matchlist assigned to tokens is a potential
" source of this condition. For instance, github.com/golang/mock/gomock
" will sometimes produce lines that satisfy this condition.
if !filereadable(file)
call add(errors, {"text": test . line})
continue
endif
" match compiler errors
let format = "%f:%l:%c: %m"
call add(errors, {
\ "filename" : file,
\ "lnum" : tokens[2],
\ "text" : test . out,
\ })
elseif paniced
call add(errors, {"text": line})
elseif !empty(errors)
" Preserve indented lines. This comes up especially with multi-line test output.
if match(line, '^ *\t\+') >= 0
call add(errors, {"text": line})
endif
endif
endfor
" ignore `go test -v` output for starting tests
let format .= ",%-G=== RUN %.%#"
" ignore `go test -v` output for passing tests
let format .= ",%-G" . indent . "--- PASS: %.%#"
return errors
" Match failure lines.
"
" Test failures start with '--- FAIL: ', followed by the test name followed
" by a space the duration of the test in parentheses
"
" e.g.:
" '--- FAIL: TestSomething (0.00s)'
if show_name
let format .= ",%G" . indent . "--- FAIL: %m (%.%#)"
else
let format .= ",%-G" . indent . "--- FAIL: %.%#"
endif
" Matches test output lines.
"
" All test output lines start with the test indentation and a tab, followed
" by the filename, a colon, the line number, another colon, a space, and the
" message. e.g.:
" '\ttime_test.go:30: Likely problem: the time zone files have not been installed.'
let format .= ",%A" . indent . "%\\t%\\+%f:%l: %m"
" also match lines that don't have a message (i.e. the message begins with a
" newline or is the empty string):
" e.g.:
" t.Errorf("\ngot %v; want %v", actual, expected)
" t.Error("")
let format .= ",%A" . indent . "%\\t%\\+%f:%l: "
" Match the 2nd and later lines of multi-line output. These lines are
" indented the number of spaces for the level of nesting of the test,
" followed by two tabs, followed by the message.
"
" Treat these lines as if they are stand-alone lines of output by using %G.
" It would also be valid to treat these lines as if they were the
" continuation of a multi-line error by using %C instead of %G, but that
" would also require that all test errors using a %A or %E modifier to
" indicate that they're multiple lines of output, but in that case the lines
" get concatenated in the quickfix list, which is not what users typically
" want when writing a newline into their test output.
let format .= ",%G" . indent . "%\\t%\\{2}%m"
" set the format for panics.
" handle panics from test timeouts
let format .= ",%+Gpanic: test timed out after %.%\\+"
" handle non-timeout panics
" In addition to 'panic', check for 'fatal error' to support older versions
" of Go that used 'fatal error'.
"
" Panics come in two flavors. When the goroutine running the tests panics,
" `go test` recovers and tries to exit more cleanly. In that case, the panic
" message is suffixed with ' [recovered]'. If the panic occurs in a
" different goroutine, it will not be suffixed with ' [recovered]'.
let format .= ",%+Afatal error: %.%# [recovered]"
let format .= ",%+Apanic: %.%# [recovered]"
let format .= ",%+Afatal error: %.%#"
let format .= ",%+Apanic: %.%#"
" Match address lines in stacktraces produced by panic.
"
" Address lines in the stack trace have leading tabs, followed by the path
" to the file. The file path is followed by a colon and then the line number
" within the file where the panic occurred. After that there's a space and
" hexadecimal number.
"
" e.g.:
" '\t/usr/local/go/src/time.go:1313 +0x5d'
" panicaddress, and readyaddress are identical except for
" panicaddress sets the filename and line number.
let panicaddress = "%\\t%f:%l +0x%[0-9A-Fa-f]%\\+"
let readyaddress = "%\\t%\\f%\\+:%\\d%\\+ +0x%[0-9A-Fa-f]%\\+"
" stdlib address is identical to readyaddress, except it matches files
" inside GOROOT.
let stdlibaddress = "%\\t" . goroot . "%\\f%\\+:%\\d%\\+ +0x%[0-9A-Fa-f]%\\+"
" Match and ignore the running goroutine line.
let format .= ",%-Cgoroutine %\\d%\\+ [running]:"
" Match address lines that refer to stdlib, but consider them informational
" only. This is to catch the lines after the first address line in the
" running goroutine of a panic stack trace. Ideally, this wouldn't be
" necessary, but when a panic happens in the goroutine running a test, it's
" recovered and another panic is created, so the stack trace actually has
" the line that caused the original panic a couple of addresses down the
" stack.
let format .= ",%-C" . stdlibaddress
" Match address lines in the first matching goroutine. This means the panic
" message will only be shown as the error message in the first address of
" the running goroutine's stack.
let format .= ",%Z" . panicaddress
" Match and ignore panic address without being part of a multi-line message.
" This is to catch those lines that come after the top most non-standard
" library line in stack traces.
let format .= ",%-G" . readyaddress
" Match and ignore exit status lines (produced when go test panics) whether
" part of a multi-line message or not, because these lines sometimes come
" before and sometimes after panic stacktraces.
let format .= ",%-Cexit status %[0-9]%\\+"
"let format .= ",exit status %[0-9]%\\+"
" Match and ignore exit failure lines whether part of a multi-line message
" or not, because these lines sometimes come before and sometimes after
" panic stacktraces.
let format .= ",%-CFAIL%\\t%.%#"
"let format .= ",FAIL%\\t%.%#"
" Match and ignore everything else in multi-line messages.
let format .= ",%-C%.%#"
" Match and ignore everything else not in a multi-line message:
let format .= ",%-G%.%#"
let s:efm = format
return s:efm
endfunction
" vim: sw=2 ts=2 et

View file

@ -0,0 +1,121 @@
func! Test_GoTest() abort
let expected = [
\ {'lnum': 12, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'log message'},
\ {'lnum': 13, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'sub badness'},
\ {'lnum': 15, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'badness'},
\ {'lnum': 16, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'helper badness'},
\ {'lnum': 20, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is an error'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'and a second line, too'},
\ {'lnum': 21, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': ''},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is another error'},
\ {'lnum': 26, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is a sub-test error'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'and a second line, too'},
\ {'lnum': 6, 'bufnr': 3, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'another package badness'},
\ {'lnum': 43, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'panic: worst ever [recovered]'}
\ ]
call s:test('play/play_test.go', expected)
endfunc
func! Test_GoTestConcurrentPanic()
let expected = [
\ {'lnum': 50, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'panic: concurrent fail'}
\ ]
call s:test('play/play_test.go', expected, "-run", "TestConcurrentPanic")
endfunc
func! Test_GoTestVerbose() abort
let expected = [
\ {'lnum': 12, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'log message'},
\ {'lnum': 13, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'sub badness'},
\ {'lnum': 15, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'badness'},
\ {'lnum': 16, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'helper badness'},
\ {'lnum': 20, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is an error'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'and a second line, too'},
\ {'lnum': 21, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': ''},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is another error'},
\ {'lnum': 26, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is a sub-test error'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'and a second line, too'},
\ {'lnum': 32, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'goodness'},
\ {'lnum': 6, 'bufnr': 3, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'another package badness'},
\ {'lnum': 43, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'panic: worst ever [recovered]'}
\ ]
call s:test('play/play_test.go', expected, "-v")
endfunc
func! Test_GoTestCompilerError() abort
let expected = [
\ {'lnum': 6, 'bufnr': 6, 'col': 22, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'syntax error: unexpected newline, expecting comma or )'}
\ ]
call s:test('compilerror/compilerror_test.go', expected)
endfunc
func! Test_GoTestTimeout() abort
let expected = [
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'panic: test timed out after 500ms'}
\ ]
let g:go_test_timeout="500ms"
call s:test('timeout/timeout_test.go', expected)
unlet g:go_test_timeout
endfunc
func! Test_GoTestShowName() abort
let expected = [
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld'},
\ {'lnum': 6, 'bufnr': 9, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'so long'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld/sub'},
\ {'lnum': 9, 'bufnr': 9, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'},
\ ]
let g:go_test_show_name=1
call s:test('showname/showname_test.go', expected)
let g:go_test_show_name=0
endfunc
func! s:test(file, expected, ...) abort
if has('nvim')
" nvim mostly shows test errors correctly, but the the expected errors are
" slightly different; buffer numbers are not the same and stderr doesn't
" seem to be redirected to the job, so the lines from the panic aren't in
" the output to be parsed, and hence are not in the quickfix lists. Once
" those two issues are resolved, this early return should be removed so
" the tests will run for Neovim, too.
return
endif
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/test'
silent exe 'e ' . $GOPATH . '/src/' . a:file
" clear the quickfix lists
call setqflist([], 'r')
let args = [1,0]
if a:0
let args += a:000
endif
" run the tests
call call(function('go#test#Test'), args)
let actual = getqflist()
let start = reltime()
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
sleep 100m
let actual = getqflist()
endwhile
for item in actual
let item.text = s:normalize_durations(item.text)
endfor
for item in a:expected
let item.text = s:normalize_durations(item.text)
endfor
call gotest#assert_quickfix(actual, a:expected)
endfunc
func! s:normalize_durations(str) abort
return substitute(a:str, '[0-9]\+\(\.[0-9]\+\)\?s', '0.000s', 'g')
endfunc
" vim: sw=2 ts=2 et

View file

@ -20,10 +20,10 @@ fun! gotest#write_file(path, contents) abort
" Set cursor.
let l:lnum = 1
for l:line in a:contents
let l:m = match(l:line, '')
let l:m = match(l:line, "\x1f")
if l:m > -1
call setpos('.', [0, l:lnum, l:m, 0])
call setline('.', substitute(getline('.'), '', '', ''))
call setline('.', substitute(getline('.'), "\x1f", '', ''))
break
endif
@ -102,5 +102,29 @@ fun! gotest#assert_fixture(path) abort
call gotest#assert_buffer(0, l:want)
endfun
func! gotest#assert_quickfix(got, want) abort
call assert_equal(len(a:want), len(a:got), "number of errors")
if len(a:want) != len(a:got)
call assert_equal(a:want, a:got)
return
endif
let i = 0
while i < len(a:want)
let want_item = a:want[i]
let got_item = a:got[i]
let i += 1
call assert_equal(want_item.bufnr, got_item.bufnr, "bufnr")
call assert_equal(want_item.lnum, got_item.lnum, "lnum")
call assert_equal(want_item.col, got_item.col, "col")
call assert_equal(want_item.vcol, got_item.vcol, "vcol")
call assert_equal(want_item.nr, got_item.nr, "nr")
call assert_equal(want_item.pattern, got_item.pattern, "pattern")
call assert_equal(want_item.text, got_item.text, "text")
call assert_equal(want_item.type, got_item.type, "type")
call assert_equal(want_item.valid, got_item.valid, "valid")
endwhile
endfunc
" vim: sw=2 ts=2 et

View file

@ -128,7 +128,7 @@ The following plugins are supported for use with vim-go:
* Real-time completion (Vim):
https://github.com/Shougo/neocomplete.vim
* Real-time completion (Neovim):
* Real-time completion (Neovim and Vim 8):
https://github.com/Shougo/deoplete.nvim and
https://github.com/zchee/deoplete-go
@ -797,6 +797,9 @@ CTRL-t
Toggles |'g:go_metalinter_autosave'|.
By default, `gometalinter` messages will be shown in the |location-list|
window. The list to use can be set using |'g:go_list_type_commands'|.
*:GoTemplateAutoCreateToggle*
:GoTemplateAutoCreateToggle
@ -1102,12 +1105,12 @@ into the statusline. This function is also used for |'g:go_auto_type_info'|.
==============================================================================
SETTINGS *go-settings*
*'g:go_test_prepend_name'*
*'g:go_test_show_name'*
Prepend the name of the failed test to each test message generated by a failed
Show the name of each failed test before the errors and logs output by the
test. By default it is disabled.
>
let g:go_test_prepend_name = 0
let g:go_test_show_name = 0
<
*'g:go_test_timeout'*
@ -1250,7 +1253,7 @@ Maximum height for the GoDoc window created with |:GoDoc|. Default is 20. >
*'g:go_doc_url'*
godoc server URL used when |:GoDocBrowser| is used. Change if you want to use
a private internal service. Default is 'https://godoc.org'.
a private internal service. Default is 'https://godoc.org'.
>
let g:go_doc_url = 'https://godoc.org'
<
@ -1371,8 +1374,12 @@ function when using the `af` text object. By default it's enabled. >
*'g:go_metalinter_autosave'*
Use this option to auto |:GoMetaLinter| on save. Only linter messages for
the active buffer will be shown. By default it's disabled >
the active buffer will be shown.
By default, `gometalinter` messages will be shown in the |location-list|
window. The list to use can be set using |'g:go_list_type_commands'|.
By default it's disabled >
let g:go_metalinter_autosave = 0
<
*'g:go_metalinter_autosave_enabled'*
@ -1384,17 +1391,17 @@ default it's using `vet` and `golint`.
<
*'g:go_metalinter_enabled'*
Specifies the currently enabled linters for the |:GoMetaLinter| command. By
default it's using `vet`, `golint` and `errcheck`.
Specifies the linters to enable for the |:GoMetaLinter| command. By default
it's using `vet`, `golint` and `errcheck`.
>
let g:go_metalinter_enabled = ['vet', 'golint', 'errcheck']
<
*'g:go_metalinter_excludes'*
*'g:go_metalinter_disabled'*
Specifies the linters to be excluded from the |:GoMetaLinter| command. By
default it's empty
Specifies the linters to disable for the |:GoMetaLinter| command. By default
it's empty
>
let g:go_metalinter_excludes = []
let g:go_metalinter_disabled = []
<
*'g:go_metalinter_command'*
@ -1437,9 +1444,9 @@ Specifies the type of list to use for command outputs (such as errors from
builds, results from static analysis commands, etc...). When an expected key
is not present in the dictionary, |'g:go_list_type'| will be used instead.
Supported keys are "GoBuild", "GoErrCheck", "GoFmt", "GoInstall", "GoLint",
"GoMetaLinter", "GoModifyTags" (used for both :GoAddTags and :GoRemoveTags),
"GoRename", "GoRun", and "GoTest". Supported values for each command are
"quickfix" and "locationlist".
"GoMetaLinter", "GoMetaLinterAutoSave", "GoModifyTags" (used for both
:GoAddTags and :GoRemoveTags), "GoRename", "GoRun", and "GoTest". Supported
values for each command are "quickfix" and "locationlist".
>
let g:go_list_type_commands = {}
<
@ -1725,7 +1732,7 @@ Highlight operators such as `:=` , `==`, `-=`, etc.
<
*'g:go_highlight_functions'*
Highlight function names.
Highlight function and method declarations.
>
let g:go_highlight_functions = 0
<
@ -1737,11 +1744,11 @@ declarations. Setting this implies the functionality from
>
let g:go_highlight_function_arguments = 0
<
*'g:go_highlight_methods'*
*'g:go_highlight_function_calls'*
Highlight method names.
Highlight function and method calls.
>
let g:go_highlight_methods = 0
let g:go_highlight_function_calls = 0
<
*'g:go_highlight_types'*

View file

@ -1,3 +1,5 @@
" vint: -ProhibitAutocmdWithNoGroup
" We take care to preserve the user's fileencodings and fileformats,
" because those settings are global (not buffer local), yet we want
" to override them for loading Go files, which are defined to be UTF-8.
@ -18,17 +20,15 @@ function! s:gofiletype_post()
let &g:fileencodings = s:current_fileencodings
endfunction
augroup vim-go-filetype
autocmd!
au BufNewFile *.go setfiletype go | setlocal fileencoding=utf-8 fileformat=unix
au BufRead *.go call s:gofiletype_pre("go")
au BufReadPost *.go call s:gofiletype_post()
" Note: should not use augroup in ftdetect (see :help ftdetect)
au BufNewFile *.go setfiletype go | setlocal fileencoding=utf-8 fileformat=unix
au BufRead *.go call s:gofiletype_pre("go")
au BufReadPost *.go call s:gofiletype_post()
au BufNewFile *.s setfiletype asm | setlocal fileencoding=utf-8 fileformat=unix
au BufRead *.s call s:gofiletype_pre("asm")
au BufReadPost *.s call s:gofiletype_post()
au BufNewFile *.s setfiletype asm | setlocal fileencoding=utf-8 fileformat=unix
au BufRead *.s call s:gofiletype_pre("asm")
au BufReadPost *.s call s:gofiletype_post()
au BufRead,BufNewFile *.tmpl set filetype=gohtmltmpl
augroup end
au BufRead,BufNewFile *.tmpl set filetype=gohtmltmpl
" vim: sw=2 ts=2 et

View file

@ -128,21 +128,21 @@ abbr if err := ...; err != nil { ... }
# error snippet
snippet errn
abbr if err != nil { ... }
abbr if err != nil { return err }
if err != nil {
return err
}
${0}
# error snippet in TestFunc
snippet errt
abbr if err != nil { ... }
abbr if err != nil { t.Fatal(err) }
if err != nil {
t.Fatal(err)
}
# error snippet in log.Fatal
snippet errl
abbr if err != nil { ... }
abbr if err != nil { log.Fatal(err) }
if err != nil {
log.Fatal(err)
}
@ -157,7 +157,7 @@ abbr if err != nil { return [...], err }
# error snippet handle and return
snippet errh
abbr if err != nil { return }
abbr if err != nil { ... return }
if err != nil {
${1}
return
@ -166,7 +166,7 @@ abbr if err != nil { return }
# error snippet with panic
snippet errp
abbr if err != nil { ... }
abbr if err != nil { panic(...) }
if err != nil {
panic(${1})
}

View file

@ -69,7 +69,7 @@ find "$vimgodir" -name '*_test.vim' | while read test_file; do
"$vimgodir/scripts/run-vim" $coverage $vim -e \
+"silent e $test_file" \
+"let g:test_verbose=$verbose" \
-S ./scripts/runtest.vim || (
-S ./scripts/runtest.vim < /dev/null || (
# If Vim exits with non-0 it's almost certainly a bug in the test runner;
# should very rarely happen in normal usage.
echo 'test runner failure'

View file

@ -42,8 +42,8 @@ if !exists("g:go_highlight_function_arguments")
let g:go_highlight_function_arguments = 0
endif
if !exists("g:go_highlight_methods")
let g:go_highlight_methods = 0
if !exists("g:go_highlight_function_calls")
let g:go_highlight_function_calls = 0
endif
if !exists("g:go_highlight_fields")
@ -202,7 +202,19 @@ else
endif
if g:go_highlight_format_strings != 0
syn match goFormatSpecifier /\([^%]\(%%\)*\)\@<=%[-#0 +]*\%(\*\|\d\+\)\=\%(\.\%(\*\|\d\+\)\)*[vTtbcdoqxXUeEfgGsp]/ contained containedin=goString
" [n] notation is valid for specifying explicit argument indexes
" 1. Match a literal % not preceded by a %.
" 2. Match any number of -, #, 0, space, or +
" 3. Match * or [n]* or any number or nothing before a .
" 4. Match * or [n]* or any number or nothing after a .
" 5. Match [n] or nothing before a verb
" 6. Match a formatting verb
syn match goFormatSpecifier /\
\([^%]\(%%\)*\)\
\@<=%[-#0 +]*\
\%(\%(\%(\[\d\+\]\)\=\*\)\|\d\+\)\=\
\%(\.\%(\%(\%(\[\d\+\]\)\=\*\)\|\d\+\)\=\)\=\
\%(\[\d\+\]\)\=[vTtbcdoqxXUeEfFgGsp]/ contained containedin=goString,goRawString
hi def link goFormatSpecifier goSpecialString
endif
@ -348,7 +360,6 @@ hi def link goOperator Operator
" Functions;
if g:go_highlight_functions isnot 0 || g:go_highlight_function_arguments isnot 0
syn match goFunctionCall /\w\+\ze(/ contains=goBuiltins,goDeclaration
syn match goDeclaration /\<func\>/ nextgroup=goReceiver,goFunction,goSimpleArguments skipwhite skipnl
syn match goReceiverVar /\w\+\ze\s\+\(\w\|\*\)/ nextgroup=goPointerOperator,goReceiverType skipwhite skipnl contained
syn match goPointerOperator /\*/ nextgroup=goReceiverType contained skipwhite skipnl
@ -367,13 +378,12 @@ else
syn keyword goDeclaration func
endif
hi def link goFunction Function
hi def link goFunctionCall Type
" Methods;
if g:go_highlight_methods != 0
syn match goMethodCall /\.\w\+\ze(/hs=s+1
" Function calls;
if g:go_highlight_function_calls != 0
syn match goFunctionCall /\w\+\ze(/ contains=goBuiltins,goDeclaration
endif
hi def link goMethodCall Type
hi def link goFunctionCall Type
" Fields;
if g:go_highlight_fields != 0

View file

@ -0,0 +1,2 @@
build
/doc/tags

View file

@ -0,0 +1,34 @@
language: vim
os:
- linux
- osx
env:
- TEST=package
- TEST=latest
before_script: |
if [ "$TEST" = "package" ]; then
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
sudo apt-get -y update
sudo apt-get -y install vim
fi
else
cd ..
git clone --depth 1 https://github.com/vim/vim
cd vim
./configure --with-features=huge
make
sudo make install
export PATH="/usr/local/bin:$PATH"
cd "$TRAVIS_BUILD_DIR"
fi
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
sudo -H easy_install pip
fi
sudo -H pip install virtualenv
script:
- make test
- make doc

View file

@ -0,0 +1,58 @@
# CONTRIBUTING
These contributing guidelines were accepted rather late in the history of this plugin, after much code had already been written.
If you find any existing behavior which does not conform to these guidelines, please correct it and send a pull request.
## General Rules
Every non local identifier must start with `g:vim_markdown_`.
## Documentation
Every new feature must be documented under in the [README.md](README.md). Documentation must be written in [GFM](https://help.github.com/articles/github-flavored-markdown) since GitHub itself is the primary to HTML converter used. In particular, remember that GFM adds line breaks at single newlines, so just forget about the 70 characters wide rule.
Vim help file [doc/vim-markdown.txt](doc/vim-markdown.txt) will be generated from [README.md](README.md) by `make doc` using [vim-tools](https://github.com/xolox/vim-tools).
## Markdown Flavors
There are many flavors of markdown, each one with an unique feature set. This plugin uses the following strategy to deal with all those flavors:
- Features from the [original markdown](http://daringfireball.net/projects/markdown/syntax) are turned on by default. They may not even have an option that turns them off.
- Features from other markdown flavors *must* have an option that turns them on or off. If the feature is common enough across multiple versions of markdown, it may be turned on by default. This shall be decided by the community when the merge request is done.
- If possible, cite the exact point in the documentation of the flavor where a feature is specified. If the feature is not documented, you may also reference the source code itself of the implementation. This way, people who do not know that flavor can check if your implementation is correct.
- Do not use the name of a flavor for a feature that is used across multiple flavors. Instead, create a separate flavor option, that automatically sets each feature.
For example, fenced code blocks (putting code between pairs of three backticks) is not part of the original markdown, but is supported by [GFM](https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks) and [Jekyll](http://jekyllrb.com/docs/configuration/).
Therefore, instead of creating an option `g:vim_markdown_gfm_fenced_code_block`, and an option `g:vim_markdown_jekyll_fenced_code_block`, create a single option `g:vim_markdown_fenced_code_block`.
Next, if there are many more than one Jekyll feature options, create a `g:vim_markdown_jekyll` option that turns them all on at once.
## Style
When choosing between multiple valid Markdown syntaxes, the default behavior must be that specified at: <http://www.cirosantilli.com/markdown-styleguide>
If you wish to have a behavior that differs from that style guide, add an option to turn it on or off, and leave it off by default.
## Tests
All new features must have unit tests.
## Issues
Issues are tracked within GitHub.
When reporting issues, your report is more effective if you include a minimal example file that reproduces the problem. Try to trim out as much as possible, until you have the smallest possible file that still reproduces the issue. Paste the example inline into your issue report, quoted using four spaces at the beginning of each line, like this example from issue [#189](https://github.com/plasticboy/vim-markdown/issues/189):
```
Minimal example:
```
=
```
bad!
```

View file

@ -0,0 +1,82 @@
VIMDIR=$(DESTDIR)/usr/share/vim
ADDONS=${VIMDIR}/addons
REGISTRY=${VIMDIR}/registry
all:
install:
mkdir -pv ${ADDONS}/ftdetect
cp -v ftdetect/markdown.vim ${ADDONS}/ftdetect/markdown.vim
mkdir -pv ${ADDONS}/ftplugin
cp -v ftplugin/markdown.vim ${ADDONS}/ftplugin/markdown.vim
mkdir -pv ${ADDONS}/syntax
cp -v syntax/markdown.vim ${ADDONS}/syntax/markdown.vim
mkdir -pv ${ADDONS}/after/ftplugin
cp -v after/ftplugin/markdown.vim ${ADDONS}/after/ftplugin/markdown.vim
mkdir -pv ${ADDONS}/indent
cp -v indent/markdown.vim ${ADDONS}/indent/markdown.vim
mkdir -pv ${ADDONS}/doc
cp -v doc/vim-markdown.txt ${ADDONS}/doc/vim-markdown.txt
mkdir -pv ${REGISTRY}
cp -v registry/markdown.yaml ${REGISTRY}/markdown.yaml
test: build/tabular build/vim-toml build/vim-json build/vader.vim
test/run-tests.sh
.PHONY: test
update: build/tabular build/vim-toml build/vim-json build/vader.vim
cd build/tabular && git pull
cd build/vim-toml && git pull
cd build/vim-json && git pull
cd build/vader.vim && git pull
.PHONY: update
build/tabular: | build
git clone https://github.com/godlygeek/tabular build/tabular
build/vim-toml: | build
git clone https://github.com/cespare/vim-toml build/vim-toml
build/vim-json: | build
git clone https://github.com/elzr/vim-json build/vim-json
build/vader.vim: | build
git clone https://github.com/junegunn/vader.vim build/vader.vim
build:
mkdir build
doc: build/html2vimdoc build/vim-tools
sed -e '/^\[!\[Build Status\]/d' \
-e '/^1\. \[/d' README.md > doc/tmp.md # remove table of contents
build/html2vimdoc/bin/python build/vim-tools/html2vimdoc.py -f vim-markdown \
doc/tmp.md | \
sed -E -e "s/[[:space:]]*$$//" -e "# remove trailing spaces" \
-e "/^.{79,}\|$$/ {" -e "# wrap table of contents over 79" \
-e "h" -e "# save the matched line to the hold space" \
-e "s/^(.*) (\|[^|]*\|)$$/\1/" -e "# make content title" \
-e "p" -e "# print title" \
-e "g" -e "# restore the matched line" \
-e "s/^.* (\|[^|]*\|)$$/ \1/" -e "# make link" \
-e ":c" -e "s/^(.{1,78})$$/ \1/" -e "tc" -e "# align right" \
-e "}" \
-e "/^- '[^']*':( |$$)/ {" \
-e "h" -e "# save the matched line to the hold space" \
-e "s/^- '([^']{3,})':.*/ \*\1\*/" -e "# make command reference" \
-e "s/^- '([^']{1,2})':.*/ \*vim-markdown-\1\*/" -e "# short command" \
-e ":a" -e "s/^(.{1,78})$$/ \1/" -e "ta" -e "# align right" \
-e "G" -e "# append the matched line after the command reference" \
-e "}" > doc/vim-markdown.txt && rm -f doc/tmp.md
.PHONY: doc
# Prerequire Python and virtualenv.
# $ sudo pip install virtualenv
# Create the virtual environment.
# Install the dependencies.
build/html2vimdoc: | build
virtualenv build/html2vimdoc
build/html2vimdoc/bin/pip install beautifulsoup coloredlogs==4.0 markdown
build/vim-tools: | build
git clone https://github.com/xolox/vim-tools.git build/vim-tools

View file

@ -1,34 +0,0 @@
# Vim Markdown runtime files
This is the development version of Vim's included syntax highlighting and
filetype plugins for Markdown. Generally you don't need to install these if
you are running a recent version of Vim.
One difference between this repository and the upstream files in Vim is that
the former forces `*.md` as Markdown, while the latter detects it as Modula-2,
with an exception for `README.md`. If you'd like to force Markdown without
installing from this repository, add the following to your vimrc:
autocmd BufNewFile,BufReadPost *.md set filetype=markdown
If you want to enable fenced code block syntax highlighting in your markdown
documents you can enable it in your `.vimrc` like so:
let g:markdown_fenced_languages = ['html', 'python', 'bash=sh']
To disable markdown syntax concealing add the following to your vimrc:
let g:markdown_syntax_conceal = 0
Syntax highlight is synchronized in 50 lines. It may cause collapsed
highlighting at large fenced code block.
In the case, please set larger value in your vimrc:
let g:markdown_minlines = 100
Note that setting too large value may cause bad performance on highlighting.
## License
Copyright © Tim Pope. Distributed under the same terms as Vim itself.
See `:help license`.

View file

@ -0,0 +1,397 @@
# Vim Markdown
[![Build Status](https://travis-ci.org/plasticboy/vim-markdown.svg)](https://travis-ci.org/plasticboy/vim-markdown)
Syntax highlighting, matching rules and mappings for [the original Markdown](http://daringfireball.net/projects/markdown/) and extensions.
1. [Installation](#installation)
1. [Options](#options)
1. [Mappings](#mappings)
1. [Commands](#commands)
1. [Credits](#credits)
1. [License](#license)
## Installation
If you use [Vundle](https://github.com/gmarik/vundle), add the following line to your `~/.vimrc`:
```vim
Plugin 'godlygeek/tabular'
Plugin 'plasticboy/vim-markdown'
```
The `tabular` plugin must come *before* `vim-markdown`.
Then run inside Vim:
```vim
:so ~/.vimrc
:PluginInstall
```
If you use [Pathogen](https://github.com/tpope/vim-pathogen), do this:
```sh
cd ~/.vim/bundle
git clone https://github.com/plasticboy/vim-markdown.git
```
To install without Pathogen using the Debian [vim-addon-manager](http://packages.qa.debian.org/v/vim-addon-manager.html), do this:
```sh
git clone https://github.com/plasticboy/vim-markdown.git
cd vim-markdown
sudo make install
vim-addon-manager install markdown
```
If you are not using any package manager, download the [tarball](https://github.com/plasticboy/vim-markdown/archive/master.tar.gz) and do this:
```sh
cd ~/.vim
tar --strip=1 -zxf vim-markdown-master.tar.gz
```
## Options
### Disable Folding
Add the following line to your `.vimrc` to disable the folding configuration:
```vim
let g:vim_markdown_folding_disabled = 1
```
This option only controls Vim Markdown specific folding configuration.
To enable/disable folding use Vim's standard folding configuration.
```vim
set [no]foldenable
```
### Change fold style
To fold in a style like [python-mode](https://github.com/klen/python-mode), add the following to your `.vimrc`:
```vim
let g:vim_markdown_folding_style_pythonic = 1
```
Level 1 heading which is served as a document title is not folded.
`g:vim_markdown_folding_level` setting is not active with this fold style.
To prevent foldtext from being set add the following to your `.vimrc`:
```vim
let g:vim_markdown_override_foldtext = 0
```
### Set header folding level
Folding level is a number between 1 and 6. By default, if not specified, it is set to 1.
```vim
let g:vim_markdown_folding_level = 6
```
Tip: it can be changed on the fly with:
```vim
:let g:vim_markdown_folding_level = 1
:edit
```
### Disable Default Key Mappings
Add the following line to your `.vimrc` to disable default key mappings:
```vim
let g:vim_markdown_no_default_key_mappings = 1
```
You can also map them by yourself with `<Plug>` mappings.
### Enable TOC window auto-fit
Allow for the TOC window to auto-fit when it's possible for it to shrink.
It never increases its default size (half screen), it only shrinks.
```vim
let g:vim_markdown_toc_autofit = 1
```
### Text emphasis restriction to single-lines
By default text emphasis works across multiple lines until a closing token is found. However, it's possible to restrict text emphasis to a single line (ie, for it to be applied a closing token must be found on the same line). To do so:
```vim
let g:vim_markdown_emphasis_multiline = 0
```
### Syntax Concealing
Concealing is set for some syntax.
For example, conceal `[link text](link url)` as just `link text`.
Also, `_italic_` and `*italic*` will conceal to just _italic_.
Similarly `__bold__`, `**bold**`, `___italic bold___`, and `***italic bold***`
will conceal to just __bold__, **bold**, ___italic bold___, and ***italic bold*** respectively.
To enable conceal use Vim's standard conceal configuration.
```vim
set conceallevel=2
```
To disable conceal regardless of `conceallevel` setting, add the following to your `.vimrc`:
```vim
let g:vim_markdown_conceal = 0
```
To disable math conceal with LaTeX math syntax enabled, add the following to your `.vimrc`:
```vim
let g:tex_conceal = ""
let g:vim_markdown_math = 1
```
### Fenced code block languages
You can use filetype name as fenced code block languages for syntax highlighting.
If you want to use different name from filetype, you can add it in your `.vimrc` like so:
```vim
let g:vim_markdown_fenced_languages = ['csharp=cs']
```
This will cause the following to be highlighted using the `cs` filetype syntax.
```csharp
...
```
Default is `['c++=cpp', 'viml=vim', 'bash=sh', 'ini=dosini']`.
### Follow named anchors
This feature allows ge to follow named anchors in links of the form
`file#anchor` or just `#anchor`, where file may omit the `.md` extension as
usual. Two variables control its operation:
```vim
let g:vim_markdown_follow_anchor = 1
```
This tells vim-markdown whether to attempt to follow a named anchor in a link or
not. When it is 1, and only if a link can be split in two parts by the pattern
'#', then the first part is interpreted as the file and the second one as the
named anchor. This also includes urls of the form `#anchor`, for which the first
part is considered empty, meaning that the target file is the current one. After
the file is opened, the anchor will be searched.
Default is `0`.
```vim
let g:vim_markdown_anchorexpr = "'<<'.v:anchor.'>>'"
```
This expression will be evaluated substituting `v:anchor` with a quoted string
that contains the anchor to visit. The result of the evaluation will become the
real anchor to search in the target file. This is useful in order to convert
anchors of the form, say, `my-section-title` to searches of the form `My Section
Title` or `<<my-section-title>>`.
Default is `''`.
### Syntax extensions
The following options control which syntax extensions will be turned on. They are off by default.
#### LaTeX math
Used as `$x^2$`, `$$x^2$$`, escapable as `\$x\$` and `\$\$x\$\$`.
```vim
let g:vim_markdown_math = 1
```
#### YAML Front Matter
Highlight YAML front matter as used by Jekyll or [Hugo](https://gohugo.io/content/front-matter/).
```vim
let g:vim_markdown_frontmatter = 1
```
#### TOML Front Matter
Highlight TOML front matter as used by [Hugo](https://gohugo.io/content/front-matter/).
TOML syntax highlight requires [vim-toml](https://github.com/cespare/vim-toml).
```vim
let g:vim_markdown_toml_frontmatter = 1
```
#### JSON Front Matter
Highlight JSON front matter as used by [Hugo](https://gohugo.io/content/front-matter/).
JSON syntax highlight requires [vim-json](https://github.com/elzr/vim-json).
```vim
let g:vim_markdown_json_frontmatter = 1
```
### Adjust new list item indent
You can adjust a new list indent. For example, you insert a single line like below:
```
* item1
```
Then if you type `o` to insert new line in vim and type `* item2`, the result will be:
```
* item1
* item2
```
vim-markdown automatically insert the indent. By default, the number of spaces of indent is 4. If you'd like to change the number as 2, just write:
```vim
let g:vim_markdown_new_list_item_indent = 2
```
### Do not require .md extensions for Markdown links
If you want to have a link like this `[link text](link-url)` and follow it for editing in vim using the `ge` command, but have it open the file "link-url.md" instead of the file "link-url", then use this option:
```vim
let g:vim_markdown_no_extensions_in_markdown = 1
```
This is super useful for GitLab and GitHub wiki repositories.
Normal behaviour would be that vim-markup required you to do this `[link text](link-url.md)`, but this is not how the Gitlab and GitHub wiki repositories work. So this option adds some consistency between the two.
### Auto-write when following link
If you follow a link like this `[link text](link-url)` using the `ge` shortcut, this option will automatically save any edits you made before moving you:
```vim
let g:vim_markdown_autowrite = 1
```
### Change default file extension
If you would like to use a file extension other than `.md` you may do so using the `vim_markdown_auto_extension_ext` variable:
```vim
let g:vim_markdown_auto_extension_ext = 'txt'
```
## Mappings
The following work on normal and visual modes:
- `gx`: open the link under the cursor in the same browser as the standard `gx` command. `<Plug>Markdown_OpenUrlUnderCursor`
The standard `gx` is extended by allowing you to put your cursor anywhere inside a link.
For example, all the following cursor positions will work:
[Example](http://example.com)
^ ^ ^^ ^ ^
1 2 34 5 6
<http://example.com>
^ ^ ^
1 2 3
Known limitation: does not work for links that span multiple lines.
- `ge`: open the link under the cursor in Vim for editing. Useful for relative markdown links. `<Plug>Markdown_EditUrlUnderCursor`
The rules for the cursor position are the same as the `gx` command.
- `]]`: go to next header. `<Plug>Markdown_MoveToNextHeader`
- `[[`: go to previous header. Contrast with `]c`. `<Plug>Markdown_MoveToPreviousHeader`
- `][`: go to next sibling header if any. `<Plug>Markdown_MoveToNextSiblingHeader`
- `[]`: go to previous sibling header if any. `<Plug>Markdown_MoveToPreviousSiblingHeader`
- `]c`: go to Current header. `<Plug>Markdown_MoveToCurHeader`
- `]u`: go to parent header (Up). `<Plug>Markdown_MoveToParentHeader`
This plugin follows the recommended Vim plugin mapping interface, so to change the map `]u` to `asdf`, add to your `.vimrc`:
map asdf <Plug>Markdown_MoveToParentHeader
To disable a map use:
map <Plug> <Plug>Markdown_MoveToParentHeader
## Commands
The following requires `:filetype plugin on`.
- `:HeaderDecrease`:
Decrease level of all headers in buffer: `h2` to `h1`, `h3` to `h2`, etc.
If range is given, only operate in the range.
If an `h1` would be decreased, abort.
For simplicity of implementation, Setex headers are converted to Atx.
- `:HeaderIncrease`: Analogous to `:HeaderDecrease`, but increase levels instead.
- `:SetexToAtx`:
Convert all Setex style headers in buffer to Atx.
If a range is given, e.g. hit `:` from visual mode, only operate on the range.
- `:TableFormat`: Format the table under the cursor [like this](http://www.cirosantilli.com/markdown-style-guide/#tables).
Requires [Tabular](https://github.com/godlygeek/tabular).
The input table *must* already have a separator line as the second line of the table.
That line only needs to contain the correct pipes `|`, nothing else is required.
- `:Toc`: create a quickfix vertical window navigable table of contents with the headers.
Hit `<Enter>` on a line to jump to the corresponding line of the markdown file.
- `:Toch`: Same as `:Toc` but in an horizontal window.
- `:Toct`: Same as `:Toc` but in a new tab.
- `:Tocv`: Same as `:Toc` for symmetry with `:Toch` and `:Tocv`.
## Credits
The main contributors of vim-markdown are:
- **Ben Williams** (A.K.A. **plasticboy**). The original developer of vim-markdown. [Homepage](http://plasticboy.com/).
If you feel that your name should be on this list, please make a pull request listing your contributions.
## License
The MIT License (MIT)
Copyright (c) 2012 Benjamin D. Williams
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,160 @@
" folding for Markdown headers, both styles (atx- and setex-)
" http://daringfireball.net/projects/markdown/syntax#header
"
" this code can be placed in file
" $HOME/.vim/after/ftplugin/markdown.vim
"
" original version from Steve Losh's gist: https://gist.github.com/1038710
function! s:is_mkdCode(lnum)
let name = synIDattr(synID(a:lnum, 1, 0), 'name')
return (name =~ '^mkd\%(Code$\|Snippet\)' || name != '' && name !~ '^\%(mkd\|html\)')
endfunction
if get(g:, "vim_markdown_folding_style_pythonic", 0)
function! Foldexpr_markdown(lnum)
let l1 = getline(a:lnum)
" keep track of fenced code blocks
if l1 =~ '````*' || l1 =~ '\~\~\~\~*'
if b:fenced_block == 0
let b:fenced_block = 1
elseif b:fenced_block == 1
let b:fenced_block = 0
endif
elseif g:vim_markdown_frontmatter == 1
if b:front_matter == 1 && a:lnum > 2
let l0 = getline(a:lnum-1)
if l0 == '---'
let b:front_matter = 0
endif
elseif a:lnum == 1
if l1 == '---'
let b:front_matter = 1
endif
endif
endif
if b:fenced_block == 1 || b:front_matter == 1
if a:lnum == 1
" fold any 'preamble'
return '>1'
else
" keep previous foldlevel
return '='
endif
endif
let l2 = getline(a:lnum+1)
if l2 =~ '^==\+\s*' && !s:is_mkdCode(a:lnum+1)
" next line is underlined (level 1)
return '>0'
elseif l2 =~ '^--\+\s*' && !s:is_mkdCode(a:lnum+1)
" next line is underlined (level 2)
return '>1'
endif
if l1 =~ '^#' && !s:is_mkdCode(a:lnum)
" current line starts with hashes
return '>'.(matchend(l1, '^#\+') - 1)
elseif a:lnum == 1
" fold any 'preamble'
return '>1'
else
" keep previous foldlevel
return '='
endif
endfunction
function! Foldtext_markdown()
let line = getline(v:foldstart)
let has_numbers = &number || &relativenumber
let nucolwidth = &fdc + has_numbers * &numberwidth
let windowwidth = winwidth(0) - nucolwidth - 6
let foldedlinecount = v:foldend - v:foldstart
let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount))
let line = substitute(line, '\%("""\|''''''\)', '', '')
let fillcharcount = windowwidth - len(line) - len(foldedlinecount) + 1
return line . ' ' . repeat("-", fillcharcount) . ' ' . foldedlinecount
endfunction
else
function! Foldexpr_markdown(lnum)
if (a:lnum == 1)
let l0 = ''
else
let l0 = getline(a:lnum-1)
endif
" keep track of fenced code blocks
if l0 =~ '````*' || l0 =~ '\~\~\~\~*'
if b:fenced_block == 0
let b:fenced_block = 1
elseif b:fenced_block == 1
let b:fenced_block = 0
endif
elseif g:vim_markdown_frontmatter == 1
if b:front_matter == 1
if l0 == '---'
let b:front_matter = 0
endif
elseif a:lnum == 2
if l0 == '---'
let b:front_matter = 1
endif
endif
endif
if b:fenced_block == 1 || b:front_matter == 1
" keep previous foldlevel
return '='
endif
let l2 = getline(a:lnum+1)
if l2 =~ '^==\+\s*' && !s:is_mkdCode(a:lnum+1)
" next line is underlined (level 1)
return '>1'
elseif l2 =~ '^--\+\s*' && !s:is_mkdCode(a:lnum+1)
" next line is underlined (level 2)
if s:vim_markdown_folding_level >= 2
return '>1'
else
return '>2'
endif
endif
let l1 = getline(a:lnum)
if l1 =~ '^#' && !s:is_mkdCode(a:lnum)
" fold level according to option
if s:vim_markdown_folding_level == 1 || matchend(l1, '^#\+') > s:vim_markdown_folding_level
if a:lnum == line('$')
return matchend(l1, '^#\+') - 1
else
return -1
endif
else
" headers are not folded
return 0
endif
endif
if l0 =~ '^#' && !s:is_mkdCode(a:lnum-1)
" previous line starts with hashes
return '>'.matchend(l0, '^#\+')
else
" keep previous foldlevel
return '='
endif
endfunction
endif
let b:fenced_block = 0
let b:front_matter = 0
let s:vim_markdown_folding_level = get(g:, "vim_markdown_folding_level", 1)
if !get(g:, "vim_markdown_folding_disabled", 0)
setlocal foldexpr=Foldexpr_markdown(v:lnum)
setlocal foldmethod=expr
if get(g:, "vim_markdown_folding_style_pythonic", 0) && get(g:, "vim_markdown_override_foldtext", 1)
setlocal foldtext=Foldtext_markdown()
endif
endif

View file

@ -0,0 +1,492 @@
*vim-markdown* Vim Markdown
===============================================================================
Contents ~
1. Introduction |vim-markdown-introduction|
2. Installation |vim-markdown-installation|
3. Options |vim-markdown-options|
1. Disable Folding |vim-markdown-disable-folding|
2. Change fold style |vim-markdown-change-fold-style|
3. Set header folding level |vim-markdown-set-header-folding-level|
4. Disable Default Key Mappings |vim-markdown-disable-default-key-mappings|
5. Enable TOC window auto-fit |vim-markdown-enable-toc-window-auto-fit|
6. Text emphasis restriction to single-lines
|vim-markdown-text-emphasis-restriction-to-single-lines|
7. Syntax Concealing |vim-markdown-syntax-concealing|
8. Fenced code block languages |vim-markdown-fenced-code-block-languages|
9. Follow named anchors |vim-markdown-follow-named-anchors|
10. Syntax extensions |vim-markdown-syntax-extensions|
1. LaTeX math |vim-markdown-latex-math|
2. YAML Front Matter |vim-markdown-yaml-front-matter|
3. TOML Front Matter |vim-markdown-toml-front-matter|
4. JSON Front Matter |vim-markdown-json-front-matter|
11. Adjust new list item indent |vim-markdown-adjust-new-list-item-indent|
12. Do not require .md extensions for Markdown links
|vim-markdown-do-not-require-.md-extensions-for-markdown-links|
13. Auto-write when following link
|vim-markdown-auto-write-when-following-link|
14. Change default file extension |vim-markdown-auto-extension-ext|
4. Mappings |vim-markdown-mappings|
5. Commands |vim-markdown-commands|
6. Credits |vim-markdown-credits|
7. License |vim-markdown-license|
8. References |vim-markdown-references|
===============================================================================
*vim-markdown-introduction*
Introduction ~
Syntax highlighting, matching rules and mappings for the original Markdown [1]
and extensions.
===============================================================================
*vim-markdown-installation*
Installation ~
If you use Vundle [2], add the following line to your '~/.vimrc':
>
Plugin 'godlygeek/tabular'
Plugin 'plasticboy/vim-markdown'
<
The 'tabular' plugin must come _before_ 'vim-markdown'.
Then run inside Vim:
>
:so ~/.vimrc
:PluginInstall
<
If you use Pathogen [3], do this:
>
cd ~/.vim/bundle
git clone https://github.com/plasticboy/vim-markdown.git
<
To install without Pathogen using the Debian vim-addon-manager [4], do this:
>
git clone https://github.com/plasticboy/vim-markdown.git
cd vim-markdown
sudo make install
vim-addon-manager install markdown
<
If you are not using any package manager, download the tarball [5] and do this:
>
cd ~/.vim
tar --strip=1 -zxf vim-markdown-master.tar.gz
<
===============================================================================
*vim-markdown-options*
Options ~
-------------------------------------------------------------------------------
*vim-markdown-disable-folding*
Disable Folding ~
Add the following line to your '.vimrc' to disable the folding configuration:
>
let g:vim_markdown_folding_disabled = 1
<
This option only controls Vim Markdown specific folding configuration.
To enable/disable folding use Vim's standard folding configuration.
>
set [no]foldenable
<
-------------------------------------------------------------------------------
*vim-markdown-change-fold-style*
Change fold style ~
To fold in a style like python-mode [6], add the following to your '.vimrc':
>
let g:vim_markdown_folding_style_pythonic = 1
<
Level 1 heading which is served as a document title is not folded.
'g:vim_markdown_folding_level' setting is not active with this fold style.
To prevent foldtext from being set add the following to your '.vimrc':
>
let g:vim_markdown_override_foldtext = 0
<
-------------------------------------------------------------------------------
*vim-markdown-set-header-folding-level*
Set header folding level ~
Folding level is a number between 1 and 6. By default, if not specified, it is
set to 1.
>
let g:vim_markdown_folding_level = 6
<
Tip: it can be changed on the fly with:
>
:let g:vim_markdown_folding_level = 1
:edit
<
-------------------------------------------------------------------------------
*vim-markdown-disable-default-key-mappings*
Disable Default Key Mappings ~
Add the following line to your '.vimrc' to disable default key mappings:
>
let g:vim_markdown_no_default_key_mappings = 1
<
You can also map them by yourself with '<Plug>' mappings.
-------------------------------------------------------------------------------
*vim-markdown-enable-toc-window-auto-fit*
Enable TOC window auto-fit ~
Allow for the TOC window to auto-fit when it's possible for it to shrink. It
never increases its default size (half screen), it only shrinks.
>
let g:vim_markdown_toc_autofit = 1
<
-------------------------------------------------------------------------------
*vim-markdown-text-emphasis-restriction-to-single-lines*
Text emphasis restriction to single-lines ~
By default text emphasis works across multiple lines until a closing token is
found. However, it's possible to restrict text emphasis to a single line (ie,
for it to be applied a closing token must be found on the same line). To do so:
>
let g:vim_markdown_emphasis_multiline = 0
<
-------------------------------------------------------------------------------
*vim-markdown-syntax-concealing*
Syntax Concealing ~
Concealing is set for some syntax.
For example, conceal '[link text](link url)' as just 'link text'. Also,
'_italic_' and '*italic*' will conceal to just _italic_. Similarly '__bold__',
'**bold**', '___italic bold___', and '***italic bold***' will conceal to just
**bold**, **bold**, **_italic bold_**, and **_italic bold_** respectively.
To enable conceal use Vim's standard conceal configuration.
>
set conceallevel=2
<
To disable conceal regardless of 'conceallevel' setting, add the following to
your '.vimrc':
>
let g:vim_markdown_conceal = 0
<
To disable math conceal with LaTeX math syntax enabled, add the following to
your '.vimrc':
>
let g:tex_conceal = ""
let g:vim_markdown_math = 1
<
-------------------------------------------------------------------------------
*vim-markdown-fenced-code-block-languages*
Fenced code block languages ~
You can use filetype name as fenced code block languages for syntax
highlighting. If you want to use different name from filetype, you can add it
in your '.vimrc' like so:
>
let g:vim_markdown_fenced_languages = ['csharp=cs']
<
This will cause the following to be highlighted using the 'cs' filetype syntax.
>
```csharp
...
```
<
Default is "['c++=cpp', 'viml=vim', 'bash=sh', 'ini=dosini']".
-------------------------------------------------------------------------------
*vim-markdown-follow-named-anchors*
Follow named anchors ~
This feature allows ge to follow named anchors in links of the form
'file#anchor' or just '#anchor', where file may omit the '.md' extension as
usual. Two variables control its operation:
>
let g:vim_markdown_follow_anchor = 1
<
This tells vim-markdown whether to attempt to follow a named anchor in a link
or not. When it is 1, and only if a link can be split in two parts by the
pattern '#', then the first part is interpreted as the file and the second one
as the named anchor. This also includes urls of the form '#anchor', for which
the first part is considered empty, meaning that the target file is the current
one. After the file is opened, the anchor will be searched.
Default is '0'.
>
let g:vim_markdown_anchorexpr = "'<<'.v:anchor.'>>'"
<
This expression will be evaluated substituting 'v:anchor' with a quoted string
that contains the anchor to visit. The result of the evaluation will become the
real anchor to search in the target file. This is useful in order to convert
anchors of the form, say, 'my-section-title' to searches of the form 'My
Section Title' or '<<my-section-title>>'.
Default is "''".
-------------------------------------------------------------------------------
*vim-markdown-syntax-extensions*
Syntax extensions ~
The following options control which syntax extensions will be turned on. They
are off by default.
-------------------------------------------------------------------------------
*vim-markdown-latex-math*
LaTeX math ~
Used as '$x^2$', '$$x^2$$', escapable as '\$x\$' and '\$\$x\$\$'.
>
let g:vim_markdown_math = 1
<
-------------------------------------------------------------------------------
*vim-markdown-yaml-front-matter*
YAML Front Matter ~
Highlight YAML front matter as used by Jekyll or Hugo [7].
>
let g:vim_markdown_frontmatter = 1
<
-------------------------------------------------------------------------------
*vim-markdown-toml-front-matter*
TOML Front Matter ~
Highlight TOML front matter as used by Hugo [7].
TOML syntax highlight requires vim-toml [8].
>
let g:vim_markdown_toml_frontmatter = 1
<
-------------------------------------------------------------------------------
*vim-markdown-json-front-matter*
JSON Front Matter ~
Highlight JSON front matter as used by Hugo [7].
JSON syntax highlight requires vim-json [9].
>
let g:vim_markdown_json_frontmatter = 1
<
-------------------------------------------------------------------------------
*vim-markdown-adjust-new-list-item-indent*
Adjust new list item indent ~
You can adjust a new list indent. For example, you insert a single line like
below:
>
* item1
<
Then if you type 'o' to insert new line in vim and type '* item2', the result
will be:
>
* item1
* item2
<
vim-markdown automatically insert the indent. By default, the number of spaces
of indent is 4. If you'd like to change the number as 2, just write:
>
let g:vim_markdown_new_list_item_indent = 2
<
-------------------------------------------------------------------------------
*vim-markdown-do-not-require-.md-extensions-for-markdown-links*
Do not require .md extensions for Markdown links ~
If you want to have a link like this '[link text](link-url)' and follow it for
editing in vim using the 'ge' command, but have it open the file "link-url.md"
instead of the file "link-url", then use this option:
>
let g:vim_markdown_no_extensions_in_markdown = 1
<
This is super useful for GitLab and GitHub wiki repositories.
Normal behaviour would be that vim-markup required you to do this '[link text
](link-url.md)', but this is not how the Gitlab and GitHub wiki repositories
work. So this option adds some consistency between the two.
-------------------------------------------------------------------------------
*vim-markdown-auto-write-when-following-link*
Auto-write when following link ~
If you follow a link like this '[link text](link-url)' using the 'ge' shortcut,
this option will automatically save any edits you made before moving you:
>
let g:vim_markdown_autowrite = 1
<
-------------------------------------------------------------------------------
*vim-markdown-auto-extension-ext*
Change default file extension ~
If you would like to use a file extension other than '.md' you may do so using
the 'vim_markdown_auto_extension_ext' variable:
>
let g:vim_markdown_auto_extension_ext = 'txt'
<
===============================================================================
*vim-markdown-mappings*
Mappings ~
The following work on normal and visual modes:
*vim-markdown-gx*
- 'gx': open the link under the cursor in the same browser as the standard
'gx' command. '<Plug>Markdown_OpenUrlUnderCursor'
The standard 'gx' is extended by allowing you to put your cursor anywhere
inside a link.
For example, all the following cursor positions will work:
>
[Example](http://example.com)
^ ^ ^^ ^ ^
1 2 34 5 6
<http://example.com>
^ ^ ^
1 2 3
<
Known limitation: does not work for links that span multiple lines.
*vim-markdown-ge*
- 'ge': open the link under the cursor in Vim for editing. Useful for
relative markdown links. '<Plug>Markdown_EditUrlUnderCursor'
The rules for the cursor position are the same as the 'gx' command.
*vim-markdown-]]*
- ']]': go to next header. '<Plug>Markdown_MoveToNextHeader'
*vim-markdown-[[*
- '[[': go to previous header. Contrast with ']c'.
'<Plug>Markdown_MoveToPreviousHeader'
*vim-markdown-][*
- '][': go to next sibling header if any.
'<Plug>Markdown_MoveToNextSiblingHeader'
*vim-markdown-[]*
- '[]': go to previous sibling header if any.
'<Plug>Markdown_MoveToPreviousSiblingHeader'
*vim-markdown-]c*
- ']c': go to Current header. '<Plug>Markdown_MoveToCurHeader'
*vim-markdown-]u*
- ']u': go to parent header (Up). '<Plug>Markdown_MoveToParentHeader'
This plugin follows the recommended Vim plugin mapping interface, so to change
the map ']u' to 'asdf', add to your '.vimrc':
>
map asdf <Plug>Markdown_MoveToParentHeader
<
To disable a map use:
>
map <Plug> <Plug>Markdown_MoveToParentHeader
<
===============================================================================
*vim-markdown-commands*
Commands ~
The following requires ':filetype plugin on'.
*:HeaderDecrease*
- ':HeaderDecrease':
Decrease level of all headers in buffer: 'h2' to 'h1', 'h3' to 'h2', etc.
If range is given, only operate in the range.
If an 'h1' would be decreased, abort.
For simplicity of implementation, Setex headers are converted to Atx.
*:HeaderIncrease*
- ':HeaderIncrease': Analogous to ':HeaderDecrease', but increase levels
instead.
*:SetexToAtx*
- ':SetexToAtx':
Convert all Setex style headers in buffer to Atx.
If a range is given, e.g. hit ':' from visual mode, only operate on the
range.
*:TableFormat*
- ':TableFormat': Format the table under the cursor like this [10].
Requires Tabular [11].
The input table _must_ already have a separator line as the second line of
the table. That line only needs to contain the correct pipes '|', nothing
else is required.
*:Toc*
- ':Toc': create a quickfix vertical window navigable table of contents with
the headers.
Hit '<Enter>' on a line to jump to the corresponding line of the markdown
file.
*:Toch*
- ':Toch': Same as ':Toc' but in an horizontal window.
*:Toct*
- ':Toct': Same as ':Toc' but in a new tab.
*:Tocv*
- ':Tocv': Same as ':Toc' for symmetry with ':Toch' and ':Tocv'.
===============================================================================
*vim-markdown-credits*
Credits ~
The main contributors of vim-markdown are:
- **Ben Williams** (A.K.A. **plasticboy**). The original developer of vim-
markdown. Homepage [12].
If you feel that your name should be on this list, please make a pull request
listing your contributions.
===============================================================================
*vim-markdown-license*
License ~
The MIT License (MIT)
Copyright (c) 2012 Benjamin D. Williams
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
===============================================================================
*vim-markdown-references*
References ~
[1] http://daringfireball.net/projects/markdown/
[2] https://github.com/gmarik/vundle
[3] https://github.com/tpope/vim-pathogen
[4] http://packages.qa.debian.org/v/vim-addon-manager.html
[5] https://github.com/plasticboy/vim-markdown/archive/master.tar.gz
[6] https://github.com/klen/python-mode
[7] https://gohugo.io/content/front-matter/
[8] https://github.com/cespare/vim-toml
[9] https://github.com/elzr/vim-json
[10] http://www.cirosantilli.com/markdown-style-guide/#tables
[11] https://github.com/godlygeek/tabular
[12] http://plasticboy.com/
vim: ft=help

View file

@ -1,6 +1,3 @@
autocmd BufNewFile,BufRead *.markdown,*.md,*.mdown,*.mkd,*.mkdn
\ if &ft =~# '^\%(conf\|modula2\)$' |
\ set ft=markdown |
\ else |
\ setf markdown |
\ endif
" markdown filetype file
au BufRead,BufNewFile *.{md,mdown,mkd,mkdn,markdown,mdwn} set filetype=markdown
au BufRead,BufNewFile *.{md,mdown,mkd,mkdn,markdown,mdwn}.{des3,des,bf,bfa,aes,idea,cast,rc2,rc4,rc5,desx} set filetype=markdown

View file

@ -1,75 +1,773 @@
" Vim filetype plugin
" Language: Markdown
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" Last Change: 2013 May 30
"TODO print messages when on visual mode. I only see VISUAL, not the messages.
if exists("b:did_ftplugin")
finish
endif
" 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-+
runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim
" 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^######[^#]@='
\ }
setlocal comments=fb:*,fb:-,fb:+,n:> commentstring=<!--%s-->
setlocal formatoptions+=tcqln formatoptions-=r formatoptions-=o
setlocal formatlistpat=^\\s*\\d\\+\\.\\s\\+\\\|^[-*+]\\s\\+\\\|^\\[^\\ze[^\\]]\\+\\]:
" 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(\=+|-+)$)'
if exists('b:undo_ftplugin')
let b:undo_ftplugin .= "|setl cms< com< fo< flp<"
else
let b:undo_ftplugin = "setl cms< com< fo< flp<"
endif
function! MarkdownFold()
let line = getline(v:lnum)
" Regular headers
let depth = match(line, '\(^#\+\)\@<=\( .*$\)\@=')
if depth > 0
return ">" . depth
endif
" Setext style headings
let nextline = getline(v:lnum + 1)
if (line =~ '^.\+$') && (nextline =~ '^=\+$')
return ">1"
endif
if (line =~ '^.\+$') && (nextline =~ '^-\+$')
return ">2"
endif
return "="
endfunction
function! MarkdownFoldText()
let hash_indent = s:HashIndent(v:foldstart)
let title = substitute(getline(v:foldstart), '^#\+\s*', '', '')
let foldsize = (v:foldend - v:foldstart + 1)
let linecount = '['.foldsize.' lines]'
return hash_indent.' '.title.' '.linecount
endfunction
function! s:HashIndent(lnum)
let hash_header = matchstr(getline(a:lnum), '^#\{1,6}')
if len(hash_header) > 0
" hashtag header
return hash_header
else
" == or -- header
let nextline = getline(a:lnum + 1)
if nextline =~ '^=\+\s*$'
return repeat('#', 1)
elseif nextline =~ '^-\+\s*$'
return repeat('#', 2)
" 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
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 has("folding") && exists("g:markdown_folding")
setlocal foldexpr=MarkdownFold()
setlocal foldmethod=expr
setlocal foldtext=MarkdownFoldText()
let b:undo_ftplugin .= " foldexpr< foldmethod< foldtext<"
" - 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, ':.'))
execute 'edit' l:url
endif
if l:anchor != ''
silent! execute '/'.l:anchor
endif
else
echomsg 'The cursor is not on a link.'
endif
endfunction
endif
" vim:set sw=2:
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) ? ' 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!
au BufWinEnter * call s:MarkdownRefreshSyntax(1)
au BufUnload * call s:MarkdownClearSyntaxVariables()
au BufWritePost * call s:MarkdownRefreshSyntax(0)
au InsertEnter,InsertLeave * call s:MarkdownRefreshSyntax(0)
au CursorHold,CursorHoldI * call s:MarkdownRefreshSyntax(0)
augroup END

View file

@ -0,0 +1,75 @@
if exists("b:did_indent") | finish | endif
let b:did_indent = 1
setlocal indentexpr=GetMarkdownIndent()
setlocal nolisp
setlocal autoindent
" Automatically insert bullets
setlocal formatoptions+=r
" Do not automatically insert bullets when auto-wrapping with text-width
setlocal formatoptions-=c
" Accept various markers as bullets
setlocal comments=b:*,b:+,b:-
" Automatically continue blockquote on line break
setlocal comments+=b:>
" Only define the function once
if exists("*GetMarkdownIndent") | finish | endif
function! s:IsMkdCode(lnum)
let name = synIDattr(synID(a:lnum, 1, 0), 'name')
return (name =~ '^mkd\%(Code$\|Snippet\)' || name != '' && name !~ '^\%(mkd\|html\)')
endfunction
function! s:IsLiStart(line)
return a:line !~ '^ *\([*-]\)\%( *\1\)\{2}\%( \|\1\)*$' &&
\ a:line =~ '^\s*[*+-] \+'
endfunction
function! s:IsHeaderLine(line)
return a:line =~ '^\s*#'
endfunction
function! s:IsBlankLine(line)
return a:line =~ '^$'
endfunction
function! s:PrevNonBlank(lnum)
let i = a:lnum
while i > 1 && s:IsBlankLine(getline(i))
let i -= 1
endwhile
return i
endfunction
function GetMarkdownIndent()
if v:lnum > 2 && s:IsBlankLine(getline(v:lnum - 1)) && s:IsBlankLine(getline(v:lnum - 2))
return 0
endif
let list_ind = get(g:, "vim_markdown_new_list_item_indent", 4)
" Find a non-blank line above the current line.
let lnum = s:PrevNonBlank(v:lnum - 1)
" At the start of the file use zero indent.
if lnum == 0 | return 0 | endif
let ind = indent(lnum)
let line = getline(lnum) " Last line
let cline = getline(v:lnum) " Current line
if s:IsLiStart(cline)
" Current line is the first line of a list item, do not change indent
return indent(v:lnum)
elseif s:IsHeaderLine(cline) && !s:IsMkdCode(v:lnum)
" Current line is the header, do not indent
return 0
elseif s:IsLiStart(line)
if s:IsMkdCode(lnum)
return ind
else
" Last line is the first line of a list item, increase indent
return ind + list_ind
end
else
return ind
endif
endfunction

View file

@ -0,0 +1,9 @@
addon: markdown
description: "Markdown syntax highlighting"
files:
- ftdetect/markdown.vim
- ftplugin/markdown.vim
- syntax/markdown.vim
- after/ftplugin/markdown.vim
- indent/markdown.vim
- doc/vim-markdown.txt

View file

@ -1,169 +1,173 @@
" Vim syntax file
" Language: Markdown
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" Filenames: *.markdown
" Last Change: 2013 May 30
" 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)
if exists("b:current_syntax")
" 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
if !exists('main_syntax')
let main_syntax = 'markdown'
" 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
runtime! syntax/html.vim
unlet! b:current_syntax
if !exists('g:markdown_fenced_languages')
let g:markdown_fenced_languages = []
endif
let s:done_include = {}
for s:type in map(copy(g:markdown_fenced_languages),'matchstr(v:val,"[^=]*$")')
if has_key(s:done_include, matchstr(s:type,'[^.]*'))
continue
endif
if s:type =~ '\.'
let b:{matchstr(s:type,'[^.]*')}_subtype = matchstr(s:type,'\.\zs.*')
endif
exe 'syn include @markdownHighlight'.substitute(s:type,'\.','','g').' syntax/'.matchstr(s:type,'[^.]*').'.vim'
unlet! b:current_syntax
let s:done_include[matchstr(s:type,'[^.]*')] = 1
endfor
unlet! s:type
unlet! s:done_include
if !exists('g:markdown_minlines')
let g:markdown_minlines = 50
endif
execute 'syn sync minlines=' . g:markdown_minlines
syn spell toplevel
syn case ignore
syn sync linebreaks=1
syn match markdownValid '[<>]\c[a-z/$!]\@!'
syn match markdownValid '&\%(#\=\w*;\)\@!'
syn match markdownLineStart "^[<@]\@!" nextgroup=@markdownBlock,htmlSpecialChar
syn cluster markdownBlock contains=markdownH1,markdownH2,markdownH3,markdownH4,markdownH5,markdownH6,markdownBlockquote,markdownListMarker,markdownOrderedListMarker,markdownCodeBlock,markdownRule
syn cluster markdownInline contains=markdownLineBreak,markdownLinkText,markdownItalic,markdownBold,markdownCode,markdownEscape,@htmlTop,markdownError
syn match markdownH1 "^.\+\n=\+$" contained contains=@markdownInline,markdownHeadingRule,markdownAutomaticLink
syn match markdownH2 "^.\+\n-\+$" contained contains=@markdownInline,markdownHeadingRule,markdownAutomaticLink
syn match markdownHeadingRule "^[=-]\+$" contained
syn region markdownH1 matchgroup=markdownH1Delimiter start="##\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
syn region markdownH2 matchgroup=markdownH2Delimiter start="###\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
syn region markdownH3 matchgroup=markdownH3Delimiter start="####\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
syn region markdownH4 matchgroup=markdownH4Delimiter start="#####\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
syn region markdownH5 matchgroup=markdownH5Delimiter start="######\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
syn region markdownH6 matchgroup=markdownH6Delimiter start="#######\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
syn match markdownBlockquote ">\%(\s\|$\)" contained nextgroup=@markdownBlock
syn region markdownCodeBlock start=" \|\t" end="$" contained
" TODO: real nesting
syn match markdownListMarker "\%(\t\| \{0,4\}\)[-*+]\%(\s\+\S\)\@=" contained
syn match markdownOrderedListMarker "\%(\t\| \{0,4}\)\<\d\+\.\%(\s\+\S\)\@=" contained
syn match markdownRule "\* *\* *\*[ *]*$" contained
syn match markdownRule "- *- *-[ -]*$" contained
syn match markdownLineBreak " \{2,\}$"
syn region markdownIdDeclaration matchgroup=markdownLinkDelimiter start="^ \{0,3\}!\=\[" end="\]:" oneline keepend nextgroup=markdownUrl skipwhite
syn match markdownUrl "\S\+" nextgroup=markdownUrlTitle skipwhite contained
syn region markdownUrl matchgroup=markdownUrlDelimiter start="<" end=">" oneline keepend nextgroup=markdownUrlTitle skipwhite contained
syn region markdownUrlTitle matchgroup=markdownUrlTitleDelimiter start=+"+ end=+"+ keepend contained
syn region markdownUrlTitle matchgroup=markdownUrlTitleDelimiter start=+'+ end=+'+ keepend contained
syn region markdownUrlTitle matchgroup=markdownUrlTitleDelimiter start=+(+ end=+)+ keepend contained
syn region markdownLinkText matchgroup=markdownLinkTextDelimiter start="!\=\[\%(\_[^]]*]\%( \=[[(]\)\)\@=" end="\]\%( \=[[(]\)\@=" nextgroup=markdownLink,markdownId skipwhite contains=@markdownInline,markdownLineStart
syn region markdownLink matchgroup=markdownLinkDelimiter start="(" end=")" contains=markdownUrl keepend contained
syn region markdownId matchgroup=markdownIdDelimiter start="\[" end="\]" keepend contained
syn region markdownAutomaticLink matchgroup=markdownUrlDelimiter start="<\%(\w\+:\|[[:alnum:]_+-]\+@\)\@=" end=">" keepend oneline
let s:conceal = ''
let s:concealends = ''
if has('conceal') && get(g:, 'markdown_syntax_conceal', 1) == 1
if has('conceal') && get(g:, 'vim_markdown_conceal', 1)
let s:conceal = ' conceal'
let s:concealends = ' concealends'
endif
exe 'syn region markdownItalic matchgroup=markdownItalicDelimiter start="\S\@<=\*\|\*\S\@=" end="\S\@<=\*\|\*\S\@=" keepend contains=markdownLineStart,@Spell' . s:concealends
exe 'syn region markdownItalic matchgroup=markdownItalicDelimiter start="\S\@<=_\|_\S\@=" end="\S\@<=_\|_\S\@=" keepend contains=markdownLineStart,@Spell' . s:concealends
exe 'syn region markdownBold matchgroup=markdownBoldDelimiter start="\S\@<=\*\*\|\*\*\S\@=" end="\S\@<=\*\*\|\*\*\S\@=" keepend contains=markdownLineStart,markdownItalic,@Spell' . s:concealends
exe 'syn region markdownBold matchgroup=markdownBoldDelimiter start="\S\@<=__\|__\S\@=" end="\S\@<=__\|__\S\@=" keepend contains=markdownLineStart,markdownItalic,@Spell' . s:concealends
exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start="\S\@<=\*\*\*\|\*\*\*\S\@=" end="\S\@<=\*\*\*\|\*\*\*\S\@=" keepend contains=markdownLineStart,@Spell' . s:concealends
exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start="\S\@<=___\|___\S\@=" end="\S\@<=___\|___\S\@=" keepend contains=markdownLineStart,@Spell' . s:concealends
syn region markdownCode matchgroup=markdownCodeDelimiter start="`" end="`" keepend contains=markdownLineStart
syn region markdownCode matchgroup=markdownCodeDelimiter start="`` \=" end=" \=``" keepend contains=markdownLineStart
syn region markdownCode matchgroup=markdownCodeDelimiter start="^\s*````*.*$" end="^\s*````*\ze\s*$" keepend
" 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
syn match markdownFootnote "\[^[^\]]\+\]"
syn match markdownFootnoteDefinition "^\[^[^\]]\+\]:"
" [link](URL) | [link][id] | [link][] | ![image](URL)
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
if main_syntax ==# 'markdown'
let s:done_include = {}
for s:type in g:markdown_fenced_languages
if has_key(s:done_include, matchstr(s:type,'[^.]*'))
continue
endif
exe 'syn region markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\..*','','').' matchgroup=markdownCodeDelimiter start="^\s*````*\s*'.matchstr(s:type,'[^=]*').'\S\@!.*$" end="^\s*````*\ze\s*$" keepend contains=@markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\.','','g')
let s:done_include[matchstr(s:type,'[^.]*')] = 1
endfor
unlet! s:type
unlet! s:done_include
" 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 start="^\s*#" end="$" contains=mkdLink,mkdInlineURL,@Spell
syn region htmlH2 start="^\s*##" end="$" contains=mkdLink,mkdInlineURL,@Spell
syn region htmlH3 start="^\s*###" end="$" contains=mkdLink,mkdInlineURL,@Spell
syn region htmlH4 start="^\s*####" end="$" contains=mkdLink,mkdInlineURL,@Spell
syn region htmlH5 start="^\s*#####" end="$" contains=mkdLink,mkdInlineURL,@Spell
syn region htmlH6 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
syn region mkdCode start=/\(\([^\\]\|^\)\\\)\@<!`/ end=/\(\([^\\]\|^\)\\\)\@<!`/
syn region mkdCode start=/\s*``[^`]*/ end=/[^`]*``\s*/
syn region mkdCode start=/^\s*\z(`\{3,}\)[^`]*$/ end=/^\s*\z1`*\s*$/
syn region mkdCode start=/\s*\~\~[^\~]*/ end=/[^\~]*\~\~\s*/
syn region mkdCode start=/^\s*\z(\~\{3,}\)\s*[0-9A-Za-z_+-]*\s*$/ end=/^\s*\z1\~*\s*$/
syn region mkdCode start="<pre[^>]*\\\@<!>" end="</pre>"
syn region mkdCode start="<code[^>]*\\\@<!>" end="</code>"
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
syn match markdownEscape "\\[][\\`*_{}()<>#+.!-]"
syn match markdownError "\w\@<=_\w\@="
hi def link markdownH1 htmlH1
hi def link markdownH2 htmlH2
hi def link markdownH3 htmlH3
hi def link markdownH4 htmlH4
hi def link markdownH5 htmlH5
hi def link markdownH6 htmlH6
hi def link markdownHeadingRule markdownRule
hi def link markdownH1Delimiter markdownHeadingDelimiter
hi def link markdownH2Delimiter markdownHeadingDelimiter
hi def link markdownH3Delimiter markdownHeadingDelimiter
hi def link markdownH4Delimiter markdownHeadingDelimiter
hi def link markdownH5Delimiter markdownHeadingDelimiter
hi def link markdownH6Delimiter markdownHeadingDelimiter
hi def link markdownHeadingDelimiter Delimiter
hi def link markdownOrderedListMarker markdownListMarker
hi def link markdownListMarker htmlTagName
hi def link markdownBlockquote Comment
hi def link markdownRule PreProc
hi def link markdownFootnote Typedef
hi def link markdownFootnoteDefinition Typedef
hi def link markdownLinkText htmlLink
hi def link markdownIdDeclaration Typedef
hi def link markdownId Type
hi def link markdownAutomaticLink markdownUrl
hi def link markdownUrl Float
hi def link markdownUrlTitle String
hi def link markdownIdDelimiter markdownLinkDelimiter
hi def link markdownUrlDelimiter htmlTag
hi def link markdownUrlTitleDelimiter Delimiter
hi def link markdownItalic htmlItalic
hi def link markdownItalicDelimiter markdownItalic
hi def link markdownBold htmlBold
hi def link markdownBoldDelimiter markdownBold
hi def link markdownBoldItalic htmlBoldItalic
hi def link markdownBoldItalicDelimiter markdownBoldItalic
hi def link markdownCodeDelimiter Delimiter
hi def link markdownEscape Special
hi def link markdownError Error
let b:current_syntax = "markdown"
if main_syntax ==# 'markdown'
unlet main_syntax
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
" vim:set sw=2:
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
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 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

View file

@ -0,0 +1,5 @@
You can run the tests using the Makefile from the top directory:
make test
To run them manually please refer to the instructions/commands in the Makefile.

View file

@ -0,0 +1,178 @@
" Tests atx and setext folding, and :Toc.
Before:
source ../after/ftplugin/markdown.vim
After:
setlocal foldexpr=0
setlocal foldmethod=manual
Given markdown;
# chap 1
hello
world
```bash
# some bash scripting
pwd
# this is another comment
# other
echo "foo"
```
## chap 1.1
- dog
- cat
~~~~bash
mkdir foo
# comment in ~
~~~~
### chap 1.1.1
- dragons
- fenixs
# chap 2
another
## chap 2.1
- uk
- japan
- china
# chap 3
nothing here
chap 4
======
setext are evil
chap 4.1
--------
evil indeed
````bash
# get system info
uname -a
````
Execute (fold level):
AssertEqual foldlevel(1), 0, '# chap 1'
AssertEqual foldlevel(3), 1, 'hello'
AssertEqual foldlevel(6), 1, '```bash'
AssertEqual foldlevel(7), 1, '# some bash scripting'
AssertEqual foldlevel(15), 1, '## chap 1.1'
AssertEqual foldlevel(21), 2, 'mkdir foo'
AssertEqual foldlevel(22), 2, 'comment in ~'
AssertEqual foldlevel(25), 2, '### chap 1.1.1'
AssertEqual foldlevel(27), 3, '- dragons'
AssertEqual foldlevel(30), 1, '# chap 2'
AssertEqual foldlevel(32), 1, 'another'
AssertEqual foldlevel(34), 1, '# chap 2.1'
AssertEqual foldlevel(37), 2, '- japan'
AssertEqual foldlevel(41), 1, '# chap 3'
AssertEqual foldlevel(45), 1, 'chap 4\n======'
AssertEqual foldlevel(48), 1, 'setext are evil'
AssertEqual foldlevel(50), 2, 'chap 4.1\n------'
Execute (fold text result):
AssertEqual foldtextresult(2), '+-- 28 lines: hello'
AssertEqual foldtextresult(31), '+-- 10 lines: another'
AssertEqual foldtextresult(42), '+-- 3 lines: nothing here'
AssertEqual foldtextresult(45), '+-- 14 lines: chap 4'
Execute (fold level with setting):
let g:vim_markdown_folding_level = 2
source ../after/ftplugin/markdown.vim
AssertEqual foldlevel(1), 0, '# chap 1'
AssertEqual foldlevel(3), 1, 'hello'
AssertEqual foldlevel(6), 1, '```bash'
AssertEqual foldlevel(7), 1, '# some bash scripting'
AssertEqual foldlevel(15), 0, '## chap 1.1'
AssertEqual foldlevel(21), 2, 'mkdir foo'
AssertEqual foldlevel(22), 2, 'comment in ~'
AssertEqual foldlevel(25), 2, '### chap 1.1.1'
AssertEqual foldlevel(27), 3, '- dragons'
AssertEqual foldlevel(30), 0, '# chap 2'
AssertEqual foldlevel(32), 1, 'another'
AssertEqual foldlevel(34), 0, '# chap 2.1'
AssertEqual foldlevel(37), 2, '- japan'
AssertEqual foldlevel(41), 0, '# chap 3'
AssertEqual foldlevel(45), 1, 'chap 4\n======'
AssertEqual foldlevel(48), 1, 'setext are evil'
AssertEqual foldlevel(50), 1, 'chap 4.1\n------'
let g:vim_markdown_folding_level = 0
Execute (check TOC):
:Toc
:lclose
let res = getloclist(0)
let elem = res[0]
AssertEqual elem.lnum, 1
AssertEqual elem.text, '# chap 1'
let elem = res[1]
AssertEqual elem.lnum, 15
AssertEqual elem.text, '## chap 1.1'
let elem = res[2]
AssertEqual elem.lnum, 25
AssertEqual elem.text, '### chap 1.1.1'
let elem = res[3]
AssertEqual elem.lnum, 30
AssertEqual elem.text, '# chap 2'
let elem = res[4]
AssertEqual elem.lnum, 34
AssertEqual elem.text, '## chap 2.1'
let elem = res[5]
AssertEqual elem.lnum, 41
AssertEqual elem.text, '# chap 3'
let elem = res[6]
AssertEqual elem.lnum, 45
AssertEqual elem.text, 'chap 4'
let elem = res[7]
AssertEqual elem.lnum, 50
AssertEqual elem.text, 'chap 4.1'
Given markdown;
---
layout: article
title: A test of the heading folding when there is YAML frontmatter
tags: markdown yaml vim-markdown
---
body
heading
-------
Execute (fold level of yaml front matter):
let g:vim_markdown_frontmatter = 1
source ../after/ftplugin/markdown.vim
AssertEqual foldlevel(1), 0, '---'
AssertEqual foldlevel(2), 0, 'layout: article'
AssertEqual foldlevel(4), 0, 'tags: markdown yaml vim-markdown'
AssertEqual foldlevel(5), 0, '---'
AssertEqual foldlevel(6), 0, 'body'
AssertEqual foldlevel(8), 2, 'heading'
AssertEqual foldlevel(9), 2, '-------'
unlet g:vim_markdown_frontmatter
Execute (check Toc of yaml front matter):
let g:vim_markdown_frontmatter = 1
:Toc
:lclose
let res = getloclist(0)
AssertEqual len(res), 1
let elem = res[0]
AssertEqual elem.lnum, 8
AssertEqual elem.text, 'heading'
unlet g:vim_markdown_frontmatter

View file

@ -0,0 +1,53 @@
Before:
source ../after/ftplugin/markdown.vim
After:
setlocal foldexpr=0
setlocal foldmethod=manual
Given markdown;
# Title
## Chapter 1
```
This is code block
# This is just a comment
```
## Capter 2
foobar
Execute (fold level # in code block):
AssertEqual foldlevel(1), 0, '# Title'
AssertEqual foldlevel(3), 1, '## Chapter 1'
AssertEqual foldlevel(7), 2, '# This is just a comment'
AssertEqual foldlevel(8), 2, '```'
AssertEqual foldlevel(10), 1, '## Chapter 2'
AssertEqual foldlevel(12), 2, 'foobar'
Given markdown;
Fold Level 1
============
Fold Level 2
------------
Execute (fold level ==, --):
AssertEqual foldlevel(2), 1, '=='
AssertEqual foldlevel(4), 2, '--'
Given markdown;
# H1
## H1.1
## H1.2
# H2
Execute (fold level # in last line):
AssertEqual foldlevel(1), 0, '# H1'
AssertEqual foldlevel(3), 1, '## H1.1'
AssertEqual foldlevel(5), 1, '## H1.2'
AssertEqual foldlevel(7), 0, '# H2'

View file

@ -0,0 +1 @@
ge test

View file

@ -0,0 +1,15 @@
Before:
let g:vim_markdown_new_list_item_indent = 2
After:
unlet g:vim_markdown_new_list_item_indent
Given markdown;
* item1
Do (new line from the first item of the list and add the second item):
o* item2
Expect (insert 2 spaces to the head of second item):
* item1
* item2

View file

@ -0,0 +1,26 @@
1. Confirm indent with new line insert after list items
'\' is not list item.
\ foo
If only space and three '*' or '-' character are in the line,
this line means horizontal item.
If current line is below horizontal item, it need not to indent.
Following example is horizontal item.
---
***
- - -
* * *
And list item must be specified space after [*-+].
Following example is list item.
* foo
- bar
+ baz
But following example is not list item.
*foo
-bar
+baz

View file

@ -0,0 +1,73 @@
Given markdown;
* item1
Do (insert enter at list end):
A\<cr>item2
Expect (auto insert * and indent level is same):
* item1
* item2
Given markdown;
Execute:
syntax off
Do (insert enter at list end with syntax off):
i* item1\<cr>item2
Expect (auto insert * and indent level is same):
* item1
* item2
Execute:
syntax on
Given markdown;
```
* item1
Do (insert after list items in code block):
jotext
Expect (no autoindent in code block):
```
* item1
text
Given markdown;
* item1
a
Do (insert enter after list):
jji\<cr>b
Expect (no autoindent outside list):
* item1
ba
Given markdown;
- a
# b
Do (insert header after list):
jjwi#
Expect (no indent header after list):
- a
## b
Given markdown;
* item1
Do (new line from the first item of the list and add the second item):
o* item2
Expect (insert 4 spaces to the head of second item):
* item1
* item2

View file

@ -0,0 +1,153 @@
Given markdown;
a <http://b> c
Execute (gx autolink):
let b:url = 'http://b'
let b:line = getline(1)
let b:func = Markdown_GetFunc('vim-markdown/ftplugin/markdown.vim', 'Markdown_GetUrlForPosition')
AssertEqual b:func(1, match(b:line, 'a') + 1), ''
AssertEqual b:func(1, match(b:line, '<') + 1), b:url
AssertEqual b:func(1, match(b:line, 'h') + 1), b:url
AssertEqual b:func(1, match(b:line, '>') + 1), b:url
AssertEqual b:func(1, match(b:line, 'c') + 1), ''
Given markdown;
a http://b.bb c
Execute (gx implicit autolink):
let b:url = 'http://b.bb'
let b:line = getline(1)
let b:func = Markdown_GetFunc('vim-markdown/ftplugin/markdown.vim', 'Markdown_GetUrlForPosition')
AssertEqual b:func(1, match(b:line, 'a') + 1), ''
AssertEqual b:func(1, match(b:line, 'h') + 1), b:url
AssertEqual b:func(1, match(b:line, 'c') + 1), ''
Given markdown;
[a]: http://b "c"
Execute (gx link reference definition):
let b:url = 'http://b'
let b:line = getline(1)
let b:func = Markdown_GetFunc('vim-markdown/ftplugin/markdown.vim', 'Markdown_GetUrlForPosition')
" TODO would be cool if all of the following gave the link.
AssertEqual b:func(1, match(b:line, 'a') + 1), ''
AssertEqual b:func(1, match(b:line, 'h') + 1), b:url
AssertEqual b:func(1, match(b:line, 'c') + 1), ''
Given markdown;
a [b](c) d
Execute (gx autolink):
let b:url = 'c'
let b:line = getline(1)
let b:func = Markdown_GetFunc('vim-markdown/ftplugin/markdown.vim', 'Markdown_GetUrlForPosition')
AssertEqual b:func(1, match(b:line, 'a') + 1), ''
AssertEqual b:func(1, match(b:line, '[') + 1), b:url
AssertEqual b:func(1, match(b:line, 'b') + 1), b:url
AssertEqual b:func(1, match(b:line, ']') + 1), b:url
AssertEqual b:func(1, match(b:line, '(') + 1), b:url
AssertEqual b:func(1, match(b:line, 'c') + 1), b:url
AssertEqual b:func(1, match(b:line, ')') + 1), b:url
AssertEqual b:func(1, match(b:line, 'd') + 1), ''
Given markdown;
[ge_test.md](ge_test.md)
Execute (ge opens file):
normal ge
AssertEqual @%, 'ge_test.md'
AssertEqual getline(1), 'ge test'
Given markdown;
[ge_test](ge_test)
Execute (ge opens file without .md extensions):
let g:vim_markdown_no_extensions_in_markdown = 1
normal ge
AssertEqual @%, 'ge_test.md'
AssertEqual getline(1), 'ge test'
unlet g:vim_markdown_no_extensions_in_markdown
Given markdown;
[ge_test.md](ge_test.md)
Execute (ge does not write before opening file):
normal ia
normal l
normal ge
AssertEqual @%, 'ge_test.md'
AssertEqual getline(1), 'ge test'
Given markdown;
[ge_test.md](ge_test.md)
Execute (ge auto-write before opening file):
let g:vim_markdown_autowrite = 1
normal ia
normal l
AssertThrows normal ge
AssertEqual g:vader_exception, 'Vim(write):E382: Cannot write, ''buftype'' option is set'
unlet g:vim_markdown_autowrite
Given markdown;
# a
b
# c
d
Execute (]] same level):
AssertEqual line('.'), 1
normal ]]
AssertEqual line('.'), 5
normal [[
AssertEqual line('.'), 1
Given markdown;
# a
b
## c
d
Execute (]] different levels level):
AssertEqual line('.'), 1
normal ]]
AssertEqual line('.'), 5
normal [[
AssertEqual line('.'), 1
Given markdown;
# a
b
## c
d
# e
f
Execute (][ different levels level):
AssertEqual line('.'), 1
normal ][
AssertEqual line('.'), 9
normal []
AssertEqual line('.'), 1
Given markdown;
# a
b
Execute (]c):
normal! 3G
AssertEqual line('.'), 3
normal ]c
AssertEqual line('.'), 1

View file

@ -0,0 +1,85 @@
Before:
let g:vim_markdown_folding_style_pythonic = 1
source ../after/ftplugin/markdown.vim
After:
setlocal foldexpr=0
setlocal foldmethod=manual
Given markdown;
# Title
## Chapter 1
```
This is code block
# This is just a comment
```
## Chapter 2
foobar
Execute (fold level # in code block):
AssertEqual foldlevel(1), 0, '# Title'
AssertEqual foldlevel(3), 1, '## Chapter 1'
AssertEqual foldlevel(7), 1, '# This is just a comment'
AssertEqual foldlevel(8), 1, '```'
AssertEqual foldlevel(10), 1, '## Chapter 2'
AssertEqual foldlevel(12), 1, 'foobar'
Execute (fold text of chapters):
let b:width = winwidth(0)
let b:hyphen = repeat('-', b:width - 18 > 2 ? b:width - 18 : b:width - 9 > 0 ? 3 : 2)
AssertEqual foldtextresult(3), strpart('## Chapter 1', 0, b:width - 9) . ' ' . b:hyphen . ' 6'
AssertEqual foldtextresult(10), strpart('## Chapter 2', 0, b:width - 9) . ' ' . b:hyphen . ' 2'
Given markdown;
Fold text 1
===========
Fold text 2
-----------
Execute (fold level ==, --):
AssertEqual foldlevel(2), 0, '=='
AssertEqual foldlevel(4), 1, '--'
Execute (fold text of ==, --):
let b:width = winwidth(0)
let b:hyphen = repeat('-', b:width - 17 > 2 ? b:width - 17 : b:width - 9 > 0 ? 3 : 2)
AssertEqual foldtextresult(3), strpart('Fold text 2', 0, b:width - 9) . ' ' . b:hyphen . ' 1'
Given markdown;
Headline
foobar
# Title
Execute (fold any preamble):
AssertEqual foldlevel(1), 1, 'Headline'
AssertEqual foldlevel(3), 1, 'foobar'
AssertEqual foldlevel(5), 0, '# Title'
Given markdown;
---
layout: article
title: A test of the heading folding when there is YAML frontmatter
tags: markdown yaml vim-markdown
---
body
heading
-------
Execute (fold level of yaml front matter):
let g:vim_markdown_frontmatter = 1
source ../after/ftplugin/markdown.vim
AssertEqual foldlevel(1), 1, '---'
AssertEqual foldlevel(2), 1, 'layout: article'
AssertEqual foldlevel(4), 1, 'tags: markdown yaml vim-markdown'
AssertEqual foldlevel(5), 1, '---'
AssertEqual foldlevel(6), 1, 'body'
AssertEqual foldlevel(8), 1, 'heading'
AssertEqual foldlevel(9), 1, '-------'
unlet g:vim_markdown_frontmatter

View file

@ -0,0 +1,16 @@
#!/usr/bin/env bash
# Exit on error.
set -e
cd "$( dirname "${BASH_SOURCE[0]}" )"
for dep in ../build/tabular ../build/vim-toml ../build/vim-json ../build/vader.vim; do
if [[ ! -d $dep ]]; then
echo "Missing dependency: $dep"
echo "You may just want to use 'make test'."
exit 1
fi
done
vim -Nu vimrc -c 'Vader! *' > /dev/null

View file

@ -0,0 +1,158 @@
Before:
let g:vim_markdown_emphasis_multiline = 0
syn off | syn on
After:
let g:vim_markdown_emphasis_multiline = 1
syn off | syn on
Given markdown;
a **b** c
Execute (bold):
AssertNotEqual SyntaxOf('a'), 'htmlBold'
AssertEqual SyntaxOf('b'), 'htmlBold'
AssertNotEqual SyntaxOf('c'), 'htmlBold'
Given markdown;
a __b__ c
Execute (bold):
AssertNotEqual SyntaxOf('a'), 'htmlBold'
AssertEqual SyntaxOf('b'), 'htmlBold'
AssertNotEqual SyntaxOf('c'), 'htmlBold'
Given markdown;
a *b* c
Execute (italic):
AssertNotEqual SyntaxOf('a'), 'htmlItalic'
AssertEqual SyntaxOf('b'), 'htmlItalic'
AssertNotEqual SyntaxOf('c'), 'htmlItalic'
Given markdown;
a _b_ c
Execute (italic):
AssertNotEqual SyntaxOf('a'), 'htmlItalic'
AssertEqual SyntaxOf('b'), 'htmlItalic'
AssertNotEqual SyntaxOf('c'), 'htmlItalic'
Given markdown;
_a_b_
Execute (italic text has underscores):
AssertEqual SyntaxOf('a'), 'htmlItalic'
AssertEqual SyntaxOf('b'), 'htmlItalic'
Given markdown;
a \*b\* c
Execute (not italic with escaped asterisks):
AssertNotEqual SyntaxOf('a'), 'htmlItalic'
AssertNotEqual SyntaxOf('b'), 'htmlItalic'
AssertNotEqual SyntaxOf('c'), 'htmlItalic'
Given markdown;
a \_b\_ c
Execute (not italic with escaped underscores):
AssertNotEqual SyntaxOf('a'), 'htmlItalic'
AssertNotEqual SyntaxOf('b'), 'htmlItalic'
AssertNotEqual SyntaxOf('c'), 'htmlItalic'
Given markdown;
a _b\_c_ d
Execute (italic with escaped underscores):
AssertNotEqual SyntaxOf('a'), 'htmlItalic'
AssertEqual SyntaxOf('b'), 'htmlItalic'
AssertEqual SyntaxOf('c'), 'htmlItalic'
AssertNotEqual SyntaxOf('d'), 'htmlItalic'
Given markdown;
a_b_c
Execute (not italic underscores within text):
AssertNotEqual SyntaxOf('a'), 'htmlItalic'
AssertNotEqual SyntaxOf('b'), 'htmlItalic'
AssertNotEqual SyntaxOf('c'), 'htmlItalic'
Given markdown;
a *b\*c* d
Execute (italic with escaped asterisks):
AssertNotEqual SyntaxOf('a'), 'htmlItalic'
AssertEqual SyntaxOf('b'), 'htmlItalic'
AssertEqual SyntaxOf('c'), 'htmlItalic'
AssertNotEqual SyntaxOf('d'), 'htmlItalic'
Given markdown;
a __b\_\_c__ d
Execute (bold with escaped underscores):
AssertNotEqual SyntaxOf('a'), 'htmlBold'
AssertEqual SyntaxOf('b'), 'htmlBold'
AssertEqual SyntaxOf('c'), 'htmlBold'
AssertNotEqual SyntaxOf('d'), 'htmlBold'
Given markdown;
_a b
c_ d
Execute (italic with underscores in multiple lines):
AssertNotEqual SyntaxOf('a'), 'htmlItalic'
AssertNotEqual SyntaxOf('b'), 'htmlItalic'
AssertNotEqual SyntaxOf('c'), 'htmlItalic'
AssertNotEqual SyntaxOf('d'), 'htmlItalic'
Given markdown;
__a b
c__ d
Execute (bold with underscores in multiple lines):
AssertNotEqual SyntaxOf('a'), 'htmlBold'
AssertNotEqual SyntaxOf('b'), 'htmlBold'
AssertNotEqual SyntaxOf('c'), 'htmlBold'
AssertNotEqual SyntaxOf('d'), 'htmlBold'
Given markdown;
___a b
c___ d
Execute (bold italic with underscores in multiple lines):
AssertNotEqual SyntaxOf('a'), 'htmlBoldItalic'
AssertNotEqual SyntaxOf('b'), 'htmlBoldItalic'
AssertNotEqual SyntaxOf('c'), 'htmlBoldItalic'
AssertNotEqual SyntaxOf('d'), 'htmlBoldItalic'
Given markdown;
*a b
c* d
Execute (italic with asterisks in multiple lines):
AssertNotEqual SyntaxOf('a'), 'htmlItalic'
AssertNotEqual SyntaxOf('b'), 'htmlItalic'
AssertNotEqual SyntaxOf('c'), 'htmlItalic'
AssertNotEqual SyntaxOf('d'), 'htmlItalic'
Given markdown;
**a b
c** d
Execute (bold with asterisks in multiple lines):
AssertNotEqual SyntaxOf('a'), 'htmlBold'
AssertNotEqual SyntaxOf('b'), 'htmlBold'
AssertNotEqual SyntaxOf('c'), 'htmlBold'
AssertNotEqual SyntaxOf('d'), 'htmlBold'
Given markdown;
***a b
c*** d
Execute (bold italic with asterisks in multiple lines):
AssertNotEqual SyntaxOf('a'), 'htmlBoldItalic'
AssertNotEqual SyntaxOf('b'), 'htmlBoldItalic'
AssertNotEqual SyntaxOf('c'), 'htmlBoldItalic'
AssertNotEqual SyntaxOf('d'), 'htmlBoldItalic'

View file

@ -0,0 +1,89 @@
# Fenced code living in an indented environment is correctly highlighted
1. run this command to do this:
```
some command
```
2. Subsequent list items are correctly highlighted.
Fenced code block with language:
```ruby
def f
0
end
```
# Links
[a](b "c")
[a]()
[good spell](a)
[badd spell](a)
[a](b "c")
[a]( b
"c" )
a (`a`) b. Fix: <https://github.com/plasticboy/vim-markdown/issues/113>
Escaped:
\[a](b)
[a\]b](c)
## Known failures
Escape does not work:
[a\](b)
Should not be links because of whitespace:
[a] (b)
[a](a
b)
[a](a b)
# Reference links
Single links:
[a][b]
[good spell][a]
[badd spell][a]
[a][]
[a] []
[a][b] c [d][e]
Reference link followed by inline link:
[a] [b](c)
## Known failures
Should be shortcut reference links:
[a]
[a] b [c]
Should be a single link:
[a] [b]
[a] b [c](d)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,44 @@
Before:
let &gdefault = 1
After:
let &gdefault = 0
Given markdown;
| normal |no space| 2 spaces ||
| - |-| --- ||
| normal |no space| 2 spaces ||
Execute (format unformatted table):
TableFormat
Expect (table is formatted):
| normal | no space | 2 spaces | |
|--------|----------|----------|--|
| normal | no space | 2 spaces | |
Given markdown;
| a | b |
|---|---|
| c | d |
Execute (format well formatted table):
TableFormat
Expect (table is not modified):
| a | b |
|---|---|
| c | d |
Given markdown;
| left |right| center ||
| :- | --: |:---:|:|
| left |right| center ||
Execute (format table with colons):
TableFormat
Expect (preserve colons to align text):
| left | right | center | |
|:-----|------:|:------:|:--|
| left | right | center | |

View file

@ -0,0 +1,53 @@
" Tests toc window auto-fit to longest header, but without exceeding half screen.
Given markdown;
# chap 1
# chap 2
# chap 3
# chap 4
# chap 5
# chap 6
# chap 7
# chap 8
# chap 9
# chap 10
# chap 11
# chap 12
## chap 12.1
### chap 12.1.1
#### chap 12.1.1.1
##### chap 12.1.1.1.1
###### chap 12.1.1.1.1.1
# chap 13
Execute (toc window autofit width):
set number
let g:vim_markdown_toc_autofit = 1
let line = '###### chap 12.1.1.1.1.1'
AssertEqual getline('33'), line
:Toc
let real_width = winwidth(0)
:lclose
let expected_width = len(line) + 2*5 + 1 + 3 - 7
AssertEqual real_width, expected_width
set nonumber
" 2 spaces * 5 additional header levels + 1 space for first header +
" 3 spaces for line numbers - 7 chars ('###### ') that don't show up on the TOC

View file

@ -0,0 +1,185 @@
Given markdown;
# a
Execute (Toc does not set nomodifiable on other files):
" Sanity check.
Assert &modifiable
:Toc
:lclose
:edit a
Assert &modifiable
Given markdown;
header 1
========
test
header 2
--------
test
### header 3
test
Execute (Toc setex headers):
:Toc
Expect (setex headers):
header 1
header 2
header 3
Given markdown;
# header 1
test
## header 2
test
### header 3
test
Execute (Toc atx headers):
:Toc
Expect (atx headers):
header 1
header 2
header 3
Given markdown;
ATX tests.
# h1 space
#h1 nospace
# h1 2 spaces
# h1 trailing hash #
## h2 space
##h2 nospace
## h2 trailing hash ##
### h3 space
###h3 nospace
### h3 trailing hash ###
#### h4
##### h5
###### h6
---
Relative positions.
# h1 before h2
## h2 between h1s
# h1 after h2
---
Setex tests.
setex h1
========
setex h2
--------
setex h1 single punctuation
=
setex h1 punctuation longer than header
================================
Prevent list vs Setex confusion:
- not Setex
- because list
---
Mixed tests.
setex h1 before atx
===================
## atx h2
### atx h3
# atx h1
setex h2
------------------
### atx h3 2
Execute (Toc multiple headers):
:Toc
Expect (multiple headers):
h1 space
h1 nospace
h1 2 spaces
h1 trailing hash
h2 space
h2 nospace
h2 trailing hash
h3 space
h3 nospace
h3 trailing hash
h4
h5
h6
h1 before h2
h2 between h1s
h1 after h2
setex h1
setex h2
setex h1 single punctuation
setex h1 punctuation longer than header
setex h1 before atx
atx h2
atx h3
atx h1
setex h2
atx h3 2
Execute:
:lclose
Given markdown;
# header 1
## header 2
### header 3
Execute (Toc cursor on the current header):
normal! 4G
:Toc
AssertEqual line('.'), 2
:lclose
normal! G
:Toc
AssertEqual line('.'), 3
:lclose

View file

@ -0,0 +1,27 @@
set nocompatible
set rtp+=../
set rtp+=../build/tabular/
set rtp+=../build/vim-toml/
set rtp+=../build/vim-json/
set rtp+=../build/vader.vim/
let $LANG='en_US'
filetype on
filetype plugin on
filetype indent on
syntax on
function! Markdown_GetScriptID(fname) abort
let a:snlist = ''
redir => a:snlist
silent! scriptnames
redir END
let a:mx = '^\s*\(\d\+\):\s*\(.*\)$'
for a:line in split(a:snlist, "\n")
if stridx(substitute(a:line, '\\', '/', 'g'), a:fname) >= 0
return substitute(a:line, a:mx, '\1', '')
endif
endfor
endfunction
function! Markdown_GetFunc(fname, funcname) abort
return function('<SNR>' . Markdown_GetScriptID(a:fname) . '_' . a:funcname)
endfunction

View file

@ -1,6 +1,6 @@
" repeat.vim - Let the repeat command repeat plugin maps
" Maintainer: Tim Pope
" Version: 1.1
" Version: 1.2
" GetLatestVimScripts: 2136 1 :AutoInstall: repeat.vim
" Installation:
@ -111,7 +111,8 @@ endfunction
function! repeat#wrap(command,count)
let preserve = (g:repeat_tick == b:changedtick)
exe 'norm! '.(a:count ? a:count : '').a:command . (&foldopen =~# 'undo\|all' ? 'zv' : '')
call feedkeys((a:count ? a:count : '').a:command, 'n')
exe (&foldopen =~# 'undo\|all' ? 'norm! zv' : '')
if preserve
let g:repeat_tick = b:changedtick
endif

View file

@ -1,7 +1,7 @@
# more can be found in snippets/html_minimal.snippets
# these UltiSnips override snippets because nested placeholders are being used
priority -50
priority -49
snippet id
id="$1"$2

View file

@ -608,6 +608,12 @@ returning ${1:variable} do${2/(^(?<var>\s*[a-z_][a-zA-Z0-9_]*\s*)(,\g<var>)*,?\s
end
endsnippet
snippet cmm "Create Migration Model Class"
class Migration${1/(?:^|_)(\w)/\u$1/g} < ApplicationRecord
self.table_name = :${1:model_name}s
end
endsnippet
snippet t. "t.binary (tcbi)"
t.binary :${1:title}${2:, :limit => ${3:2}.megabytes}
t.$0

View file

@ -8,7 +8,7 @@ priority -50
# Built In library #
######################
snippet cat "Catenate"
Catenate SEPARATOR=${1:---} ${2:Hello} ${3:world}
\${${1:name}}= Catenate SEPARATOR=${2:---} ${3:Hello} ${4:world}
endsnippet
snippet eval "Evaluate"
@ -109,6 +109,10 @@ snippet sgv "Set Global Variable"
Set Global Variable \${${1:name}} ${2:${value}}
endsnippet
snippet sbe "Should Be Equal"
Should Be Equal "\${${1:var}}" "${2:expected value}" ${3:"optional error msg"} ${4:ignore_case=True}
endsnippet
snippet sleep "Sleep"
Sleep ${1:2 minutes 10 seconds}
endsnippet
@ -142,6 +146,12 @@ Import library Dialogs
Pause execution
endsnippet
snippet tpause "Teardown Pause - pause test execution only on failure"
[Teardown] Run Keyword If Test Failed Run Keywords
... Import library Dialogs AND
... Pause execution
endsnippet
##############################
# Selenium2Library library #

View file

@ -2,6 +2,48 @@ priority -50
extends texmath
global !p
def create_table(snip):
rows = snip.buffer[snip.line].split('x')[0]
cols = snip.buffer[snip.line].split('x')[1]
int_val = lambda string: int(''.join(s for s in string if s.isdigit()))
rows = int_val(rows)
cols = int_val(cols)
offset = cols + 1
old_spacing = snip.buffer[snip.line][:snip.buffer[snip.line].rfind('\t') + 1]
snip.buffer[snip.line] = ''
final_str = old_spacing + "\\begin{tabular}{|" + "|".join(['$' + str(i + 1) for i in range(cols)]) + "|}\n"
for i in range(rows):
final_str += old_spacing + '\t'
final_str += " & ".join(['$' + str(i * cols + j + offset) for j in range(cols)])
final_str += " \\\\\\\n"
final_str += old_spacing + "\\end{tabular}\n$0"
snip.expand_anon(final_str)
def add_row(snip):
row_len = int(''.join(s for s in snip.buffer[snip.line] if s.isdigit()))
old_spacing = snip.buffer[snip.line][:snip.buffer[snip.line].rfind('\t') + 1]
snip.buffer[snip.line] = ''
final_str = old_spacing
final_str += " & ".join(['$' + str(j + 1) for j in range(row_len)])
final_str += " \\\\\\"
snip.expand_anon(final_str)
endglobal
snippet "b(egin)?" "begin{} / end{}" br
\begin{${1:something}}
${0:${VISUAL}}
@ -20,6 +62,14 @@ $0${2/(?<=.)(c|l|r)|./(?1: & )/g}
\end{$1${1/(t)$|(a)$|(.*)/(?1:abular)(?2:rray)/}}
endsnippet
pre_expand "create_table(snip)"
snippet "gentbl(\d+)x(\d+)" "Generate table of *width* by *height*" r
endsnippet
pre_expand "add_row(snip)"
snippet "tr(\d+)" "Add table row of dimension ..." r
endsnippet
snippet table "Table environment" b
\begin{table}[${1:htpb}]
\centering

View file

@ -0,0 +1,38 @@
snippet mod
module ${0:`expand('%:t:r')`}
snippet imp
import ${0:http}
snippet impt
import type ${0:option.option}
snippet exp
export ${0}
snippet expt
export ${0}
snippet fn
val ${1:fn} ${2}: fn ${3:'a} -> ${4:'a}
let $1 ${5} =
${0:${VISUAL}}
snippet mat
match ${1} with
| ${2} -> ${0}
snippet -
| ${1} -> ${0}
snippet let
let ${1} = ${2:${VISUAL}} in
${0}
snippet letf
let ${1} =
${0:${VISUAL}}
snippet ty
type ${1:msg}
= ${0}
snippet test
test "${1}" =
${0:${VISUAL}}
snippet doc
{-| ${0}
-}
snippet p
|> ${0}
snippet ae
assert.equal ${0}

View file

@ -48,6 +48,17 @@ snippet once
${0}
#endif /* end of include guard: $1 */
# Disable C++ name mangling in C headers
snippet nocxx
#ifdef __cplusplus
extern "C" {
#endif
${0}
#ifdef __cplusplus
} /* extern "C" */
#endif
##
## Control Statements
# if

Some files were not shown because too many files have changed in this diff Show more