diff --git a/etc/soft/nvim/+plugins/vimwiki/CONTRIBUTING.md b/etc/soft/nvim/+plugins/vimwiki/CONTRIBUTING.md
new file mode 100644
index 0000000..1685084
--- /dev/null
+++ b/etc/soft/nvim/+plugins/vimwiki/CONTRIBUTING.md
@@ -0,0 +1,63 @@
+# Filing a bug
+
+Before filing a bug or starting to write a patch, check the latest development version from
+https://github.com/vimwiki/vimwiki/tree/dev to see if your problem is already fixed.
+
+Issues can be filed at https://github.com/vimwiki/vimwiki/issues/ .
+
+# Creating a pull request
+
+If you want to provide a pull request on GitHub, please start from the `dev` branch, not from the
+`master` branch. (Caution, GitHub shows `master` as the default branch from which to start a PR.)
+
+Make sure to update `doc/vimwiki.txt` with the following information:
+
+1. Update the changelog to include information on the new feature the PR introduces or the bug it
+ is fixing.
+2. Add a help section to describe any new features or options.
+2. If you are a first time contributor add your name to the list of contributors.
+
+# More info and advice for (aspiring) core developers
+
+- Before implementing a non-trivial feature, think twice what it means for the user. We should
+ always try to keep backward compatibility. If you are not sure, discuss it on GitHub.
+- Also, when thinking about adding a new feature, it should be something which fits into the
+ overall design of Vimwiki and which a significant portion of the users may like. Keep in mind
+ that everybody has their own way to use Vimwiki.
+- Keep the coding style consistent.
+- Test your changes. Keep in mind that Vim has a ton of options and the users tons of different
+ setups. Take a little time to think about under which circumstances your changes could break.
+
+## Git branching model
+
+- there are two branches with eternal lifetime:
+ - `dev`: This is where the main development happens. Tasks which are done in one or only a few
+ commits go here directly. Always try to keep this branch in a working state, that is, if the
+ task you work on requires multiple commits, make sure intermediate commits don't make Vimwiki
+ unusable (or at least push these commits at one go).
+ - `master`: This branch is for released states only. Whenever a reasonable set of changes has
+ piled up in the `dev` branch, a [release is done](#Preparing a release). After a release,
+ `dev` has been merged into `master` and `master` got exactly one additional commit in which
+ the version number in `plugin/vimwiki.vim` is updated. Apart from these commits and the merge
+ commit from `dev`, nothing happens on `master`. Never should `master` merge into `dev`. When
+ the users ask, we should recommend this branch for them to use.
+- Larger changes which require multiple commits are done in feature branches. They are based on
+ `dev` and merge into `dev` when the work is done.
+
+## Preparing a release
+
+1. `git checkout dev`
+2. Update the changelog in the doc, nicely grouped, with a new version number and release date.
+3. Update the list of contributors.
+4. Update the version number at the top of the doc file.
+5. If necessary, update the Readme and the home page.
+6. `git checkout master && git merge dev`
+7. Update the version number at the top of plugin/vimwiki.vim.
+8. Set a tag with the version number in Git: `git tag vX.Y`
+9. `git push --tags`
+10. In GitHub, go to _Releases_ -> _Draft a new release_ -> choose the tag, convert the changelog from the
+ doc to markdown and post it there. Make plans to build an automatic converter and immediately
+ forget this plan.
+11. Tell the world.
+
+%% vim:tw=99
diff --git a/etc/soft/nvim/+plugins/vimwiki/LICENSE.md b/etc/soft/nvim/+plugins/vimwiki/LICENSE.md
new file mode 100644
index 0000000..cdf8546
--- /dev/null
+++ b/etc/soft/nvim/+plugins/vimwiki/LICENSE.md
@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2008-2010 Maxim Kim
+ 2013-2017 Daniel Schemala
+
+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.
diff --git a/etc/soft/nvim/+plugins/vimwiki/README-cn.md b/etc/soft/nvim/+plugins/vimwiki/README-cn.md
new file mode 100644
index 0000000..5d1a064
--- /dev/null
+++ b/etc/soft/nvim/+plugins/vimwiki/README-cn.md
@@ -0,0 +1,161 @@
+VimWiki —— Vim 个人 Wiki 插件
+==============================================================================
+
+[English](README.md)
+
+
+ *
+
+介绍
+------------------------------------------------------------------------------
+
+Vimwiki 是 Vim 中的个人 Wiki —— 一组链接起来的、有独特语法高亮的文本文件。
+
+通过 Vimwiki,你可以:
+
+ * 组织笔记和想法
+ * 管理待办事项
+ * 编写文档
+ * 坚持写日记
+ * 将这一切导出成 HTML 网页
+
+马上开始!按下 `')
- elseif level < plevel
- let plevel = s:close_list(toc, plevel, level)
- endif
- let toc_text = s:process_tags_remove_links(text)
- let toc_text = s:process_tags_typefaces(toc_text)
- call add(toc, '
'.param.'
')
- endif
- let shift = toc_idx * len(toc)
- call extend(a:dest, toc, row + shift)
- let toc_idx += 1
+ if type ==# 'date' && !empty(param)
+ return param
endif
endfor
endif
-endfunction "}}}
+ return a:default_date
+endfunction
-" get title.
-function! s:process_title(placeholders, default_title) "{{{
+
+function! s:process_title(placeholders, default_title)
if !empty(a:placeholders)
for [placeholder, row, idx] in a:placeholders
let [type, param] = placeholder
- if type == 'title' && !empty(param)
+ if type ==# 'title' && !empty(param)
return param
endif
endfor
endif
return a:default_title
-endfunction "}}}
+endfunction
+
-function! s:is_html_uptodate(wikifile) "{{{
+function! s:is_html_uptodate(wikifile)
let tpl_time = -1
let tpl_file = s:template_full_name('')
@@ -265,20 +239,20 @@ function! s:is_html_uptodate(wikifile) "{{{
endif
let wikifile = fnamemodify(a:wikifile, ":p")
- let subdir = vimwiki#base#subdir(VimwikiGet('path'), wikifile)
- let htmlfile = expand(VimwikiGet('path_html').subdir.
- \fnamemodify(wikifile, ":t:r").".html")
+ let htmlfile = expand(vimwiki#vars#get_wikilocal('path_html') .
+ \ vimwiki#vars#get_bufferlocal('subdir') . fnamemodify(wikifile, ":t:r").".html")
if getftime(wikifile) <= getftime(htmlfile) && tpl_time <= getftime(htmlfile)
return 1
endif
return 0
-endfunction "}}}
+endfunction
-function! s:html_insert_contents(html_lines, content) "{{{
+
+function! s:html_insert_contents(html_lines, content)
let lines = []
for line in a:html_lines
- if line =~ '%content%'
+ if line =~# '%content%'
let parts = split(line, '%content%', 1)
if empty(parts)
call extend(lines, a:content)
@@ -295,176 +269,217 @@ function! s:html_insert_contents(html_lines, content) "{{{
endif
endfor
return lines
-endfunction "}}}
-"}}}
+endfunction
-" INLINE TAGS "{{{
-function! s:tag_em(value) "{{{
- return ''.s:mid(a:value, 1).''
-endfunction "}}}
-function! s:tag_strong(value) "{{{
- return ''.s:mid(a:value, 1).''
-endfunction "}}}
+function! s:tag_eqin(value)
+ " mathJAX wants \( \) for inline maths
+ return '\('.s:mid(a:value, 1).'\)'
+endfunction
-function! s:tag_todo(value) "{{{
- return ''.a:value.''
-endfunction "}}}
-function! s:tag_strike(value) "{{{
- return ''.s:mid(a:value, 2).''
-endfunction "}}}
+function! s:tag_em(value)
+ return ''.s:mid(a:value, 1).''
+endfunction
-function! s:tag_super(value) "{{{
- return ''.s:mid(a:value, 1).''
-endfunction "}}}
-function! s:tag_sub(value) "{{{
- return ''.s:mid(a:value, 2).''
-endfunction "}}}
-
-function! s:tag_code(value) "{{{
- return ''.s:mid(a:value, 1).'
'
-endfunction "}}}
-
-function! s:tag_pre(value) "{{{
- return ''.s:mid(a:value, 3).'
'
-endfunction "}}}
-
-function! s:tag_internal_link(value) "{{{
- " Make This is a link
- " from [[This is a link]]
- " Make This is a link
- " from [[link|This is a link]]
- " Make This is a link
- " from [[link][This is a link]]
- " TODO: rename function -- it makes not only internal links.
- " TODO: refactor it.
-
- function! s:linkify(src, caption, style) "{{{
- if a:style == ''
- let style_str = ''
- else
- let style_str = ' style="'.a:style.'"'
- endif
-
- if s:is_img_link(a:caption)
- let link = ''.
- \ ''
- elseif vimwiki#base#is_non_wiki_link(a:src)
- let link = ''.a:caption.''
- elseif s:is_img_link(a:src)
- let link = '
'
- elseif vimwiki#base#is_link_to_dir(a:src)
- if g:vimwiki_dir_link == ''
- let link = ''.a:caption.''
- else
- let link = ''.a:caption.''
- endif
- else
- let link = ''.a:caption.''
+function! s:tag_strong(value, header_ids)
+ let text = s:mid(a:value, 1)
+ let id = s:escape_html_attribute(text)
+ let complete_id = ''
+ for l in range(6)
+ if a:header_ids[l][0] != ''
+ let complete_id .= a:header_ids[l][0].'-'
endif
+ endfor
+ if a:header_ids[5][0] == ''
+ let complete_id = complete_id[:-2]
+ endif
+ let complete_id .= '-'.id
+ return ''.text.''
+endfunction
- return link
- endfunction "}}}
-
- let value = s:mid(a:value, 2)
- let line = ''
- if value =~ '|'
- let link_parts = split(value, "|", 1)
- else
- let link_parts = split(value, "][", 1)
+function! s:tag_tags(value, header_ids)
+ let complete_id = ''
+ for level in range(6)
+ if a:header_ids[level][0] != ''
+ let complete_id .= a:header_ids[level][0].'-'
+ endif
+ endfor
+ if a:header_ids[5][0] == ''
+ let complete_id = complete_id[:-2]
endif
+ let complete_id = s:escape_html_attribute(complete_id)
+ let result = []
+ for tag in split(a:value, ':')
+ let id = s:escape_html_attribute(tag)
+ call add(result, ''.tag.'')
+ endfor
+ return join(result)
+endfunction
- if len(link_parts) > 1
- if len(link_parts) < 3
- let style = ""
- else
- let style = link_parts[2]
- endif
- let line = s:linkify(link_parts[0], link_parts[1], style)
+function! s:tag_todo(value)
+ return ''.a:value.''
+endfunction
- else
- let line = s:linkify(value, value, '')
- endif
- return line
-endfunction "}}}
-function! s:tag_external_link(value) "{{{
- "" Make link desc
- "" from [link link desc]
+function! s:tag_strike(value)
+ return '
'.s:mid(a:value, 2).''
+endfunction
- let value = s:mid(a:value, 1)
- let line = ''
- if s:is_web_link(value)
- let lnkElements = split(value)
- let head = lnkElements[0]
- let rest = join(lnkElements[1:])
- if rest==""
- let rest=head
- endif
- if s:is_img_link(rest)
- if rest!=head
- let line = ''
- else
- let line = '
'
+function! s:tag_super(value)
+ return ''.s:mid(a:value, 1).''
+endfunction
+
+
+function! s:tag_sub(value)
+ return ''.s:mid(a:value, 2).''
+endfunction
+
+
+function! s:tag_code(value)
+ return '
'.s:safe_html_preformatted(s:mid(a:value, 1)).'
'
+endfunction
+
+
+" match n-th ARG within {{URL[|ARG1|ARG2|...]}}
+" *c,d,e),...
+function! s:incl_match_arg(nn_index)
+ let rx = vimwiki#vars#get_global('rxWikiInclPrefix'). vimwiki#vars#get_global('rxWikiInclUrl')
+ let rx = rx . repeat(vimwiki#vars#get_global('rxWikiInclSeparator') .
+ \ vimwiki#vars#get_global('rxWikiInclArg'), a:nn_index-1)
+ if a:nn_index > 0
+ let rx = rx. vimwiki#vars#get_global('rxWikiInclSeparator'). '\zs' .
+ \ vimwiki#vars#get_global('rxWikiInclArg') . '\ze'
+ endif
+ let rx = rx . vimwiki#vars#get_global('rxWikiInclArgs') .
+ \ vimwiki#vars#get_global('rxWikiInclSuffix')
+ return rx
+endfunction
+
+
+function! s:linkify_link(src, descr)
+ let src_str = ' href="'.s:escape_html_attribute(a:src).'"'
+ let descr = vimwiki#u#trim(a:descr)
+ let descr = (descr == "" ? a:src : descr)
+ let descr_str = (descr =~# vimwiki#vars#get_global('rxWikiIncl')
+ \ ? s:tag_wikiincl(descr)
+ \ : descr)
+ return ''.descr_str.''
+endfunction
+
+
+function! s:linkify_image(src, descr, verbatim_str)
+ let src_str = ' src="'.a:src.'"'
+ let descr_str = (a:descr != '' ? ' alt="'.a:descr.'"' : '')
+ let verbatim_str = (a:verbatim_str != '' ? ' '.a:verbatim_str : '')
+ return ''
+endfunction
+
+
+function! s:tag_weblink(value)
+ " Weblink Template -> descr
+ let str = a:value
+ let url = matchstr(str, vimwiki#vars#get_syntaxlocal('rxWeblinkMatchUrl'))
+ let descr = matchstr(str, vimwiki#vars#get_syntaxlocal('rxWeblinkMatchDescr'))
+ let line = s:linkify_link(url, descr)
+ return line
+endfunction
+
+
+function! s:tag_wikiincl(value)
+ " {{imgurl|arg1|arg2}} -> ???
+ " {{imgurl}} ->
+ " {{imgurl|descr|style="A"}} ->
+ " {{imgurl|descr|class="B"}} ->
+ let str = a:value
+ " custom transclusions
+ let line = VimwikiWikiIncludeHandler(str)
+ " otherwise, assume image transclusion
+ if line == ''
+ let url_0 = matchstr(str, vimwiki#vars#get_global('rxWikiInclMatchUrl'))
+ let descr = matchstr(str, s:incl_match_arg(1))
+ let verbatim_str = matchstr(str, s:incl_match_arg(2))
+
+ let link_infos = vimwiki#base#resolve_link(url_0)
+
+ if link_infos.scheme =~# '\mlocal\|wiki\d\+\|diary'
+ let url = vimwiki#path#relpath(fnamemodify(s:current_html_file, ':h'), link_infos.filename)
+ " strip the .html extension when we have wiki links, so that the user can
+ " simply write {{image.png}} to include an image from the wiki directory
+ if link_infos.scheme =~# '\mwiki\d\+\|diary'
+ let url = fnamemodify(url, ':r')
endif
else
- let line = ''.rest.''
+ let url = link_infos.filename
endif
- elseif s:is_img_link(value)
- let line = '
'
- else
- " [alskfj sfsf] shouldn't be a link. So return it as it was --
- " enclosed in [...]
- let line = '['.value.']'
+
+ let url = escape(url, '#')
+ let line = s:linkify_image(url, descr, verbatim_str)
endif
return line
-endfunction "}}}
-
-function! s:tag_wikiword_link(value) "{{{
- " Make WikiWord from WikiWord
- if a:value[0] == '!'
- return a:value[1:]
- elseif g:vimwiki_camel_case
- let line = ''.a:value.''
- return line
- else
- return a:value
- endif
-endfunction "}}}
-
-function! s:tag_barebone_link(value) "{{{
- "" Make http://habamax.ru
- "" from http://habamax.ru
+endfunction
+
+
+function! s:tag_wikilink(value)
+ " [[url]] -> url
+ " [[url|descr]] -> descr
+ " [[url|{{...}}]] -> ...
+ " [[fileurl.ext|descr]] -> descr
+ " [[dirurl/|descr]] -> descr
+ " [[url#a1#a2]] -> url#a1#a2
+ " [[#a1#a2]] -> #a1#a2
+ let str = a:value
+ let url = matchstr(str, vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchUrl'))
+ let descr = matchstr(str, vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchDescr'))
+ let descr = vimwiki#u#trim(descr)
+ let descr = (descr != '' ? descr : url)
+
+ let line = VimwikiLinkConverter(url, s:current_wiki_file, s:current_html_file)
+ if line == ''
+ let link_infos = vimwiki#base#resolve_link(url, s:current_wiki_file)
+
+ if link_infos.scheme ==# 'file'
+ " external file links are always absolute
+ let html_link = link_infos.filename
+ elseif link_infos.scheme ==# 'local'
+ let html_link = vimwiki#path#relpath(fnamemodify(s:current_html_file, ':h'),
+ \ link_infos.filename)
+ elseif link_infos.scheme =~# '\mwiki\d\+\|diary'
+ " wiki links are always relative to the current file
+ let html_link = vimwiki#path#relpath(
+ \ fnamemodify(s:current_wiki_file, ':h'),
+ \ fnamemodify(link_infos.filename, ':r'))
+ if html_link !~ '\m/$'
+ let html_link .= '.html'
+ endif
+ else " other schemes, like http, are left untouched
+ let html_link = link_infos.filename
+ endif
- if s:is_img_link(a:value)
- let line = '
'
- else
- let line = ''.a:value.''
+ if link_infos.anchor != ''
+ let anchor = substitute(link_infos.anchor, '#', '-', 'g')
+ let html_link .= '#'.anchor
+ endif
+ let line = html_link
endif
+
+ let line = s:linkify_link(line, descr)
return line
-endfunction "}}}
+endfunction
-function! s:tag_no_wikiword_link(value) "{{{
- if a:value[0] == '!'
- return a:value[1:]
- else
- return a:value
- endif
-endfunction "}}}
-function! s:tag_remove_internal_link(value) "{{{
+function! s:tag_remove_internal_link(value)
let value = s:mid(a:value, 2)
let line = ''
- if value =~ '|'
+ if value =~# '|'
let link_parts = split(value, "|", 1)
else
let link_parts = split(value, "][", 1)
@@ -481,9 +496,10 @@ function! s:tag_remove_internal_link(value) "{{{
let line = value
endif
return line
-endfunction "}}}
+endfunction
-function! s:tag_remove_external_link(value) "{{{
+
+function! s:tag_remove_external_link(value)
let value = s:mid(a:value, 1)
let line = ''
@@ -491,8 +507,8 @@ function! s:tag_remove_external_link(value) "{{{
let lnkElements = split(value)
let head = lnkElements[0]
let rest = join(lnkElements[1:])
- if rest==""
- let rest=head
+ if rest == ""
+ let rest = head
endif
let line = rest
elseif s:is_img_link(value)
@@ -503,15 +519,25 @@ function! s:tag_remove_external_link(value) "{{{
let line = '['.value.']'
endif
return line
-endfunction "}}}
+endfunction
+
-function! s:make_tag(line, regexp, func) "{{{
+function! s:make_tag(line, regexp, func, ...)
" Make tags for a given matched regexp.
" Exclude preformatted text and href links.
-
- let patt_splitter = '\(`[^`]\+`\)\|\({{{.\+}}}\)\|'.
- \ '\(\)\|\(
\)'
- if '`[^`]\+`' == a:regexp || '{{{.\+}}}' == a:regexp
+ " FIXME
+ let patt_splitter = '\(`[^`]\+`\)\|'.
+ \ '\('.vimwiki#vars#get_syntaxlocal('rxPreStart').'.\+'.
+ \ vimwiki#vars#get_syntaxlocal('rxPreEnd').'\)\|'.
+ \ '\(\)\|'.
+ \ '\(
\)\|'.
+ \ '\(
") @@ -758,22 +810,62 @@ function! s:process_tag_pre(line, pre) "{{{ endif let pre = [1, len(matchstr(a:line, '^\s*\ze{{{'))] let processed = 1 - elseif pre[0] && a:line =~ '^\s*}}}\s*$' + elseif pre[0] && a:line =~# '^\s*}}}\s*$' let pre = [0, 0] call add(lines, "") let processed = 1 elseif pre[0] let processed = 1 - call add(lines, substitute(a:line, '^\s\{'.pre[1].'}', '', '')) + "XXX destroys indent in general! + "call add(lines, substitute(a:line, '^\s\{'.pre[1].'}', '', '')) + call add(lines, s:safe_html_preformatted(a:line)) endif return [processed, lines, pre] -endfunction "}}} +endfunction + + +function! s:process_tag_math(line, math) + " math is the list of [is_in_math, indent_of_math] + let lines = [] + let math = a:math + let processed = 0 + if !math[0] && a:line =~# '^\s*{{\$[^\(}}$\)]*\s*$' + let class = matchstr(a:line, '{{$\zs.*$') + "FIXME class cannot be any string! + let class = substitute(class, '\s\+$', '', 'g') + " store the environment name in a global variable in order to close the + " environment properly + let s:current_math_env = matchstr(class, '^%\zs\S\+\ze%') + if s:current_math_env != "" + call add(lines, substitute(class, '^%\(\S\+\)%', '\\begin{\1}', '')) + elseif class != "" + call add(lines, "\\\[".class) + else + call add(lines, "\\\[") + endif + let math = [1, len(matchstr(a:line, '^\s*\ze{{\$'))] + let processed = 1 + elseif math[0] && a:line =~# '^\s*}}\$\s*$' + let math = [0, 0] + if s:current_math_env != "" + call add(lines, "\\end{".s:current_math_env."}") + else + call add(lines, "\\\]") + endif + let processed = 1 + elseif math[0] + let processed = 1 + call add(lines, substitute(a:line, '^\s\{'.math[1].'}', '', '')) + endif + return [processed, lines, math] +endfunction + -function! s:process_tag_quote(line, quote) "{{{ +function! s:process_tag_quote(line, quote) let lines = [] let quote = a:quote let processed = 0 - if a:line =~ '^\s\{4,}\S' + if a:line =~# '^\s\{4,}\S' if !quote call add(lines, "
") let quote = 1 @@ -785,37 +877,38 @@ function! s:process_tag_quote(line, quote) "{{{ let quote = 0 endif return [processed, lines, quote] -endfunction "}}} +endfunction -function! s:process_tag_list(line, lists) "{{{ - function! s:add_checkbox(line, rx_list, st_tag, en_tag) "{{{ - let st_tag = a:st_tag - let en_tag = a:en_tag +function! s:process_tag_list(line, lists) + function! s:add_checkbox(line, rx_list) + let st_tag = '' let chk = matchlist(a:line, a:rx_list) - if len(chk) > 0 - if len(chk[1])>0 - "wildcard characters are difficult to match correctly - if chk[1] =~ '[.*\\^$~]' - let chk[1] ='\'.chk[1] - endif - let completion = match(g:vimwiki_listsyms, '\C' . chk[1]) - if completion >= 0 && completion <=4 - let st_tag = ' ' - endif + if !empty(chk) && len(chk[1]) > 0 + let completion = index(vimwiki#vars#get_syntaxlocal('listsyms_list'), chk[1]) + let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list')) + if completion == 0 + let st_tag = ' ' + elseif completion == -1 && chk[1] == vimwiki#vars#get_global('listsym_rejected') + let st_tag = ' ' + elseif completion > 0 && completion < n + let completion = float2nr(round(completion / (n-1.0) * 3.0 + 0.5 )) + let st_tag = ' ' endif endif - return [st_tag, en_tag] - endfunction "}}} + return [st_tag, ''] + endfunction + let in_list = (len(a:lists) > 0) " If it is not list yet then do not process line that starts from *bold* " text. + " XXX necessary? in *bold* text, no space must follow the first * if !in_list - let pos = match(a:line, g:vimwiki_rxBold) - if pos != -1 && strpart(a:line, 0, pos) =~ '^\s*$' + let pos = match(a:line, '^\s*'.vimwiki#vars#get_syntaxlocal('rxBold')) + if pos != -1 return [0, []] endif endif @@ -823,16 +916,16 @@ function! s:process_tag_list(line, lists) "{{{ let lines = [] let processed = 0 - if a:line =~ g:vimwiki_rxListBullet - let lstSym = matchstr(a:line, '[*-]') + if a:line =~# '^\s*'.s:bullets.'\s' + let lstSym = matchstr(a:line, s:bullets) let lstTagOpen = ' ' let lstTagClose = '
' - let lstRegExp = g:vimwiki_rxListBullet - elseif a:line =~ g:vimwiki_rxListNumber - let lstSym = '#' + let lstRegExp = '^\s*'.s:bullets.'\s' + elseif a:line =~# '^\s*'.s:numbers.'\s' + let lstSym = matchstr(a:line, s:numbers) let lstTagOpen = '' let lstTagClose = '
' - let lstRegExp = g:vimwiki_rxListNumber + let lstRegExp = '^\s*'.s:numbers.'\s' else let lstSym = '' let lstTagOpen = '' @@ -846,9 +939,8 @@ function! s:process_tag_list(line, lists) "{{{ let line = substitute(a:line, '\t', repeat(' ', &tabstop), 'g') let indent = stridx(line, lstSym) - let checkbox = '\s*\[\(.\?\)\]\s*' - let [st_tag, en_tag] = s:add_checkbox(line, - \ lstRegExp.checkbox, '', '') + let checkbox = '\s*\[\(.\)\]\s*' + let [st_tag, en_tag] = s:add_checkbox(line, lstRegExp.checkbox) if !in_list call add(a:lists, [lstTagClose, indent]) @@ -871,11 +963,10 @@ function! s:process_tag_list(line, lists) "{{{ call add(a:lists, [en_tag, indent]) call add(lines, st_tag) - call add(lines, - \ substitute(a:line, lstRegExp.'\%('.checkbox.'\)\?', '', '')) + call add(lines, substitute(a:line, lstRegExp.'\%('.checkbox.'\)\?', '', '')) let processed = 1 - elseif in_list > 0 && a:line =~ '^\s\+\S\+' - if g:vimwiki_list_ignore_newline + elseif in_list && a:line =~# '^\s\+\S\+' + if vimwiki#vars#get_global('list_ignore_newline') call add(lines, a:line) else call add(lines, '
'.a:line) @@ -885,9 +976,10 @@ function! s:process_tag_list(line, lists) "{{{ call s:close_tag_list(a:lists, lines) endif return [processed, lines] -endfunction "}}} +endfunction -function! s:process_tag_def_list(line, deflist) "{{{ + +function! s:process_tag_def_list(line, deflist) let lines = [] let deflist = a:deflist let processed = 0 @@ -909,68 +1001,86 @@ function! s:process_tag_def_list(line, deflist) "{{{ call add(lines, "") endif return [processed, lines, deflist] -endfunction "}}} +endfunction + -function! s:process_tag_para(line, para) "{{{ +function! s:process_tag_para(line, para) let lines = [] let para = a:para let processed = 0 - if a:line =~ '^\s\{,3}\S' + if a:line =~# '^\s\{,3}\S' if !para call add(lines, "") let para = 1 endif let processed = 1 - call add(lines, a:line) - elseif para && a:line =~ '^\s*$' + if vimwiki#vars#get_global('text_ignore_newline') + call add(lines, a:line) + else + call add(lines, a:line."
") let para = 0 endif return [processed, lines, para] -endfunction "}}} +endfunction + -function! s:process_tag_h(line, id) "{{{ +function! s:process_tag_h(line, id) let line = a:line let processed = 0 let h_level = 0 let h_text = '' let h_id = '' - if a:line =~ g:vimwiki_rxH6 - let h_level = 6 - elseif a:line =~ g:vimwiki_rxH5 - let h_level = 5 - elseif a:line =~ g:vimwiki_rxH4 - let h_level = 4 - elseif a:line =~ g:vimwiki_rxH3 - let h_level = 3 - elseif a:line =~ g:vimwiki_rxH2 - let h_level = 2 - elseif a:line =~ g:vimwiki_rxH1 - let h_level = 1 + + if a:line =~# vimwiki#vars#get_syntaxlocal('rxHeader') + let h_level = vimwiki#u#count_first_sym(a:line) endif if h_level > 0 - let a:id[h_level] += 1 - " reset higher level ids - for level in range(h_level+1, 6) - let a:id[level] = 0 - endfor - let centered = 0 - if a:line =~ '^\s\+' - let centered = 1 - endif + let h_text = vimwiki#u#trim(matchstr(line, vimwiki#vars#get_syntaxlocal('rxHeader'))) + let h_number = '' + let h_complete_id = '' + let h_id = s:escape_html_attribute(h_text) + let centered = (a:line =~# '^\s') - let line = s:trim(line) + if h_text !=# vimwiki#vars#get_global('toc_header') - let h_number = '' - for l in range(1, h_level-1) - let h_number .= a:id[l].'.' - endfor - let h_number .= a:id[h_level] + let a:id[h_level-1] = [h_text, a:id[h_level-1][1]+1] + + " reset higher level ids + for level in range(h_level, 5) + let a:id[level] = ['', 0] + endfor - let h_id = 'toc_'.h_number + for l in range(h_level-1) + let h_number .= a:id[l][1].'.' + if a:id[l][0] != '' + let h_complete_id .= a:id[l][0].'-' + endif + endfor + let h_number .= a:id[h_level-1][1] + let h_complete_id .= a:id[h_level-1][0] + + if vimwiki#vars#get_global('html_header_numbering') + let num = matchstr(h_number, + \ '^\(\d.\)\{'.(vimwiki#vars#get_global('html_header_numbering')-1).'}\zs.*') + if !empty(num) + let num .= vimwiki#vars#get_global('html_header_numbering_sym') + endif + let h_text = num.' '.h_text + endif + let h_complete_id = s:escape_html_attribute(h_complete_id) + let h_part = '' - let line = h_part.h_text.'' let processed = 1 endif - return [processed, line, h_level, h_text, h_id] -endfunction "}}} + return [processed, line] +endfunction + -function! s:process_tag_hr(line) "{{{ +function! s:process_tag_hr(line) let line = a:line let processed = 0 - if a:line =~ '^-----*$' + if a:line =~# '^-----*$' let line = '
") + endif + elseif para && a:line =~# '^\s*$' call add(lines, "
' let processed = 1 endif return [processed, line] -endfunction "}}} +endfunction -function! s:process_tag_table(line, table) "{{{ - function! s:table_empty_cell(value) "{{{ + +function! s:process_tag_table(line, table, header_ids) + function! s:table_empty_cell(value) let cell = {} - if a:value =~ '^\s*\\/\s*$' + if a:value =~# '^\s*\\/\s*$' let cell.body = '' let cell.rowspan = 0 let cell.colspan = 1 - elseif a:value =~ '^\s*>\s*$' + elseif a:value =~# '^\s*>\s*$' let cell.body = '' let cell.rowspan = 1 let cell.colspan = 0 - elseif a:value =~ '^\s*$' + elseif a:value =~# '^\s*$' let cell.body = ' ' let cell.rowspan = 1 let cell.colspan = 1 @@ -1027,11 +1132,11 @@ function! s:process_tag_table(line, table) "{{{ endif return cell - endfunction "}}} + endfunction - function! s:table_add_row(table, line) "{{{ + function! s:table_add_row(table, line) if empty(a:table) - if a:line =~ '^\s\+' + if a:line =~# '^\s\+' let row = ['center', []] else let row = ['normal', []] @@ -1040,60 +1145,83 @@ function! s:process_tag_table(line, table) "{{{ let row = [[]] endif return row - endfunction "}}} + endfunction let table = a:table let lines = [] let processed = 0 - if a:line =~ '^\s*|[-+]\+|\s*$' + if vimwiki#tbl#is_separator(a:line) call extend(table, s:table_add_row(a:table, a:line)) let processed = 1 - elseif a:line =~ '^\s*|.\+|\s*$' + elseif vimwiki#tbl#is_table(a:line) call extend(table, s:table_add_row(a:table, a:line)) let processed = 1 - let cells = split(a:line, '\s*|\s*', 1)[1: -2] + " let cells = split(a:line, vimwiki#tbl#cell_splitter(), 1)[1: -2] + let cells = vimwiki#tbl#get_cells(a:line) call map(cells, 's:table_empty_cell(v:val)') call extend(table[-1], cells) else - let table = s:close_tag_table(table, lines) + let table = s:close_tag_table(table, lines, a:header_ids) endif return [processed, lines, table] -endfunction "}}} - -"}}} +endfunction -" }}} -" WIKI2HTML "{{{ -function! s:parse_line(line, state) " {{{ +function! s:parse_line(line, state) let state = {} let state.para = a:state.para let state.quote = a:state.quote let state.pre = a:state.pre[:] + let state.math = a:state.math[:] let state.table = a:state.table[:] let state.lists = a:state.lists[:] let state.deflist = a:state.deflist let state.placeholder = a:state.placeholder - let state.toc = a:state.toc - let state.toc_id = a:state.toc_id + let state.header_ids = a:state.header_ids let res_lines = [] - let line = s:safe_html(a:line) + let line = s:safe_html_line(a:line) let processed = 0 + " pres + if !processed + let [processed, lines, state.pre] = s:process_tag_pre(line, state.pre) + " pre is just fine to be in the list -- do not close list item here. + " if processed && len(state.lists) + " call s:close_tag_list(state.lists, lines) + " endif + if !processed + let [processed, lines, state.math] = s:process_tag_math(line, state.math) + endif + if processed && len(state.table) + let state.table = s:close_tag_table(state.table, lines, state.header_ids) + endif + if processed && state.deflist + let state.deflist = s:close_tag_def_list(state.deflist, lines) + endif + if processed && state.quote + let state.quote = s:close_tag_quote(state.quote, lines) + endif + if processed && state.para + let state.para = s:close_tag_para(state.para, lines) + endif + call extend(res_lines, lines) + endif + + if !processed - if line =~ g:vimwiki_rxComment + if line =~# vimwiki#vars#get_syntaxlocal('rxComment') let processed = 1 endif endif " nohtml -- placeholder if !processed - if line =~ '^\s*%nohtml' + if line =~# '\m^\s*%nohtml\s*$' let processed = 1 let state.placeholder = ['nohtml'] endif @@ -1101,57 +1229,40 @@ function! s:parse_line(line, state) " {{{ " title -- placeholder if !processed - if line =~ '^\s*%title' + if line =~# '\m^\s*%title\%(\s.*\)\?$' let processed = 1 - let param = matchstr(line, '^\s*%title\s\zs.*') + let param = matchstr(line, '\m^\s*%title\s\+\zs.*') let state.placeholder = ['title', param] endif endif - " html template -- placeholder "{{{ + " date -- placeholder if !processed - if line =~ '^\s*%template' + if line =~# '\m^\s*%date\%(\s.*\)\?$' let processed = 1 - let param = matchstr(line, '^\s*%template\s\zs.*') - let state.placeholder = ['template', param] + let param = matchstr(line, '\m^\s*%date\s\+\zs.*') + let state.placeholder = ['date', param] endif endif - "}}} - " toc -- placeholder "{{{ + " html template -- placeholder if !processed - if line =~ '^\s*%toc' + if line =~# '\m^\s*%template\%(\s.*\)\?$' let processed = 1 - let param = matchstr(line, '^\s*%toc\s\zs.*') - let state.placeholder = ['toc', param] + let param = matchstr(line, '\m^\s*%template\s\+\zs.*') + let state.placeholder = ['template', param] endif endif - "}}} - " pres "{{{ + + " tables if !processed - let [processed, lines, state.pre] = s:process_tag_pre(line, state.pre) - " pre is just fine to be in the list -- do not close list item here. - " if processed && len(state.lists) - " call s:close_tag_list(state.lists, lines) - " endif - if processed && len(state.table) - let state.table = s:close_tag_table(state.table, lines) - endif - if processed && state.deflist - let state.deflist = s:close_tag_def_list(state.deflist, lines) - endif - if processed && state.quote - let state.quote = s:close_tag_quote(state.quote, lines) - endif - if processed && state.para - let state.para = s:close_tag_para(state.para, lines) - endif + let [processed, lines, state.table] = s:process_tag_table(line, state.table, state.header_ids) call extend(res_lines, lines) endif - "}}} - " lists "{{{ + + " lists if !processed let [processed, lines] = s:process_tag_list(line, state.lists) if processed && state.quote @@ -1160,8 +1271,11 @@ function! s:parse_line(line, state) " {{{ if processed && state.pre[0] let state.pre = s:close_tag_pre(state.pre, lines) endif + if processed && state.math[0] + let state.math = s:close_tag_math(state.math, lines) + endif if processed && len(state.table) - let state.table = s:close_tag_table(state.table, lines) + let state.table = s:close_tag_table(state.table, lines, state.header_ids) endif if processed && state.deflist let state.deflist = s:close_tag_def_list(state.deflist, lines) @@ -1170,40 +1284,29 @@ function! s:parse_line(line, state) " {{{ let state.para = s:close_tag_para(state.para, lines) endif - call map(lines, 's:process_inline_tags(v:val)') + call map(lines, 's:process_inline_tags(v:val, state.header_ids)') call extend(res_lines, lines) endif - "}}} - " headers "{{{ + + " headers if !processed - let [processed, line, h_level, h_text, h_id] = s:process_tag_h(line, state.toc_id) + let [processed, line] = s:process_tag_h(line, state.header_ids) if processed call s:close_tag_list(state.lists, res_lines) - let state.table = s:close_tag_table(state.table, res_lines) + let state.table = s:close_tag_table(state.table, res_lines, state.header_ids) let state.pre = s:close_tag_pre(state.pre, res_lines) + let state.math = s:close_tag_math(state.math, res_lines) let state.quote = s:close_tag_quote(state.quote, res_lines) let state.para = s:close_tag_para(state.para, res_lines) - let line = s:process_inline_tags(line) - call add(res_lines, line) - - " gather information for table of contents - call add(state.toc, [h_level, h_text, h_id]) endif endif - "}}} - " tables "{{{ - if !processed - let [processed, lines, state.table] = s:process_tag_table(line, state.table) - call extend(res_lines, lines) - endif - "}}} - " quotes "{{{ + " quotes if !processed let [processed, lines, state.quote] = s:process_tag_quote(line, state.quote) if processed && len(state.lists) @@ -1213,44 +1316,48 @@ function! s:parse_line(line, state) " {{{ let state.deflist = s:close_tag_def_list(state.deflist, lines) endif if processed && len(state.table) - let state.table = s:close_tag_table(state.table, lines) + let state.table = s:close_tag_table(state.table, lines, state.header_ids) endif if processed && state.pre[0] let state.pre = s:close_tag_pre(state.pre, lines) endif + if processed && state.math[0] + let state.math = s:close_tag_math(state.math, lines) + endif if processed && state.para let state.para = s:close_tag_para(state.para, lines) endif - call map(lines, 's:process_inline_tags(v:val)') + call map(lines, 's:process_inline_tags(v:val, state.header_ids)') call extend(res_lines, lines) endif - "}}} - " horizontal rules "{{{ + + " horizontal rules if !processed let [processed, line] = s:process_tag_hr(line) if processed call s:close_tag_list(state.lists, res_lines) - let state.table = s:close_tag_table(state.table, res_lines) + let state.table = s:close_tag_table(state.table, res_lines, state.header_ids) let state.pre = s:close_tag_pre(state.pre, res_lines) + let state.math = s:close_tag_math(state.math, res_lines) call add(res_lines, line) endif endif - "}}} - " definition lists "{{{ + + " definition lists if !processed let [processed, lines, state.deflist] = s:process_tag_def_list(line, state.deflist) - call map(lines, 's:process_inline_tags(v:val)') + call map(lines, 's:process_inline_tags(v:val, state.header_ids)') call extend(res_lines, lines) endif - "}}} - "" P "{{{ + + "" P if !processed let [processed, lines, state.para] = s:process_tag_para(line, state.para) if processed && len(state.lists) @@ -1262,15 +1369,18 @@ function! s:parse_line(line, state) " {{{ if processed && state.pre[0] let state.pre = s:close_tag_pre(state.pre, res_lines) endif + if processed && state.math[0] + let state.math = s:close_tag_math(state.math, res_lines) + endif if processed && len(state.table) - let state.table = s:close_tag_table(state.table, res_lines) + let state.table = s:close_tag_table(state.table, res_lines, state.header_ids) endif - call map(lines, 's:process_inline_tags(v:val)') + call map(lines, 's:process_inline_tags(v:val, state.header_ids)') call extend(res_lines, lines) endif - "}}} + "" add the rest if !processed @@ -1279,163 +1389,276 @@ function! s:parse_line(line, state) " {{{ return [res_lines, state] -endfunction " }}} - -function! vimwiki#html#Wiki2HTML(path, wikifile) "{{{ - - let starttime = reltime() " start the clock - " echo 'Generating HTML ... ' - if !s:syntax_supported() - echomsg 'vimwiki: Only vimwiki_default syntax supported!!!' - return - endif +endfunction + + +function! s:use_custom_wiki2html() + let custom_wiki2html = vimwiki#vars#get_wikilocal('custom_wiki2html') + return !empty(custom_wiki2html) && + \ (s:file_exists(custom_wiki2html) || s:binary_exists(custom_wiki2html)) +endfunction + + +function! vimwiki#html#CustomWiki2HTML(path, wikifile, force) + call vimwiki#path#mkdir(a:path) + echomsg system(vimwiki#vars#get_wikilocal('custom_wiki2html'). ' '. + \ a:force. ' '. + \ vimwiki#vars#get_wikilocal('syntax'). ' '. + \ strpart(vimwiki#vars#get_wikilocal('ext'), 1). ' '. + \ shellescape(a:path). ' '. + \ shellescape(a:wikifile). ' '. + \ shellescape(s:default_CSS_full_name(a:path)). ' '. + \ (len(vimwiki#vars#get_wikilocal('template_path')) > 1 ? + \ shellescape(expand(vimwiki#vars#get_wikilocal('template_path'))) : '-'). ' '. + \ (len(vimwiki#vars#get_wikilocal('template_default')) > 0 ? + \ vimwiki#vars#get_wikilocal('template_default') : '-'). ' '. + \ (len(vimwiki#vars#get_wikilocal('template_ext')) > 0 ? + \ vimwiki#vars#get_wikilocal('template_ext') : '-'). ' '. + \ (len(vimwiki#vars#get_bufferlocal('subdir')) > 0 ? + \ shellescape(s:root_path(vimwiki#vars#get_bufferlocal('subdir'))) : '-'). ' '. + \ (len(vimwiki#vars#get_wikilocal('custom_wiki2html_args')) > 0 ? + \ vimwiki#vars#get_wikilocal('custom_wiki2html_args') : '-')) +endfunction + + +function! s:convert_file(path_html, wikifile) + let done = 0 let wikifile = fnamemodify(a:wikifile, ":p") - let subdir = vimwiki#base#subdir(VimwikiGet('path'), wikifile) - let path = expand(a:path).subdir + let path_html = expand(a:path_html).vimwiki#vars#get_bufferlocal('subdir') let htmlfile = fnamemodify(wikifile, ":t:r").'.html' - let lsource = readfile(wikifile) - let ldest = [] + " the currently processed file name is needed when processing links + " yeah yeah, shame on me for using (quasi-) global variables + let s:current_wiki_file = wikifile + let s:current_html_file = path_html . htmlfile - call vimwiki#base#mkdir(path) + if s:use_custom_wiki2html() + let force = 1 + call vimwiki#html#CustomWiki2HTML(path_html, wikifile, force) + let done = 1 + endif - " nohtml placeholder -- to skip html generation. - let nohtml = 0 + if s:syntax_supported() && done == 0 + let lsource = readfile(wikifile) + let ldest = [] + + call vimwiki#path#mkdir(path_html) + + " nohtml placeholder -- to skip html generation. + let nohtml = 0 + + " template placeholder + let template_name = '' + + " for table of contents placeholders. + let placeholders = [] + + " current state of converter + let state = {} + let state.para = 0 + let state.quote = 0 + let state.pre = [0, 0] " [in_pre, indent_pre] + let state.math = [0, 0] " [in_math, indent_math] + let state.table = [] + let state.deflist = 0 + let state.lists = [] + let state.placeholder = [] + let state.header_ids = [['', 0], ['', 0], ['', 0], ['', 0], ['', 0], ['', 0]] + " [last seen header text in this level, number] + + " prepare constants for s:safe_html_line() + let s:lt_pattern = '<' + let s:gt_pattern = '>' + if vimwiki#vars#get_global('valid_html_tags') != '' + let tags = join(split(vimwiki#vars#get_global('valid_html_tags'), '\s*,\s*'), '\|') + let s:lt_pattern = '\c<\%(/\?\%('.tags.'\)\%(\s\{-1}\S\{-}\)\{-}/\?>\)\@!' + let s:gt_pattern = '\c\%(\?\%('.tags.'\)\%(\s\{-1}\S\{-}\)\{-}/\?\)\@' + endif - " template placeholder - let template_name = '' + " prepare regexps for lists + let s:bullets = '[*-]' + let s:numbers = '\C\%(#\|\d\+)\|\d\+\.\|[ivxlcdm]\+)\|[IVXLCDM]\+)\|\l\{1,2})\|\u\{1,2})\)' - " for table of contents placeholders. - let placeholders = [] + for line in lsource + let oldquote = state.quote + let [lines, state] = s:parse_line(line, state) - " current state of converter - let state = {} - let state.para = 0 - let state.quote = 0 - let state.pre = [0, 0] " [in_pre, indent_pre] - let state.table = [] - let state.deflist = 0 - let state.lists = [] - let state.placeholder = [] - let state.toc = [] - let state.toc_id = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 } - - for line in lsource - let oldquote = state.quote - let [lines, state] = s:parse_line(line, state) - - " Hack: There could be a lot of empty strings before s:process_tag_quote - " find out `quote` is over. So we should delete them all. Think of the way - " to refactor it out. - if oldquote != state.quote - call s:remove_blank_lines(ldest) - endif - - if !empty(state.placeholder) - if state.placeholder[0] == 'nohtml' - let nohtml = 1 - break - elseif state.placeholder[0] == 'template' - let template_name = state.placeholder[1] - else - call add(placeholders, [state.placeholder, len(ldest), len(placeholders)]) + " Hack: There could be a lot of empty strings before s:process_tag_quote + " find out `quote` is over. So we should delete them all. Think of the way + " to refactor it out. + if oldquote != state.quote + call s:remove_blank_lines(ldest) + endif + + if !empty(state.placeholder) + if state.placeholder[0] ==# 'nohtml' + let nohtml = 1 + break + elseif state.placeholder[0] ==# 'template' + let template_name = state.placeholder[1] + else + call add(placeholders, [state.placeholder, len(ldest), len(placeholders)]) + endif + let state.placeholder = [] endif - let state.placeholder = [] + + call extend(ldest, lines) + endfor + + + if nohtml + echon "\r"."%nohtml placeholder found" + return '' endif + call s:remove_blank_lines(ldest) + + " process end of file + " close opened tags if any + let lines = [] + call s:close_tag_quote(state.quote, lines) + call s:close_tag_para(state.para, lines) + call s:close_tag_pre(state.pre, lines) + call s:close_tag_math(state.math, lines) + call s:close_tag_list(state.lists, lines) + call s:close_tag_def_list(state.deflist, lines) + call s:close_tag_table(state.table, lines, state.header_ids) call extend(ldest, lines) - endfor + let title = s:process_title(placeholders, fnamemodify(a:wikifile, ":t:r")) + let date = s:process_date(placeholders, strftime('%Y-%m-%d')) - if nohtml - echon "\r"."%nohtml placeholder found" - return - endif + let html_lines = s:get_html_template(template_name) - let toc = s:get_html_toc(state.toc) - call s:process_toc(ldest, placeholders, toc) - call s:remove_blank_lines(ldest) + " processing template variables (refactor to a function) + call map(html_lines, 'substitute(v:val, "%title%", "'. title .'", "g")') + call map(html_lines, 'substitute(v:val, "%date%", "'. date .'", "g")') + call map(html_lines, 'substitute(v:val, "%root_path%", "'. + \ s:root_path(vimwiki#vars#get_bufferlocal('subdir')) .'", "g")') - "" process end of file - "" close opened tags if any - let lines = [] - call s:close_tag_quote(state.quote, lines) - call s:close_tag_para(state.para, lines) - call s:close_tag_pre(state.pre, lines) - call s:close_tag_list(state.lists, lines) - call s:close_tag_def_list(state.deflist, lines) - call s:close_tag_table(state.table, lines) - call extend(ldest, lines) - - let title = s:process_title(placeholders, fnamemodify(a:wikifile, ":t:r")) - - let html_lines = s:get_html_template(a:wikifile, template_name) - - " processing template variables (refactor to a function) - call map(html_lines, 'substitute(v:val, "%title%", "'. title .'", "g")') - call map(html_lines, 'substitute(v:val, "%root_path%", "'. - \ s:root_path(subdir) .'", "g")') - - let css_name = expand(VimwikiGet('css_name')) - let css_name = substitute(css_name, '\', '/', 'g') - call map(html_lines, 'substitute(v:val, "%css%", "'. css_name .'", "g")') - - let enc = &fileencoding - if enc == '' - let enc = &encoding + let css_name = expand(vimwiki#vars#get_wikilocal('css_name')) + let css_name = substitute(css_name, '\', '/', 'g') + call map(html_lines, 'substitute(v:val, "%css%", "'. css_name .'", "g")') + + let enc = &fileencoding + if enc == '' + let enc = &encoding + endif + call map(html_lines, 'substitute(v:val, "%encoding%", "'. enc .'", "g")') + + let html_lines = s:html_insert_contents(html_lines, ldest) " %contents% + + call writefile(html_lines, path_html.htmlfile) + let done = 1 + + endif + + if done == 0 + echomsg 'Vimwiki Error: Conversion to HTML is not supported for this syntax' + return '' endif - call map(html_lines, 'substitute(v:val, "%encoding%", "'. enc .'", "g")') - let html_lines = s:html_insert_contents(html_lines, ldest) " %contents% - - "" make html file. - call writefile(html_lines, path.htmlfile) + return path_html.htmlfile +endfunction - " measure the elapsed time and cut away miliseconds and smaller - let elapsedtimestr = matchstr(reltimestr(reltime(starttime)),'\d\+\(\.\d\d\)\=') - " echon "\r".htmlfile.' written (time: '.elapsedtimestr.'s)' - return path.htmlfile -endfunction "}}} + +function! vimwiki#html#Wiki2HTML(path_html, wikifile) + let result = s:convert_file(a:path_html, a:wikifile) + if result != '' + call s:create_default_CSS(a:path_html) + endif + return result +endfunction -function! vimwiki#html#WikiAll2HTML(path) "{{{ - if !s:syntax_supported() - echomsg 'vimwiki: Only vimwiki_default syntax supported!!!' +function! vimwiki#html#WikiAll2HTML(path_html) + if !s:syntax_supported() && !s:use_custom_wiki2html() + echomsg 'Vimwiki Error: Conversion to HTML is not supported for this syntax' return endif - echomsg 'Saving vimwiki files...' + echomsg 'Vimwiki: Saving Vimwiki files ...' let save_eventignore = &eventignore let &eventignore = "all" - let cur_buf = bufname('%') - bufdo call s:save_vimwiki_buffer() - exe 'buffer '.cur_buf + try + wall + catch + " just ignore errors + endtry let &eventignore = save_eventignore - let path = expand(a:path) - call vimwiki#base#mkdir(path) + let path_html = expand(a:path_html) + call vimwiki#path#mkdir(path_html) - echomsg 'Deleting non-wiki html files...' - call s:delete_html_files(path) + echomsg 'Vimwiki: Deleting non-wiki html files ...' + call s:delete_html_files(path_html) - echomsg 'Converting wiki to html files...' + echomsg 'Vimwiki: Converting wiki to html files ...' let setting_more = &more setlocal nomore - let wikifiles = split(glob(VimwikiGet('path').'**/*'.VimwikiGet('ext')), '\n') + " temporarily adjust current_subdir global state variable + let current_subdir = vimwiki#vars#get_bufferlocal('subdir') + let current_invsubdir = vimwiki#vars#get_bufferlocal('invsubdir') + + let wikifiles = split(glob(vimwiki#vars#get_wikilocal('path').'**/*'. + \ vimwiki#vars#get_wikilocal('ext')), '\n') for wikifile in wikifiles + let wikifile = fnamemodify(wikifile, ":p") + + " temporarily adjust 'subdir' and 'invsubdir' state variables + let subdir = vimwiki#base#subdir(vimwiki#vars#get_wikilocal('path'), wikifile) + call vimwiki#vars#set_bufferlocal('subdir', subdir) + call vimwiki#vars#set_bufferlocal('invsubdir', vimwiki#base#invsubdir(subdir)) + if !s:is_html_uptodate(wikifile) - echomsg 'Processing '.wikifile - call vimwiki#html#Wiki2HTML(path, wikifile) + echomsg 'Vimwiki: Processing '.wikifile + + call s:convert_file(path_html, wikifile) else - echomsg 'Skipping '.wikifile + echomsg 'Vimwiki: Skipping '.wikifile endif endfor - call s:create_default_CSS(path) - echomsg 'Done!' + " reset 'subdir' state variable + call vimwiki#vars#set_bufferlocal('subdir', current_subdir) + call vimwiki#vars#set_bufferlocal('invsubdir', current_invsubdir) + + let created = s:create_default_CSS(path_html) + if created + echomsg 'Vimwiki: Default style.css has been created' + endif + echomsg 'Vimwiki: HTML exported to '.path_html + echomsg 'Vimwiki: Done!' let &more = setting_more -endfunction "}}} -"}}} +endfunction + + +function! s:file_exists(fname) + return !empty(getftype(expand(a:fname))) +endfunction + + +function! s:binary_exists(fname) + return executable(expand(a:fname)) +endfunction + + +function! s:get_wikifile_url(wikifile) + return vimwiki#vars#get_wikilocal('path_html') . + \ vimwiki#base#subdir(vimwiki#vars#get_wikilocal('path'), a:wikifile). + \ fnamemodify(a:wikifile, ":t:r").'.html' +endfunction + + +function! vimwiki#html#PasteUrl(wikifile) + execute 'r !echo file://'.s:get_wikifile_url(a:wikifile) +endfunction + + +function! vimwiki#html#CatUrl(wikifile) + execute '!echo file://'.s:get_wikifile_url(a:wikifile) +endfunction + diff --git a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/lst.vim b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/lst.vim index a359d96..201a658 100644 --- a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/lst.vim +++ b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/lst.vim @@ -1,369 +1,1697 @@ -" vim:tabstop=2:shiftwidth=2:expandtab:foldmethod=marker:textwidth=79 +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 " Vimwiki autoload plugin file -" Todo lists related stuff here. -" Author: Maxim Kim-" Home: http://code.google.com/p/vimwiki/ +" Description: Everything concerning lists and checkboxes +" Home: https://github.com/vimwiki/vimwiki/ + if exists("g:loaded_vimwiki_list_auto") || &cp finish endif -let g:loaded_vimwiki_lst_auto = 1 +let g:loaded_vimwiki_list_auto = 1 -" Script variables {{{ -let s:rx_li_box = '\[.\?\]' -" }}} -" Script functions {{{ +" --------------------------------------------------------- +" incrementation functions for the various kinds of numbers +" --------------------------------------------------------- -" Get checkbox regexp -function! s:rx_li_symbol(rate) "{{{ - let result = '' - if a:rate == 100 - let result = g:vimwiki_listsyms[4] - elseif a:rate == 0 - let result = g:vimwiki_listsyms[0] - elseif a:rate >= 67 - let result = g:vimwiki_listsyms[3] - elseif a:rate >= 34 - let result = g:vimwiki_listsyms[2] +function! s:increment_1(value) + return eval(a:value) + 1 +endfunction + + +function! s:increment_A(value) + let list_of_chars = split(a:value, '.\zs') + let done = 0 + for idx in reverse(range(len(list_of_chars))) + let cur_num = char2nr(list_of_chars[idx]) + if cur_num < 90 + let list_of_chars[idx] = nr2char(cur_num + 1) + let done = 1 + break + else + let list_of_chars[idx] = 'A' + endif + endfor + if !done + call insert(list_of_chars, 'A') + endif + return join(list_of_chars, '') +endfunction + + +function! s:increment_a(value) + let list_of_chars = split(a:value, '.\zs') + let done = 0 + for idx in reverse(range(len(list_of_chars))) + let cur_num = char2nr(list_of_chars[idx]) + if cur_num < 122 + let list_of_chars[idx] = nr2char(cur_num + 1) + let done = 1 + break + else + let list_of_chars[idx] = 'a' + endif + endfor + if !done + call insert(list_of_chars, 'a') + endif + return join(list_of_chars, '') +endfunction + + +function! s:increment_I(value) + let subst_list = [ ['XLVIII$', 'IL'], ['VIII$', 'IX'], ['III$', 'IV'], + \ ['DCCCXCIX$', 'CM'], ['CCCXCIX$', 'CD'], ['LXXXIX$', 'XC'], + \ ['XXXIX$', 'XL'], ['\(I\{1,2\}\)$', '\1I'], ['CDXCIX$', 'D'], + \ ['CMXCIX$', 'M'], ['XCIX$', 'C'], ['I\([VXLCDM]\)$', '\1'], + \ ['\([VXLCDM]\)$', '\1I'] ] + for [regex, subst] in subst_list + if a:value =~# regex + return substitute(a:value, regex, subst, '') + endif + endfor + return '' +endfunction + + +function! s:increment_i(value) + let subst_list = [ ['xlviii$', 'il'], ['viii$', 'ix'], ['iii$', 'iv'], + \ ['dcccxcix$', 'cm'], ['cccxcix$', 'cd'], ['lxxxix$', 'xc'], + \ ['xxxix$', 'xl'], ['\(i\{1,2\}\)$', '\1i'], ['cdxcix$', 'd'], + \ ['cmxcix$', 'm'], ['xcix$', 'c'], ['i\([vxlcdm]\)$', '\1'], + \ ['\([vxlcdm]\)$', '\1i'] ] + for [regex, subst] in subst_list + if a:value =~# regex + return substitute(a:value, regex, subst, '') + endif + endfor + return '' +endfunction + + +" --------------------------------------------------------- +" utility functions +" --------------------------------------------------------- + +function! s:substitute_rx_in_line(lnum, pattern, new_string) + call setline(a:lnum, substitute(getline(a:lnum), a:pattern, a:new_string, '')) +endfunction + + +function! s:substitute_string_in_line(lnum, old_string, new_string) + call s:substitute_rx_in_line(a:lnum, vimwiki#u#escape(a:old_string), a:new_string) +endfunction + + +function! s:first_char(string) + return matchstr(a:string, '^.') +endfunction + + +if exists("*strdisplaywidth") + function! s:string_length(str) + return strdisplaywidth(a:str) + endfunction +else + function! s:string_length(str) + return strlen(substitute(a:str, '.', 'x', 'g')) + endfunction +endif + + +function! vimwiki#lst#default_symbol() + return vimwiki#vars#get_syntaxlocal('list_markers')[0] +endfunction + + +function! vimwiki#lst#get_list_margin() + let list_margin = vimwiki#vars#get_wikilocal('list_margin') + if list_margin < 0 + return &sw else - let result = g:vimwiki_listsyms[1] + return list_margin endif +endfunction - return '\['.result.'\]' -endfunction "}}} -" Get regexp of the list item. -function! s:rx_list_item() "{{{ - return '\('.g:vimwiki_rxListBullet.'\|'.g:vimwiki_rxListNumber.'\)' -endfunction "}}} +"Returns: the column where the text of a line starts (possible list item +"markers and checkboxes are skipped) +function! s:text_begin(lnum) + return s:string_length(matchstr(getline(a:lnum), vimwiki#vars#get_syntaxlocal('rxListItem'))) +endfunction -" Get regexp of the list item with checkbox. -function! s:rx_cb_list_item() "{{{ - return s:rx_list_item().'\s*\zs\[.\?\]' -endfunction "}}} -" Get level of the list item. -function! s:get_level(lnum) "{{{ - if VimwikiGet('syntax') == 'media' - let level = vimwiki#base#count_first_sym(getline(a:lnum)) +"Returns: 2 if there is a marker and text +" 1 for a marker and no text +" 0 for no marker at all (empty line or only text) +function! s:line_has_marker(lnum) + if getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxListItem').'\s*$' + return 1 + elseif getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxListItem').'\s*\S' + return 2 else + return 0 + endif +endfunction + + +" --------------------------------------------------------- +" get properties of a list item +" --------------------------------------------------------- + +"Returns: the mainly used data structure in this file +"An item represents a single list item and is a dictionary with the keys +"lnum - the line number of the list item +"type - 1 for bulleted item, 2 for numbered item, 0 for a regular line +"mrkr - the concrete marker, e.g. '**' or 'b)' +"cb - the char in the checkbox or '' if there is no checkbox +function! s:get_item(lnum) + let item = {'lnum': a:lnum} + if a:lnum == 0 || a:lnum > line('$') + let item.type = 0 + return item + endif + + let matches = matchlist(getline(a:lnum), vimwiki#vars#get_syntaxlocal('rxListItem')) + if matches == [] || + \ (matches[1] == '' && matches[2] == '') || + \ (matches[1] != '' && matches[2] != '') + let item.type = 0 + return item + endif + + let item.cb = matches[3] + + if matches[1] != '' + let item.type = 1 + let item.mrkr = matches[1] + else + let item.type = 2 + let item.mrkr = matches[2] + endif + + return item +endfunction + + +function! s:empty_item() + return {'type': 0} +endfunction + + +"Returns: level of the line +"0 is the 'highest' level +function! s:get_level(lnum) + if getline(a:lnum) =~# '^\s*$' + return 0 + endif + if !vimwiki#vars#get_syntaxlocal('recurring_bullets') let level = indent(a:lnum) + else + let level = s:string_length(matchstr(getline(a:lnum), + \ vimwiki#vars#get_syntaxlocal(rx_bullet_chars)))-1 + if level < 0 + let level = (indent(a:lnum) == 0) ? 0 : 9999 + endif endif return level -endfunction "}}} +endfunction + + +"Returns: 1, a, i, A, I or '' +"If in doubt if alphanumeric character or romanian +"numeral, peek in the previous line +function! s:guess_kind_of_numbered_item(item) + if a:item.type != 2 | return '' | endif + let number_chars = a:item.mrkr[:-2] + let divisor = a:item.mrkr[-1:] + + let number_kinds = vimwiki#vars#get_syntaxlocal('number_kinds') + + if number_chars =~# '\d\+' + return '1' + endif + if number_chars =~# '\l\+' + if number_chars !~# '^[ivxlcdm]\+' || index(number_kinds, 'i') == -1 + return 'a' + else + + let item_above = s:get_prev_list_item(a:item, 0) + if item_above.type != 0 + if index(number_kinds, 'a') == -1 || + \ (item_above.mrkr[-1:] !=# divisor && number_chars =~# 'i\+') || + \ s:increment_i(item_above.mrkr[:-2]) ==# number_chars + return 'i' + else + return 'a' + endif + else + if number_chars =~# 'i\+' || index(number_kinds, 'a') == -1 + return 'i' + else + return 'a' + endif + endif -" Get previous list item. -" Returns: line number or 0. -function! s:prev_list_item(lnum) "{{{ - let c_lnum = a:lnum - 1 - while c_lnum >= 1 - let line = getline(c_lnum) - if line =~ s:rx_list_item() - return c_lnum endif - if line =~ '^\s*$' - return 0 + endif + if number_chars =~# '\u\+' + if number_chars !~# '^[IVXLCDM]\+' || index(number_kinds, 'I') == -1 + return 'A' + else + + let item_above = s:get_prev_list_item(a:item, 0) + if item_above.type != 0 + if index(number_kinds, 'A') == -1 || + \ (item_above.mrkr[-1:] !=# divisor && number_chars =~# 'I\+') || + \ s:increment_I(item_above.mrkr[:-2]) ==# number_chars + return 'I' + else + return 'A' + endif + else + if number_chars =~# 'I\+' || index(number_kinds, 'A') == -1 + return 'I' + else + return 'A' + endif + endif + endif - let c_lnum -= 1 + endif +endfunction + + +function! s:regexp_of_marker(item) + if a:item.type == 1 + return vimwiki#u#escape(a:item.mrkr) + elseif a:item.type == 2 + let number_divisors = vimwiki#vars#get_syntaxlocal('number_divisors') + for ki in ['d', 'u', 'l'] + let match = matchstr(a:item.mrkr, '\'.ki.'\+['.number_divisors.']') + if match != '' + return '\'.ki.'\+'.vimwiki#u#escape(match[-1:]) + endif + endfor + else + return '' + endif +endfunction + + +" Returns: Whether or not the checkbox of a list item is [X] or [-] +function! s:is_closed(item) + let state = a:item.cb + return state ==# vimwiki#vars#get_syntaxlocal('listsyms_list')[-1] + \ || state ==# vimwiki#vars#get_global('listsym_rejected') +endfunction + +" --------------------------------------------------------- +" functions for navigating between items +" --------------------------------------------------------- + +"Returns: the list item after a:item or an empty item +"If a:ignore_kind is 1, the markers can differ +function! s:get_next_list_item(item, ignore_kind) + let org_lvl = s:get_level(a:item.lnum) + if !a:ignore_kind + let org_regex = s:regexp_of_marker(a:item) + endif + + let cur_ln = s:get_next_line(a:item.lnum) + while cur_ln <= line('$') + let cur_lvl = s:get_level(cur_ln) + if cur_lvl <= org_lvl + if a:ignore_kind + return s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl) + else + return s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex) + endif + endif + let cur_ln = s:get_next_line(cur_ln) endwhile - return 0 -endfunction "}}} - -" Get next list item in the list. -" Returns: line number or 0. -function! s:next_list_item(lnum) "{{{ - let c_lnum = a:lnum + 1 - while c_lnum <= line('$') - let line = getline(c_lnum) - if line =~ s:rx_list_item() - return c_lnum - endif - if line =~ '^\s*$' - return 0 - endif - let c_lnum += 1 + return s:empty_item() +endfunction + + +"Returns: the list item before a:item or an empty item +"If a:ignore_kind is 1, the markers can differ +function! s:get_prev_list_item(item, ignore_kind) + let org_lvl = s:get_level(a:item.lnum) + if !a:ignore_kind + let org_regex = s:regexp_of_marker(a:item) + endif + + let cur_ln = s:get_prev_line(a:item.lnum) + while cur_ln >= 1 + let cur_lvl = s:get_level(cur_ln) + if cur_lvl <= org_lvl + if a:ignore_kind + return s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl) + else + return s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex) + endif + endif + let cur_ln = s:get_prev_line(cur_ln) + endwhile + return s:empty_item() +endfunction + + +function! s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex) + let cur_linecontent = getline(a:cur_ln) + if a:cur_lvl == a:org_lvl + if cur_linecontent =~# '^\s*'.a:org_regex.'\s' + return s:get_item(a:cur_ln) + else + return s:empty_item() + endif + elseif a:cur_lvl < a:org_lvl + return s:empty_item() + endif +endfunction + + +function! s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl) + if a:cur_lvl == a:org_lvl + return s:get_item(a:cur_ln) + elseif a:cur_lvl < a:org_lvl + return s:empty_item() + endif +endfunction + + +function! s:get_first_item_in_list(item, ignore_kind) + let cur_item = a:item + while 1 + let prev_item = s:get_prev_list_item(cur_item, a:ignore_kind) + if prev_item.type == 0 + break + else + let cur_item = prev_item + endif endwhile - return 0 -endfunction "}}} - -" Find next list item in the buffer. -" Returns: line number or 0. -function! s:find_next_list_item(lnum) "{{{ - let c_lnum = a:lnum + 1 - while c_lnum <= line('$') - let line = getline(c_lnum) - if line =~ s:rx_list_item() - return c_lnum - endif - let c_lnum += 1 + return cur_item +endfunction + + +function! s:get_last_item_in_list(item, ignore_kind) + let cur_item = a:item + while 1 + let next_item = s:get_next_list_item(cur_item, a:ignore_kind) + if next_item.type == 0 + break + else + let cur_item = next_item + endif endwhile - return 0 -endfunction "}}} - -" Set state of the list item on line number "lnum" to [ ] or [x] -function! s:set_state(lnum, rate) "{{{ - let line = getline(a:lnum) - let state = s:rx_li_symbol(a:rate) - let line = substitute(line, s:rx_li_box, state, '') - call setline(a:lnum, line) -endfunction "}}} - -" Get state of the list item on line number "lnum" -function! s:get_state(lnum) "{{{ - let state = 0 - let line = getline(a:lnum) - let opt = matchstr(line, s:rx_cb_list_item()) - if opt =~ s:rx_li_symbol(100) - let state = 100 - elseif opt =~ s:rx_li_symbol(0) - let state = 0 - elseif opt =~ s:rx_li_symbol(25) - let state = 25 - elseif opt =~ s:rx_li_symbol(50) - let state = 50 - elseif opt =~ s:rx_li_symbol(75) - let state = 75 + return cur_item +endfunction + + +"Returns: lnum+1 in most cases, but skips blank lines and preformatted text, +"0 in case of nonvalid line. +"If there is no second argument, 0 is returned at a header, otherwise the +"header is skipped +function! s:get_next_line(lnum, ...) + if getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxPreStart') + let cur_ln = a:lnum + 1 + while cur_ln <= line('$') && getline(cur_ln) !~# vimwiki#vars#get_syntaxlocal('rxPreEnd') + let cur_ln += 1 + endwhile + let next_line = cur_ln + else + let next_line = nextnonblank(a:lnum+1) endif - return state -endfunction "}}} -" Returns 1 if there is checkbox on a list item, 0 otherwise. -function! s:is_cb_list_item(lnum) "{{{ - return getline(a:lnum) =~ s:rx_cb_list_item() -endfunction "}}} + if a:0 > 0 && getline(next_line) =~# vimwiki#vars#get_syntaxlocal('rxHeader') + let next_line = s:get_next_line(next_line, 1) + endif + + if next_line < 0 || next_line > line('$') || + \ (getline(next_line) =~# vimwiki#vars#get_syntaxlocal('rxHeader') && a:0 == 0) + return 0 + endif + + return next_line +endfunction -" Returns start line number of list item, 0 if it is not a list. -function! s:is_list_item(lnum) "{{{ - let c_lnum = a:lnum - while c_lnum >= 1 - let line = getline(c_lnum) - if line =~ s:rx_list_item() - return c_lnum + +"Returns: lnum-1 in most cases, but skips blank lines and preformatted text +"0 in case of nonvalid line and a header, because a header ends every list +function! s:get_prev_line(lnum) + let prev_line = prevnonblank(a:lnum-1) + + if getline(prev_line) =~# vimwiki#vars#get_syntaxlocal('rxPreEnd') + let cur_ln = a:lnum - 1 + while 1 + if cur_ln == 0 || getline(cur_ln) =~# vimwiki#vars#get_syntaxlocal('rxPreStart') + break + endif + let cur_ln -= 1 + endwhile + let prev_line = cur_ln + endif + + if prev_line < 0 || prev_line > line('$') || + \ getline(prev_line) =~# vimwiki#vars#get_syntaxlocal('rxHeader') + return 0 + endif + + return prev_line +endfunction + + +function! s:get_first_child(item) + if a:item.lnum >= line('$') + return s:empty_item() + endif + let org_lvl = s:get_level(a:item.lnum) + let cur_item = s:get_item(s:get_next_line(a:item.lnum)) + while 1 + if cur_item.type != 0 && s:get_level(cur_item.lnum) > org_lvl + return cur_item endif - if line =~ '^\s*$' - return 0 + if cur_item.lnum > line('$') || cur_item.lnum <= 0 || s:get_level(cur_item.lnum) <= org_lvl + return s:empty_item() endif - if indent(c_lnum) > indent(a:lnum) - return 0 + let cur_item = s:get_item(s:get_next_line(cur_item.lnum)) + endwhile +endfunction + + +"Returns: the next sibling of a:child, given the parent item +"Used for iterating over children +"Note: child items do not necessarily have the same indent, i.e. level +function! s:get_next_child_item(parent, child) + if a:parent.type == 0 | return s:empty_item() | endif + let parent_lvl = s:get_level(a:parent.lnum) + let cur_ln = s:get_last_line_of_item_incl_children(a:child) + while 1 + let next_line = s:get_next_line(cur_ln) + if next_line == 0 || s:get_level(next_line) <= parent_lvl + break + endif + let cur_ln = next_line + let cur_item = s:get_item(cur_ln) + if cur_item.type > 0 + return cur_item + endif + endwhile + return s:empty_item() +endfunction + + +function! s:get_parent(item) + let parent_line = 0 + + let cur_ln = prevnonblank(a:item.lnum) + let child_lvl = s:get_level(cur_ln) + if child_lvl == 0 + return s:empty_item() + endif + + while 1 + let cur_ln = s:get_prev_line(cur_ln) + if cur_ln == 0 | break | endif + let cur_lvl = s:get_level(cur_ln) + if cur_lvl < child_lvl + let cur_item = s:get_item(cur_ln) + if cur_item.type == 0 + let child_lvl = cur_lvl + continue + endif + let parent_line = cur_ln + break endif - let c_lnum -= 1 endwhile - return 0 -endfunction "}}} - -" Returns char column of checkbox. Used in parent/child checks. -function! s:get_li_pos(lnum) "{{{ - return stridx(getline(a:lnum), '[') -endfunction "}}} - -" Returns list of line numbers of parent and all its child items. -function! s:get_child_items(lnum) "{{{ - let result = [] - let lnum = a:lnum - let p_pos = s:get_level(lnum) - - " add parent - call add(result, lnum) - - let lnum = s:next_list_item(lnum) - while lnum != 0 && s:is_list_item(lnum) && s:get_level(lnum) > p_pos - call add(result, lnum) - let lnum = s:next_list_item(lnum) + return s:get_item(parent_line) +endfunction + + +"Returns: the item above or the item below or an empty item +function! s:get_a_neighbor_item(item) + let prev_item = s:get_prev_list_item(a:item, 1) + if prev_item.type != 0 + return prev_item + else + let next_item = s:get_next_list_item(a:item, 1) + if next_item.type != 0 + return next_item + endif + endif + return s:empty_item() +endfunction + + +function! s:get_a_neighbor_item_in_column(lnum, column) + let cur_ln = s:get_prev_line(a:lnum) + while cur_ln >= 1 + if s:get_level(cur_ln) <= a:column + return s:get_corresponding_item(cur_ln) + endif + let cur_ln = s:get_prev_line(cur_ln) endwhile - - return result -endfunction "}}} + return s:empty_item() +endfunction -" Returns list of line numbers of all items of the same level. -function! s:get_sibling_items(lnum) "{{{ - let result = [] - let lnum = a:lnum - let ind = s:get_level(lnum) - while lnum != 0 && s:get_level(lnum) >= ind - if s:get_level(lnum) == ind && s:is_cb_list_item(lnum) - call add(result, lnum) +"Returns: the item if there is one in a:lnum +"else the multiline item a:lnum belongs to +function! s:get_corresponding_item(lnum) + let item = s:get_item(a:lnum) + if item.type != 0 + return item + endif + let org_lvl = s:get_level(a:lnum) + let cur_ln = a:lnum + while cur_ln > 0 + let cur_lvl = s:get_level(cur_ln) + let cur_item = s:get_item(cur_ln) + if cur_lvl < org_lvl && cur_item.type != 0 + return cur_item endif - let lnum = s:next_list_item(lnum) + if cur_lvl < org_lvl + let org_lvl = cur_lvl + endif + let cur_ln = s:get_prev_line(cur_ln) endwhile + return s:empty_item() +endfunction + - let lnum = s:prev_list_item(a:lnum) - while lnum != 0 && s:get_level(lnum) >= ind - if s:get_level(lnum) == ind && s:is_cb_list_item(lnum) - call add(result, lnum) +"Returns: the last line of a (possibly multiline) item, including all children +function! s:get_last_line_of_item_incl_children(item) + let cur_ln = a:item.lnum + let org_lvl = s:get_level(a:item.lnum) + while 1 + let next_line = s:get_next_line(cur_ln) + if next_line == 0 || s:get_level(next_line) <= org_lvl + return cur_ln endif - let lnum = s:prev_list_item(lnum) + let cur_ln = next_line endwhile - - return result -endfunction "}}} - -" Returns line number of the parent of lnum item -function! s:get_parent_item(lnum) "{{{ - let lnum = a:lnum - let ind = s:get_level(lnum) - - let lnum = s:prev_list_item(lnum) - while lnum != 0 && s:is_list_item(lnum) && s:get_level(lnum) >= ind - let lnum = s:prev_list_item(lnum) +endfunction + + +"Returns: the last line of a (possibly multiline) item +"Note: there can be other list items between the first and last line +function! s:get_last_line_of_item(item) + if a:item.type == 0 | return 0 | endif + let org_lvl = s:get_level(a:item.lnum) + let last_corresponding_line = a:item.lnum + + let cur_ln = s:get_next_line(a:item.lnum) + while 1 + if cur_ln == 0 || s:get_level(cur_ln) <= org_lvl + break + endif + let cur_item = s:get_item(cur_ln) + if cur_item.type == 0 + let last_corresponding_line = cur_ln + let cur_ln = s:get_next_line(cur_ln) + else + let cur_ln = s:get_next_line(s:get_last_line_of_item_incl_children(cur_item)) + endif endwhile - if s:is_cb_list_item(lnum) - return lnum - else - return a:lnum + return last_corresponding_line +endfunction + + +" --------------------------------------------------------- +" renumber list items +" --------------------------------------------------------- + +"Renumbers the current list from a:item on downwards +"Returns: the last item that was adjusted +function! s:adjust_numbered_list_below(item, recursive) + if !(a:item.type == 2 || (a:item.type == 1 && a:recursive)) + return a:item endif -endfunction "}}} -" Creates checkbox in a list item. -function! s:create_cb_list_item(lnum) "{{{ - let line = getline(a:lnum) - let m = matchstr(line, s:rx_list_item()) - if m != '' - let li_content = substitute(strpart(line, len(m)), '^\s*', '', '') - let line = substitute(m, '\s*$', ' ', '').'[ ] '.li_content - call setline(a:lnum, line) + let kind = s:guess_kind_of_numbered_item(a:item) + + let cur_item = a:item + while 1 + if a:recursive + call s:adjust_items_recursively(cur_item) + endif + + let next_item = s:get_next_list_item(cur_item, 0) + if next_item.type == 0 + break + endif + + if cur_item.type == 2 + let new_val = s:increment_{kind}(cur_item.mrkr[:-2]) . cur_item.mrkr[-1:] + call s:substitute_string_in_line(next_item.lnum, next_item.mrkr, new_val) + let next_item.mrkr = new_val + endif + + let cur_item = next_item + endwhile + return cur_item +endfunction + + +function! s:adjust_items_recursively(parent) + if a:parent.type == 0 + return s:empty_item() + end + + let child_item = s:get_first_child(a:parent) + if child_item.type == 0 + return child_item endif -endfunction "}}} + while 1 + let last_item = s:adjust_numbered_list(child_item, 1, 1) + + let child_item = s:get_next_child_item(a:parent, last_item) + if child_item.type == 0 + return last_item + endif + endwhile +endfunction -" Tells if all of the sibling list items are checked or not. -function! s:all_siblings_checked(lnum) "{{{ - let result = 0 - let cnt = 0 - let siblings = s:get_sibling_items(a:lnum) - for lnum in siblings - let cnt += s:get_state(lnum) - endfor - let result = cnt/len(siblings) - return result -endfunction "}}} -" Creates checkbox on a list item if there is no one. -function! s:TLI_create_checkbox(lnum) "{{{ - if a:lnum && !s:is_cb_list_item(a:lnum) - if g:vimwiki_auto_checkbox - call s:create_cb_list_item(a:lnum) +"Renumbers the list a:item is in. +"If a:ignore_kind == 0, only the items which have the same kind of marker as +"a:item are considered, otherwise all items. +"Returns: the last item that was adjusted +function! s:adjust_numbered_list(item, ignore_kind, recursive) + if !(a:item.type == 2 || (a:item.type == 1 && (a:ignore_kind || a:recursive))) + return s:empty_item() + end + + let first_item = s:get_first_item_in_list(a:item, a:ignore_kind) + + while 1 + if first_item.type == 2 + let new_mrkr = s:guess_kind_of_numbered_item(first_item) . first_item.mrkr[-1:] + call s:substitute_string_in_line(first_item.lnum, first_item.mrkr, new_mrkr) + let first_item.mrkr = new_mrkr endif + + let last_item = s:adjust_numbered_list_below(first_item, a:recursive) + + let next_first_item = s:get_next_list_item(last_item, 1) + if a:ignore_kind == 0 || next_first_item.type == 0 + return last_item + endif + let first_item = next_first_item + endwhile +endfunction + + +"Renumbers the list the cursor is in +"also update its parents checkbox state +function! vimwiki#lst#adjust_numbered_list() + let cur_item = s:get_corresponding_item(line('.')) + if cur_item.type == 0 | return | endif + call s:adjust_numbered_list(cur_item, 1, 0) + call s:update_state(s:get_parent(cur_item)) +endfunction + + +"Renumbers all lists of the buffer +"of course, this might take some seconds +function! vimwiki#lst#adjust_whole_buffer() + let cur_ln = 1 + while 1 + let cur_item = s:get_item(cur_ln) + if cur_item.type != 0 + let cur_item = s:adjust_numbered_list(cur_item, 0, 1) + endif + let cur_ln = s:get_next_line(cur_item.lnum, 1) + if cur_ln <= 0 || cur_ln > line('$') + return + endif + endwhile +endfunction + + +" --------------------------------------------------------- +" checkbox stuff +" --------------------------------------------------------- + +"Returns: the rate of checkboxed list item in percent +function! s:get_rate(item) + if a:item.type == 0 || a:item.cb == '' + return -1 + endif + let state = a:item.cb + if state == vimwiki#vars#get_global('listsym_rejected') + return -1 + endif + let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list')) + return index(vimwiki#vars#get_syntaxlocal('listsyms_list'), state) * 100/(n-1) +endfunction + + +"Set state of the list item to [ ] or [o] or whatever +"Returns: 1 if the state changed, 0 otherwise +function! s:set_state(item, new_rate) + let new_state = s:rate_to_state(a:new_rate) + let old_state = s:rate_to_state(s:get_rate(a:item)) + if new_state !=# old_state + call s:substitute_rx_in_line(a:item.lnum, '\[.]', '['.new_state.']') return 1 + else + return 0 endif - return 0 -endfunction "}}} +endfunction -" Switch state of the child list items. -function! s:TLI_switch_child_state(lnum) "{{{ - let current_state = s:get_state(a:lnum) - if current_state == 100 - let new_state = 0 + +" Sets the state of the list item to [ ] or [o] or whatever. Updates the states of its child items. +" If the new state should be [X] or [-], the state of the current list item is changed to this +" state, but if a child item already has [X] or [-] it is left alone. +function! s:set_state_plus_children(item, new_rate, ...) + let retain_state_if_closed = a:0 > 0 && a:1 > 0 + + if !(retain_state_if_closed && (a:new_rate == 100 || a:new_rate == -1) && s:is_closed(a:item)) + call s:set_state(a:item, a:new_rate) + endif + + let all_children_are_done = 1 + let all_children_are_rejected = 1 + + let child_item = s:get_first_child(a:item) + while 1 + if child_item.type == 0 + break + endif + if child_item.cb != vimwiki#vars#get_global('listsym_rejected') + let all_children_are_rejected = 0 + endif + if child_item.cb != vimwiki#vars#get_syntaxlocal('listsyms_list')[-1] + let all_children_are_done = 0 + endif + if !all_children_are_done && !all_children_are_rejected + break + endif + let child_item = s:get_next_child_item(a:item, child_item) + endwhile + + if (a:new_rate == 100 && all_children_are_done) || + \ (a:new_rate == -1) && all_children_are_rejected + return + endif + + if (a:new_rate == -1 && all_children_are_done) || + \ (a:new_rate == 100 && all_children_are_rejected) + let retain_closed_children = 0 else - let new_state = 100 + let retain_closed_children = 1 endif - for lnum in s:get_child_items(a:lnum) - call s:set_state(lnum, new_state) - endfor -endfunction "}}} - -" Switch state of the parent list items. -function! s:TLI_switch_parent_state(lnum) "{{{ - let c_lnum = a:lnum - while s:is_cb_list_item(c_lnum) - let parent_lnum = s:get_parent_item(c_lnum) - if parent_lnum == c_lnum + + let child_item = s:get_first_child(a:item) + while 1 + if child_item.type == 0 break endif - call s:set_state(parent_lnum, s:all_siblings_checked(c_lnum)) + if child_item.cb != '' + call s:set_state_plus_children(child_item, a:new_rate, retain_closed_children) + endif + let child_item = s:get_next_child_item(a:item, child_item) + endwhile +endfunction + + +"Returns: the appropriate symbol for a given percent rate +function! s:rate_to_state(rate) + let listsyms_list = vimwiki#vars#get_syntaxlocal('listsyms_list') + let state = '' + let n = len(listsyms_list) + if a:rate == 100 + let state = listsyms_list[n-1] + elseif a:rate == 0 + let state = listsyms_list[0] + elseif a:rate == -1 + let state = vimwiki#vars#get_global('listsym_rejected') + else + let index = float2nr(ceil(a:rate/100.0*(n-2))) + let state = listsyms_list[index] + endif + return state +endfunction + + +"updates the symbol of a checkboxed item according to the symbols of its +"children +function! s:update_state(item) + if a:item.type == 0 || a:item.cb == '' + return + endif + + let sum_children_rate = 0 + let count_children_with_cb = 0 + let count_rejected_children = 0 - let c_lnum = parent_lnum + let child_item = s:get_first_child(a:item) + + while 1 + if child_item.type == 0 + break + endif + if child_item.cb != '' + let rate = s:get_rate(child_item) + if rate == -1 + " for calculating the parent rate, a [-] item counts as much as a [X] item ... + let rate = 100 + " ... with the exception that a parent with *only* [-] items will be [-] too + let count_rejected_children += 1 + endif + let count_children_with_cb += 1 + let sum_children_rate += rate + endif + let child_item = s:get_next_child_item(a:item, child_item) endwhile -endfunction "}}} -function! s:TLI_toggle(lnum) "{{{ - if !s:TLI_create_checkbox(a:lnum) - call s:TLI_switch_child_state(a:lnum) + if count_children_with_cb > 0 + if count_rejected_children == count_children_with_cb + let new_rate = -1 + else + let new_rate = sum_children_rate / count_children_with_cb + endif + call s:set_state_recursively(a:item, new_rate) + else + let rate = s:get_rate(a:item) + if rate > 0 && rate < 100 + call s:set_state_recursively(a:item, 0) + endif endif - call s:TLI_switch_parent_state(a:lnum) -endfunction "}}} +endfunction -" Script functions }}} -" Toggle list item between [ ] and [X] -function! vimwiki#lst#ToggleListItem(line1, line2) "{{{ - let line1 = a:line1 - let line2 = a:line2 +function! s:set_state_recursively(item, new_rate) + let state_changed = s:set_state(a:item, a:new_rate) + if state_changed + call s:update_state(s:get_parent(a:item)) + endif +endfunction - if line1 != line2 && !s:is_list_item(line1) - let line1 = s:find_next_list_item(line1) + +"Creates checkbox in a list item. +"Returns: 1 if successful +function! s:create_cb(item, start_rate) + if a:item.type == 0 || a:item.cb != '' + return 0 endif - let c_lnum = line1 - while c_lnum != 0 && c_lnum <= line2 - let li_lnum = s:is_list_item(c_lnum) + let new_item = a:item + let new_item.cb = s:rate_to_state(a:start_rate) + call s:substitute_rx_in_line(new_item.lnum, + \ vimwiki#u#escape(new_item.mrkr) . '\zs\ze', ' [' . new_item.cb . ']') + + call s:update_state(new_item) + return 1 +endfunction + - if li_lnum - let li_level = s:get_level(li_lnum) - if c_lnum == line1 - let start_li_level = li_level +function! s:remove_cb(item) + let item = a:item + if item.type != 0 && item.cb != '' + let item.cb = '' + call s:substitute_rx_in_line(item.lnum, '\s\+\[.\]', '') + endif + return item +endfunction + + +" Change state of the checkboxes in the lines of the given range +function! s:change_cb(from_line, to_line, new_rate) + let from_item = s:get_corresponding_item(a:from_line) + if from_item.type == 0 + return + endif + + let parent_items_of_lines = [] + + for cur_ln in range(from_item.lnum, a:to_line) + let cur_item = s:get_item(cur_ln) + if cur_item.type != 0 && cur_item.cb != '' + call s:set_state_plus_children(cur_item, a:new_rate) + let cur_parent_item = s:get_parent(cur_item) + if index(parent_items_of_lines, cur_parent_item) == -1 + call insert(parent_items_of_lines, cur_parent_item) endif + endif + endfor + + for parent_item in parent_items_of_lines + call s:update_state(parent_item) + endfor + +endfunction + + +" Toggles checkbox between two states in the lines of the given range, creates checkboxes (with +" a:start_rate as state) if there aren't any. +function! s:toggle_create_cb(from_line, to_line, state1, state2, start_rate) + let from_item = s:get_corresponding_item(a:from_line) + if from_item.type == 0 + return + endif - if li_level <= start_li_level - call s:TLI_toggle(li_lnum) - let start_li_level = li_level + if from_item.cb == '' + + "if from_line has no CB, make a CB in every selected line + let parent_items_of_lines = [] + for cur_ln in range(from_item.lnum, a:to_line) + let cur_item = s:get_item(cur_ln) + let success = s:create_cb(cur_item, a:start_rate) + + if success + let cur_parent_item = s:get_parent(cur_item) + if index(parent_items_of_lines, cur_parent_item) == -1 + call insert(parent_items_of_lines, cur_parent_item) + endif + endif + endfor + + for parent_item in parent_items_of_lines + call s:update_state(parent_item) + endfor + + else + + "if from_line has CB, toggle it and set all siblings to the same new state + let rate_first_line = s:get_rate(from_item) + let new_rate = rate_first_line == a:state1 ? a:state2 : a:state1 + + call s:change_cb(a:from_line, a:to_line, new_rate) + + endif + +endfunction + + +"Decrement checkbox between [ ] and [X] +"in the lines of the given range +function! vimwiki#lst#decrement_cb(from_line, to_line) + let from_item = s:get_corresponding_item(a:from_line) + if from_item.type == 0 + return + endif + + "if from_line has CB, decrement it and set all siblings to the same new state + let rate_first_line = s:get_rate(from_item) + let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list')) + let new_rate = max([rate_first_line - 100/(n-1)-1, 0]) + + call s:change_cb(a:from_line, a:to_line, new_rate) + +endfunction + + +"Increment checkbox between [ ] and [X] +"in the lines of the given range +function! vimwiki#lst#increment_cb(from_line, to_line) + let from_item = s:get_corresponding_item(a:from_line) + if from_item.type == 0 + return + endif + + "if from_line has CB, increment it and set all siblings to the same new state + let rate_first_line = s:get_rate(from_item) + let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list')) + let new_rate = min([rate_first_line + 100/(n-1)+1, 100]) + + call s:change_cb(a:from_line, a:to_line, new_rate) + +endfunction + + +"Toggles checkbox between [ ] and [X] or creates one +"in the lines of the given range +function! vimwiki#lst#toggle_cb(from_line, to_line) + return s:toggle_create_cb(a:from_line, a:to_line, 100, 0, 0) +endfunction + + +"Toggles checkbox between [ ] and [-] or creates one +"in the lines of the given range +function! vimwiki#lst#toggle_rejected_cb(from_line, to_line) + return s:toggle_create_cb(a:from_line, a:to_line, -1, 0, -1) +endfunction + + +function! vimwiki#lst#remove_cb(first_line, last_line) + let first_item = s:get_corresponding_item(a:first_line) + let last_item = s:get_corresponding_item(a:last_line) + + if first_item.type == 0 || last_item.type == 0 + return + endif + + let parent_items_of_lines = [] + let cur_ln = first_item.lnum + while 1 + if cur_ln <= 0 || cur_ln > last_item.lnum | break | endif + let cur_item = s:get_item(cur_ln) + if cur_item.type != 0 + let cur_item = s:remove_cb(cur_item) + let cur_parent_item = s:get_parent(cur_item) + if index(parent_items_of_lines, cur_parent_item) == -1 + call insert(parent_items_of_lines, cur_parent_item) endif endif + let cur_ln = s:get_next_line(cur_ln) + endwhile + for parent_item in parent_items_of_lines + call s:update_state(parent_item) + endfor +endfunction + - let c_lnum = s:find_next_list_item(c_lnum) +function! vimwiki#lst#remove_cb_in_list() + let first_item = s:get_first_item_in_list(s:get_corresponding_item(line('.')), 0) + + let cur_item = first_item + while 1 + let next_item = s:get_next_list_item(cur_item, 0) + let cur_item = s:remove_cb(cur_item) + if next_item.type == 0 + break + else + let cur_item = next_item + endif endwhile -endfunction "}}} + call s:update_state(s:get_parent(first_item)) +endfunction + + -function! vimwiki#lst#kbd_cr() "{{{ - " This function is heavily relies on proper 'set comments' option. - let cr = "\ " - if getline('.') =~ s:rx_cb_list_item() - let cr .= '[ ] ' +" --------------------------------------------------------- +" change the level of list items +" --------------------------------------------------------- + +function! s:set_indent(lnum, new_indent) + if &expandtab + let indentstring = repeat(' ', a:new_indent) + else + let indentstring = repeat('\t', a:new_indent / &tabstop) . repeat(' ', a:new_indent % &tabstop) endif - return cr -endfunction "}}} + call s:substitute_rx_in_line(a:lnum, '^\s*', indentstring) +endfunction -function! vimwiki#lst#kbd_oO(cmd) "{{{ - " cmd should be 'o' or 'O' - let l:count = v:count1 - while l:count > 0 +function! s:decrease_level(item) + let removed_indent = 0 + if vimwiki#vars#get_syntaxlocal('recurring_bullets') && a:item.type == 1 && + \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), + \ s:first_char(a:item.mrkr)) > -1 + if s:string_length(a:item.mrkr) >= 2 + call s:substitute_string_in_line(a:item.lnum, s:first_char(a:item.mrkr), '') + let removed_indent = -1 + endif + else + let old_indent = indent(a:item.lnum) + if &shiftround + let new_indent = (old_indent - 1) / vimwiki#u#sw() * vimwiki#u#sw() + else + let new_indent = old_indent - vimwiki#u#sw() + endif + call s:set_indent(a:item.lnum, new_indent) + let removed_indent = new_indent - old_indent + endif + return removed_indent +endfunction - let beg_lnum = foldclosed('.') - let end_lnum = foldclosedend('.') - if end_lnum != -1 && a:cmd ==# 'o' - let lnum = end_lnum - let line = getline(beg_lnum) + +function! s:increase_level(item) + let additional_indent = 0 + if vimwiki#vars#get_syntaxlocal('recurring_bullets') && a:item.type == 1 && + \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), + \ s:first_char(a:item.mrkr)) > -1 + call s:substitute_string_in_line(a:item.lnum, a:item.mrkr, a:item.mrkr . + \ s:first_char(a:item.mrkr)) + let additional_indent = 1 + else + let old_indent = indent(a:item.lnum) + if &shiftround + let new_indent = (old_indent / vimwiki#u#sw() + 1) * vimwiki#u#sw() else - let line = getline('.') - let lnum = line('.') + let new_indent = old_indent + vimwiki#u#sw() endif + call s:set_indent(a:item.lnum, new_indent) + let additional_indent = new_indent - old_indent + endif + return additional_indent +endfunction - " let line = substitute(m, '\s*$', ' ', '').'[ ] '.li_content - let m = matchstr(line, s:rx_list_item()) - let res = '' - if line =~ s:rx_cb_list_item() - let res = substitute(m, '\s*$', ' ', '').'[ ] ' - elseif line =~ s:rx_list_item() - let res = substitute(m, '\s*$', ' ', '') - elseif &autoindent || &smartindent - let res = matchstr(line, '^\s*') + +"adds a:indent_by to the current indent +"a:indent_by can be negative +function! s:indent_line_by(lnum, indent_by) + let item = s:get_item(a:lnum) + if vimwiki#vars#get_syntaxlocal('recurring_bullets') && item.type == 1 && + \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), + \ s:first_char(item.mrkr)) > -1 + if a:indent_by > 0 + call s:substitute_string_in_line(a:lnum, item.mrkr, item.mrkr . s:first_char(item.mrkr)) + elseif a:indent_by < 0 + call s:substitute_string_in_line(a:lnum, s:first_char(item.mrkr), '') endif + else + call s:set_indent(a:lnum, indent(a:lnum) + a:indent_by) + endif +endfunction + - if a:cmd ==# 'o' - call append(lnum, res) - call cursor(lnum + 1, col('$')) +"changes lvl of lines in selection +function! s:change_level(from_line, to_line, direction, plus_children) + let from_item = s:get_corresponding_item(a:from_line) + if from_item.type == 0 + if a:direction ==# 'increase' && a:from_line == a:to_line && empty(getline(a:from_line)) + "that's because :> doesn't work on an empty line + normal! gi else - call append(lnum - 1, res) - call cursor(lnum, col('$')) + execute a:from_line.','.a:to_line.(a:direction ==# 'increase' ? '>' : '<') + endif + return + endif + + if a:direction ==# 'decrease' && s:get_level(from_item.lnum) == 0 + return + endif + + if a:from_line == a:to_line + if a:plus_children + let to_line = s:get_last_line_of_item_incl_children(from_item) + else + let to_line = s:get_last_line_of_item(from_item) + endif + else + let to_item = s:get_corresponding_item(a:to_line) + if to_item.type == 0 + let to_line = a:to_line + else + if a:plus_children + let to_line = s:get_last_line_of_item_incl_children(to_item) + else + let to_line = s:get_last_line_of_item(to_item) + endif + endif + endif + + if to_line == 0 + return + endif + + let to_be_adjusted = s:get_a_neighbor_item(from_item) + let old_parent = s:get_parent(from_item) + let first_line_level = s:get_level(from_item.lnum) + let more_than_one_level_concerned = 0 + + let first_line_indented_by = (a:direction ==# 'increase') ? + \ s:increase_level(from_item) : s:decrease_level(from_item) + + let cur_ln = s:get_next_line(from_item.lnum) + while cur_ln > 0 && cur_ln <= to_line + if !more_than_one_level_concerned && + \ s:get_level(cur_ln) != first_line_level && + \ s:get_item(cur_ln).type != 0 + let more_than_one_level_concerned = 1 + endif + call s:indent_line_by(cur_ln, first_line_indented_by) + let cur_ln = s:get_next_line(cur_ln, 1) + endwhile + + if a:from_line == a:to_line + call s:adjust_mrkr(from_item) + endif + call s:update_state(old_parent) + let from_item = s:get_item(from_item.lnum) + if from_item.cb != '' + call s:update_state(from_item) + call s:update_state(s:get_parent(from_item)) + endif + + if more_than_one_level_concerned + call vimwiki#lst#adjust_whole_buffer() + else + call s:adjust_numbered_list(from_item, 0, 0) + call s:adjust_numbered_list(to_be_adjusted, 0, 0) + endif +endfunction + + +function! vimwiki#lst#change_level(from_line, to_line, direction, plus_children) + let cur_col = col('$') - col('.') + call s:change_level(a:from_line, a:to_line, a:direction, a:plus_children) + call cursor('.', col('$') - cur_col) +endfunction + + +"indent line a:lnum to be the continuation of a:prev_item +function! s:indent_multiline(prev_item, lnum) + if a:prev_item.type != 0 + call s:set_indent(a:lnum, s:text_begin(a:prev_item.lnum)) + endif +endfunction + + +" --------------------------------------------------------- +" change markers of list items +" --------------------------------------------------------- + +"Returns: the position of a marker in g:vimwiki_list_markers +function! s:get_idx_list_markers(item) + if a:item.type == 1 + let m = s:first_char(a:item.mrkr) + else + let m = s:guess_kind_of_numbered_item(a:item) . a:item.mrkr[-1:] + endif + return index(vimwiki#vars#get_syntaxlocal('list_markers'), m) +endfunction + + +"changes the marker of the given item to the next in g:vimwiki_list_markers +function! s:get_next_mrkr(item) + let markers = vimwiki#vars#get_syntaxlocal('list_markers') + if a:item.type == 0 + let new_mrkr = markers[0] + else + let idx = s:get_idx_list_markers(a:item) + let new_mrkr = markers[(idx+1) % len(markers)] + endif + return new_mrkr +endfunction + + +"changes the marker of the given item to the previous in g:vimwiki_list_markers +function! s:get_prev_mrkr(item) + let markers = vimwiki#vars#get_syntaxlocal('list_markers') + if a:item.type == 0 + return markers[-1] + endif + let idx = s:get_idx_list_markers(a:item) + if idx == -1 + return markers[-1] + else + return markers[(idx - 1 + len(markers)) % len(markers)] + endif +endfunction + + +function! s:set_new_mrkr(item, new_mrkr) + if a:item.type == 0 + call s:substitute_rx_in_line(a:item.lnum, '^\s*\zs\ze', a:new_mrkr.' ') + if indent(a:item.lnum) == 0 && !vimwiki#vars#get_syntaxlocal('recurring_bullets') + call s:set_indent(a:item.lnum, vimwiki#lst#get_list_margin()) endif + else + call s:substitute_string_in_line(a:item.lnum, a:item.mrkr, a:new_mrkr) + endif +endfunction + + +function! vimwiki#lst#change_marker(from_line, to_line, new_mrkr, mode) + let cur_col_from_eol = col("$") - (a:mode ==# "i" ? col("'^") : col('.')) + let new_mrkr = a:new_mrkr + let cur_ln = a:from_line + while 1 + let cur_item = s:get_item(cur_ln) + + if new_mrkr ==# "next" + let new_mrkr = s:get_next_mrkr(cur_item) + elseif new_mrkr ==# "prev" + let new_mrkr = s:get_prev_mrkr(cur_item) + endif + + "handle markers like *** + if index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(new_mrkr)) > -1 + "use *** if the item above has *** too + let item_above = s:get_prev_list_item(cur_item, 1) + if item_above.type == 1 && s:first_char(item_above.mrkr) ==# s:first_char(new_mrkr) + let new_mrkr = item_above.mrkr + else + "use *** if the item below has *** too + let item_below = s:get_next_list_item(cur_item, 1) + if item_below.type == 1 && s:first_char(item_below.mrkr) ==# s:first_char(new_mrkr) + let new_mrkr = item_below.mrkr + else + "if the old is ### and the new is * use *** + if cur_item.type == 1 && + \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), + \ s:first_char(cur_item.mrkr))>-1 + let new_mrkr = repeat(new_mrkr, s:string_length(cur_item.mrkr)) + else + "use *** if the parent item has ** + let parent_item = s:get_parent(cur_item) + if parent_item.type == 1 && s:first_char(parent_item.mrkr) ==# s:first_char(new_mrkr) + let new_mrkr = repeat(s:first_char(parent_item.mrkr), + \ s:string_length(parent_item.mrkr)+1) + endif + endif + endif + endif + + endif + + call s:set_new_mrkr(cur_item, new_mrkr) + call s:adjust_numbered_list(s:get_item(cur_ln), 1, 0) + + if cur_ln >= a:to_line | break | endif + let cur_ln = s:get_next_line(cur_ln, 1) + endwhile + + call cursor('.', col('$') - cur_col_from_eol) +endfunction - let l:count -= 1 + +function! vimwiki#lst#change_marker_in_list(new_mrkr) + let cur_item = s:get_corresponding_item(line('.')) + let first_item = s:get_first_item_in_list(cur_item, 0) + let last_item = s:get_last_item_in_list(cur_item, 0) + if first_item.type == 0 || last_item.type == 0 | return | endif + let first_item_line = first_item.lnum + + let cur_item = first_item + while cur_item.type != 0 && cur_item.lnum <= last_item.lnum + call s:set_new_mrkr(cur_item, a:new_mrkr) + let cur_item = s:get_next_list_item(cur_item, 1) endwhile + call s:adjust_numbered_list(s:get_item(first_item_line), 0, 0) +endfunction + + +"sets kind of the item depending on neighbor items and the parent item +function! s:adjust_mrkr(item) + if a:item.type == 0 || vimwiki#vars#get_syntaxlocal('recurring_bullets') + return + endif + + let new_mrkr = a:item.mrkr + let neighbor_item = s:get_a_neighbor_item(a:item) + if neighbor_item.type != 0 + let new_mrkr = neighbor_item.mrkr + endif + + "if possible, set e.g. *** if parent has ** as marker + if neighbor_item.type == 0 && a:item.type == 1 && + \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), + \ s:first_char(a:item.mrkr)) > -1 + let parent_item = s:get_parent(a:item) + if parent_item.type == 1 && s:first_char(parent_item.mrkr) ==# s:first_char(a:item.mrkr) + let new_mrkr = repeat(s:first_char(parent_item.mrkr), s:string_length(parent_item.mrkr)+1) + endif + endif + + call s:substitute_string_in_line(a:item.lnum, a:item.mrkr, new_mrkr) + call s:adjust_numbered_list(a:item, 0, 1) +endfunction + + +function! s:clone_marker_from_to(from, to) + let item_from = s:get_item(a:from) + if item_from.type == 0 | return | endif + let new_mrkr = item_from.mrkr . ' ' + call s:substitute_rx_in_line(a:to, '^\s*', new_mrkr) + let new_indent = ( vimwiki#vars#get_syntaxlocal('recurring_bullets') ? 0 : indent(a:from) ) + call s:set_indent(a:to, new_indent) + if item_from.cb != '' + call s:create_cb(s:get_item(a:to), 0) + call s:update_state(s:get_parent(s:get_item(a:to))) + endif + if item_from.type == 2 + let adjust_from = ( a:from < a:to ? a:from : a:to ) + call s:adjust_numbered_list_below(s:get_item(adjust_from), 0) + endif +endfunction + + +function! s:remove_mrkr(item) + let item = a:item + if item.cb != '' + let item = s:remove_cb(item) + let parent_item = s:get_parent(item) + else + let parent_item = s:empty_item() + endif + call s:substitute_rx_in_line(item.lnum, vimwiki#u#escape(item.mrkr).'\s*', '') + call remove(item, 'mrkr') + call remove(item, 'cb') + let item.type = 0 + call s:update_state(parent_item) + return item +endfunction + + +function! s:create_marker(lnum) + let new_sibling = s:get_corresponding_item(a:lnum) + if new_sibling.type == 0 + let new_sibling = s:get_a_neighbor_item_in_column(a:lnum, virtcol('.')) + endif + if new_sibling.type != 0 + call s:clone_marker_from_to(new_sibling.lnum, a:lnum) + else + let cur_item = s:get_item(a:lnum) + call s:set_new_mrkr(cur_item, vimwiki#vars#get_syntaxlocal('list_markers')[0]) + call s:adjust_numbered_list(cur_item, 0, 0) + endif +endfunction + + +" --------------------------------------------------------- +" handle keys +" --------------------------------------------------------- + +function! vimwiki#lst#kbd_o() + let fold_end = foldclosedend('.') + let lnum = (fold_end == -1) ? line('.') : fold_end + let cur_item = s:get_item(lnum) + "inserting and deleting the x is necessary + "because otherwise the indent is lost + normal! ox + if cur_item.lnum < s:get_last_line_of_item(cur_item) + call s:indent_multiline(cur_item, cur_item.lnum+1) + else + call s:clone_marker_from_to(cur_item.lnum, cur_item.lnum+1) + endif startinsert! +endfunction -endfunction "}}} + +function! vimwiki#lst#kbd_O() + normal! Ox + let cur_ln = line('.') + if getline(cur_ln+1) !~# '^\s*$' + call s:clone_marker_from_to(cur_ln+1, cur_ln) + else + call s:clone_marker_from_to(cur_ln-1, cur_ln) + endif + startinsert! +endfunction + + +function! s:cr_on_empty_list_item(lnum, behavior) + if a:behavior == 1 + "just make a new list item + normal! gi + call s:clone_marker_from_to(a:lnum, a:lnum+1) + startinsert! + return + elseif a:behavior == 2 + "insert new marker but remove marker in old line + call append(a:lnum-1, '') + startinsert! + return + elseif a:behavior == 3 + "list is finished, but cursor stays in current line + let item = s:get_item(a:lnum) + let neighbor_item = s:get_a_neighbor_item(item) + let child_item = s:get_first_child(item) + let parent_item = (item.cb != '') ? s:get_parent(item) : s:empty_item() + normal! "_cc + call s:adjust_numbered_list(neighbor_item, 0, 0) + call s:adjust_numbered_list(child_item, 0, 0) + call s:update_state(parent_item) + startinsert + return + elseif a:behavior == 4 + "list is finished, but cursor goes to next line + let item = s:get_item(a:lnum) + let neighbor_item = s:get_a_neighbor_item(item) + let child_item = s:get_first_child(item) + let parent_item = (item.cb != '') ? s:get_parent(item) : s:empty_item() + normal! "_cc + call s:adjust_numbered_list(neighbor_item, 0, 0) + call s:adjust_numbered_list(child_item, 0, 0) + call s:update_state(parent_item) + startinsert + return + elseif a:behavior == 5 + "successively decrease level + if s:get_level(a:lnum) > 0 + call s:change_level(a:lnum, a:lnum, 'decrease', 0) + startinsert! + else + let item = s:get_item(a:lnum) + let neighbor_item = s:get_a_neighbor_item(item) + let child_item = s:get_first_child(item) + let parent_item = (item.cb != '') ? s:get_parent(item) : s:empty_item() + normal! "_cc + call s:adjust_numbered_list(neighbor_item, 0, 0) + call s:adjust_numbered_list(child_item, 0, 0) + call s:update_state(parent_item) + startinsert + endif + return + endif +endfunction + + +function! s:cr_on_empty_line(lnum, behavior) + "inserting and deleting the x is necessary + "because otherwise the indent is lost + normal! gi x + if a:behavior == 2 || a:behavior == 3 + call s:create_marker(a:lnum+1) + endif +endfunction + + +function! s:cr_on_list_item(lnum, insert_new_marker, not_at_eol) + if a:insert_new_marker + "the ultimate feature of this script: make new marker on + normal! gi + call s:clone_marker_from_to(a:lnum, a:lnum+1) + "tiny sweet extra feature: indent next line if current line ends with : + if !a:not_at_eol && getline(a:lnum) =~# ':$' + call s:change_level(a:lnum+1, a:lnum+1, 'increase', 0) + endif + else + " || (cur_item.lnum < s:get_last_line_of_item(cur_item)) + "indent this line so that it becomes the continuation of the line above + normal! gi + let prev_line = s:get_corresponding_item(s:get_prev_line(a:lnum+1)) + call s:indent_multiline(prev_line, a:lnum+1) + endif +endfunction + + +function! vimwiki#lst#kbd_cr(normal, just_mrkr) + let lnum = line('.') + let has_bp = s:line_has_marker(lnum) + + if has_bp != 0 && virtcol('.') < s:text_begin(lnum) + call append(lnum-1, '') + startinsert! + return + endif + + if has_bp == 1 + call s:cr_on_empty_list_item(lnum, a:just_mrkr) + return + endif + + let insert_new_marker = (a:normal == 1 || a:normal == 3) + if getline('.')[col("'^")-1:] =~# '^\s\+$' + let cur_col = 0 + else + let cur_col = col("$") - col("'^") + if getline('.')[col("'^")-1] =~# '\s' && exists("*strdisplaywidth") + let ws_behind_cursor = + \ strdisplaywidth(matchstr(getline('.')[col("'^")-1:], '\s\+'), + \ virtcol("'^")-1) + let cur_col -= ws_behind_cursor + endif + if insert_new_marker && cur_col == 0 && getline(lnum) =~# '\s$' + let insert_new_marker = 0 + endif + endif + + if has_bp == 0 + call s:cr_on_empty_line(lnum, a:normal) + endif + + if has_bp == 2 + call s:cr_on_list_item(lnum, insert_new_marker, cur_col) + endif + + call cursor(lnum+1, col("$") - cur_col) + if cur_col == 0 + startinsert! + else + startinsert + endif + +endfunction + + +"creates a list item in the current line or removes it +function! vimwiki#lst#toggle_list_item() + let cur_col_from_eol = col("$") - col("'^") + let cur_item = s:get_item(line('.')) + + if cur_item.type == 0 + call s:create_marker(cur_item.lnum) + else + let prev_item = s:get_prev_list_item(cur_item, 1) + if prev_item.type == 0 + let prev_item = s:get_corresponding_item(s:get_prev_line(cur_item.lnum)) + endif + let cur_item = s:remove_mrkr(cur_item) + let adjust_prev_item = (prev_item.type == 2 && + \ s:get_level(cur_item.lnum) <= s:get_level(prev_item.lnum)) ? 1 : 0 + call s:indent_multiline(prev_item, cur_item.lnum) + if adjust_prev_item + call s:adjust_numbered_list_below(prev_item, 0) + endif + endif + + "set cursor position s.t. it's on the same char as before + let new_cur_col = col("$") - cur_col_from_eol + call cursor(cur_item.lnum, new_cur_col >= 1 ? new_cur_col : 1) + + if cur_col_from_eol == 0 || getline(cur_item.lnum) =~# '^\s*$' + startinsert! + else + startinsert + endif +endfunction + + +" --------------------------------------------------------- +" misc stuff +" --------------------------------------------------------- + +function! vimwiki#lst#TO_list_item(inner, visual) + let lnum = prevnonblank('.') + let item = s:get_corresponding_item(lnum) + if item.type == 0 + return + endif + let from_line = item.lnum + if a:inner + let to_line = s:get_last_line_of_item(item) + else + let to_line = s:get_last_line_of_item_incl_children(item) + endif + normal! V + call cursor(to_line, 0) + normal! o + call cursor(from_line, 0) +endfunction + + +function! vimwiki#lst#fold_level(lnum) + let cur_item = s:get_item(a:lnum) + if cur_item.type != 0 + let parent_item = s:get_parent(cur_item) + let child_item = s:get_first_child(cur_item) + let next_item = s:get_next_child_item(parent_item, cur_item) + if child_item.type != 0 + return 'a1' + elseif next_item.type == 0 + return 's1' + endif + endif + return '=' +endfunction diff --git a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/markdown_base.vim b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/markdown_base.vim new file mode 100644 index 0000000..f1ce091 --- /dev/null +++ b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/markdown_base.vim @@ -0,0 +1,150 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki autoload plugin file +" Description: Link functions for markdown syntax +" Home: https://github.com/vimwiki/vimwiki/ + + +function! s:safesubstitute(text, search, replace, mode) + " Substitute regexp but do not interpret replace + let escaped = escape(a:replace, '\&') + return substitute(a:text, a:search, escaped, a:mode) +endfunction + + +function! vimwiki#markdown_base#scan_reflinks() + let mkd_refs = {} + " construct list of references using vimgrep + try + " Why noautocmd? Because https://github.com/vimwiki/vimwiki/issues/121 + noautocmd execute 'vimgrep #'.vimwiki#vars#get_syntaxlocal('rxMkdRef').'#j %' + catch /^Vim\%((\a\+)\)\=:E480/ " No Match + "Ignore it, and move on to the next file + endtry + + for d in getqflist() + let matchline = join(getline(d.lnum, min([d.lnum+1, line('$')])), ' ') + let descr = matchstr(matchline, vimwiki#vars#get_syntaxlocal('rxMkdRefMatchDescr')) + let url = matchstr(matchline, vimwiki#vars#get_syntaxlocal('rxMkdRefMatchUrl')) + if descr != '' && url != '' + let mkd_refs[descr] = url + endif + endfor + call vimwiki#vars#set_bufferlocal('markdown_refs', mkd_refs) + return mkd_refs +endfunction + + +" try markdown reference links +function! vimwiki#markdown_base#open_reflink(link) + " echom "vimwiki#markdown_base#open_reflink" + let link = a:link + let mkd_refs = vimwiki#vars#get_bufferlocal('markdown_refs') + if has_key(mkd_refs, link) + let url = mkd_refs[link] + call vimwiki#base#system_open_link(url) + return 1 + else + return 0 + endif +endfunction + + +function! s:normalize_link_syntax_n() + let lnum = line('.') + + " try WikiIncl + let lnk = vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_global('rxWikiIncl')) + if !empty(lnk) + " NO-OP !! + return + endif + + " try WikiLink0: replace with WikiLink1 + let lnk = vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWikiLink0')) + if !empty(lnk) + let sub = vimwiki#base#normalize_link_helper(lnk, + \ vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchUrl'), + \ vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchDescr'), + \ vimwiki#vars#get_syntaxlocal('WikiLink1Template2')) + call vimwiki#base#replacestr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWikiLink0'), sub) + return + endif + + " try WikiLink1: replace with WikiLink0 + let lnk = vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWikiLink1')) + if !empty(lnk) + let sub = vimwiki#base#normalize_link_helper(lnk, + \ vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchUrl'), + \ vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchDescr'), + \ vimwiki#vars#get_global('WikiLinkTemplate2')) + call vimwiki#base#replacestr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWikiLink1'), sub) + return + endif + + " try Weblink + let lnk = vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWeblink')) + if !empty(lnk) + let sub = vimwiki#base#normalize_link_helper(lnk, + \ vimwiki#vars#get_syntaxlocal('rxWeblinkMatchUrl'), + \ vimwiki#vars#get_syntaxlocal('rxWeblinkMatchDescr'), + \ vimwiki#vars#get_syntaxlocal('Weblink1Template')) + call vimwiki#base#replacestr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWeblink'), sub) + return + endif + + " try Word (any characters except separators) + " rxWord is less permissive than rxWikiLinkUrl which is used in + " normalize_link_syntax_v + let lnk = vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_global('rxWord')) + if !empty(lnk) + let sub = vimwiki#base#normalize_link_helper(lnk, + \ vimwiki#vars#get_global('rxWord'), '', + \ vimwiki#vars#get_syntaxlocal('Weblink1Template')) + call vimwiki#base#replacestr_at_cursor('\V'.lnk, sub) + return + endif + +endfunction + + +function! s:normalize_link_syntax_v() + let lnum = line('.') + let sel_save = &selection + let &selection = "old" + let rv = @" + let rt = getregtype('"') + let done = 0 + + try + norm! gvy + let visual_selection = @" + let link = s:safesubstitute(vimwiki#vars#get_syntaxlocal('Weblink1Template'), + \ '__LinkUrl__', visual_selection, '') + let link = s:safesubstitute(link, '__LinkDescription__', visual_selection, '') + + call setreg('"', substitute(link, '\n', '', ''), visualmode()) + + " paste result + norm! `>""pgvd + + finally + call setreg('"', rv, rt) + let &selection = sel_save + endtry + +endfunction + + +function! vimwiki#markdown_base#normalize_link(is_visual_mode) + if 0 + " Syntax-specific links + else + if !a:is_visual_mode + call s:normalize_link_syntax_n() + elseif line("'<") == line("'>") + " action undefined for multi-line visual mode selections + call s:normalize_link_syntax_v() + endif + endif +endfunction + diff --git a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/path.vim b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/path.vim new file mode 100644 index 0000000..367b1d7 --- /dev/null +++ b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/path.vim @@ -0,0 +1,183 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki autoload plugin file +" Description: Path manipulation functions +" Home: https://github.com/vimwiki/vimwiki/ + + +function! vimwiki#path#chomp_slash(str) + return substitute(a:str, '[/\\]\+$', '', '') +endfunction + + +" Define path-compare function, either case-sensitive or not, depending on OS. +if vimwiki#u#is_windows() + function! vimwiki#path#is_equal(p1, p2) + return a:p1 ==? a:p2 + endfunction +else + function! vimwiki#path#is_equal(p1, p2) + return a:p1 ==# a:p2 + endfunction +endif + + +" collapse sections like /a/b/../c to /a/c +function! vimwiki#path#normalize(path) + let path = a:path + while 1 + let result = substitute(path, '/[^/]\+/\.\.', '', '') + if result ==# path + break + endif + let path = result + endwhile + return result +endfunction + + +function! vimwiki#path#path_norm(path) + " /-slashes + if a:path !~# '^scp:' + let path = substitute(a:path, '\', '/', 'g') + " treat multiple consecutive slashes as one path separator + let path = substitute(path, '/\+', '/', 'g') + " ensure that we are not fooled by a symbolic link + return resolve(path) + else + return a:path + endif +endfunction + + +function! vimwiki#path#is_link_to_dir(link) + " Check if link is to a directory. + " It should be ended with \ or /. + return a:link =~# '\m[/\\]$' +endfunction + + +function! vimwiki#path#abs_path_of_link(link) + return vimwiki#path#normalize(expand("%:p:h").'/'.a:link) +endfunction + + +" return longest common path prefix of 2 given paths. +" '~/home/usrname/wiki', '~/home/usrname/wiki/shmiki' => '~/home/usrname/wiki' +function! vimwiki#path#path_common_pfx(path1, path2) + let p1 = split(a:path1, '[/\\]', 1) + let p2 = split(a:path2, '[/\\]', 1) + + let idx = 0 + let minlen = min([len(p1), len(p2)]) + while (idx < minlen) && vimwiki#path#is_equal(p1[idx], p2[idx]) + let idx = idx + 1 + endwhile + if idx == 0 + return '' + else + return join(p1[: idx-1], '/') + endif +endfunction + + +function! vimwiki#path#wikify_path(path) + let result = resolve(fnamemodify(a:path, ':p')) + if vimwiki#u#is_windows() + let result = substitute(result, '\\', '/', 'g') + endif + let result = vimwiki#path#chomp_slash(result) + return result +endfunction + + +function! vimwiki#path#current_wiki_file() + return vimwiki#path#wikify_path(expand('%:p')) +endfunction + + +" Returns: the relative path from a:dir to a:file +function! vimwiki#path#relpath(dir, file) + let result = [] + let dir = split(a:dir, '/') + let file = split(a:file, '/') + while (len(dir) > 0 && len(file) > 0) && vimwiki#path#is_equal(dir[0], file[0]) + call remove(dir, 0) + call remove(file, 0) + endwhile + if empty(dir) && empty(file) + return './' + endif + for segment in dir + let result += ['..'] + endfor + for segment in file + let result += [segment] + endfor + let result_path = join(result, '/') + if a:file =~ '\m/$' + let result_path .= '/' + endif + return result_path +endfunction + + +" If the optional argument provided and nonzero, +" it will ask before creating a directory +" Returns: 1 iff directory exists or successfully created +function! vimwiki#path#mkdir(path, ...) + let path = expand(a:path) + + if path =~# '^scp:' + " we can not do much, so let's pretend everything is ok + return 1 + endif + + if isdirectory(path) + return 1 + else + if !exists("*mkdir") + return 0 + endif + + let path = vimwiki#path#chomp_slash(path) + if vimwiki#u#is_windows() && !empty(vimwiki#vars#get_global('w32_dir_enc')) + let path = iconv(path, &enc, vimwiki#vars#get_global('w32_dir_enc')) + endif + + if a:0 && a:1 && input("Vimwiki: Make new directory: ".path."\n [y]es/[N]o? ") !~? '^y' + return 0 + endif + + call mkdir(path, "p") + return 1 + endif +endfunction + + +function! vimwiki#path#is_absolute(path) + if vimwiki#u#is_windows() + return a:path =~? '\m^\a:' + else + return a:path =~# '\m^/\|\~/' + endif +endfunction + + +" Combine a directory and a file into one path, doesn't generate duplicate +" path separator in case the directory is also having an ending / or \. This +" is because on windows ~\vimwiki//.tags is invalid but ~\vimwiki/.tags is a +" valid path. +if vimwiki#u#is_windows() + function! vimwiki#path#join_path(directory, file) + let directory = vimwiki#path#chomp_slash(a:directory) + let file = substitute(a:file, '\m^[\\/]\+', '', '') + return directory . '/' . file + endfunction +else + function! vimwiki#path#join_path(directory, file) + let directory = substitute(a:directory, '\m/\+$', '', '') + let file = substitute(a:file, '\m^/\+', '', '') + return directory . '/' . file + endfunction +endif + diff --git a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/style.css b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/style.css index f569a40..a5f11b9 100644 --- a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/style.css +++ b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/style.css @@ -24,16 +24,60 @@ del {text-decoration: line-through; color: #777777;} .justright {text-align: right;} .justcenter {text-align: center;} .center {margin-left: auto; margin-right: auto;} +.tag {background-color: #eeeeee; font-family: monospace; padding: 2px;} +.header a {text-decoration: none; color: inherit;} + /* classes for items of todo lists */ -.done0:before {content: "\2592\2592\2592\2592"; color: SkyBlue;} -.done1:before {content: "\2588\2592\2592\2592"; color: SkyBlue;} -.done2:before {content: "\2588\2588\2592\2592"; color: SkyBlue;} -.done3:before {content: "\2588\2588\2588\2592"; color: SkyBlue;} -.done4:before {content: "\2588\2588\2588\2588"; color: SkyBlue;} -/* comment the next four or five lines out * - * if you do not want color-coded todo lists */ -.done0 {color: #c00000;} -.done1 {color: #c08000;} -.done2 {color: #80a000;} -.done3 {color: #00c000;} -.done4 {color: #7f7f7f; text-decoration: line-through;} +.rejected { + /* list-style: none; */ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAAACXBIWXMAAADFAAAAxQEdzbqoAAAAB3RJTUUH4QgEFhAtuWgv9wAAAPZQTFRFmpqam5iYnJaWnJeXnpSUn5OTopCQpoqKpouLp4iIqIiIrYCAt3V1vW1tv2xsmZmZmpeXnpKS/x4e/x8f/yAg/yIi/yQk/yUl/yYm/ygo/ykp/yws/zAw/zIy/zMz/zQ0/zU1/zY2/zw8/0BA/0ZG/0pK/1FR/1JS/1NT/1RU/1VV/1ZW/1dX/1pa/15e/19f/2Zm/2lp/21t/25u/3R0/3p6/4CA/4GB/4SE/4iI/46O/4+P/52d/6am/6ur/66u/7Oz/7S0/7e3/87O/9fX/9zc/93d/+Dg/+vr/+3t/+/v//Dw//Ly//X1//f3//n5//z8////gzaKowAAAA90Uk5T/Pz8/Pz8/Pz8/Pz8/f39ppQKWQAAAAFiS0dEEnu8bAAAAACuSURBVAhbPY9ZF4FQFEZPSKbIMmWep4gMGTKLkIv6/3/GPbfF97b3w17rA0kQOPgvAeHW6uJ6+5h7HqLdwowgOzejXRXBdx6UdSru216xuOMBHHNU0clTzeSUA6EhF8V8kqroluMiU6HKcuf4phGPr1o2q9kYZWwNq1qfRRmTaXpqsyjj17KkWCxKBUBgXWueHIyiAIg18gsse4KHkLF5IKIY10WQgv7fOy4ST34BRiopZ8WLNrgAAAAASUVORK5CYII=); + background-repeat: no-repeat; + background-position: 0 .2em; + padding-left: 1.5em; +} +.done0 { + /* list-style: none; */ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAxQAAAMUBHc26qAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAA7SURBVCiR7dMxEgAgCANBI3yVRzF5KxNbW6wsuH7LQ2YKQK1mkswBVERYF5Os3UV3gwd/jF2SkXy66gAZkxS6BniubAAAAABJRU5ErkJggg==); + background-repeat: no-repeat; + background-position: 0 .2em; + padding-left: 1.5em; +} +.done1 { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAxQAAAMUBHc26qAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABtSURBVCiR1ZO7DYAwDER9BDmTeZQMFXmUbGYpOjrEryA0wOvO8itOslFrJYAug5BMM4BeSkmjsrv3aVTa8p48Xw1JSkSsWVUFwD05IqS1tmYzk5zzae9jnVVVzGyXb8sALjse+euRkEzu/uirFomVIdDGOLjuAAAAAElFTkSuQmCC); + background-repeat: no-repeat; + background-position: 0 .15em; + padding-left: 1.5em; +} +.done2 { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAxQAAAMUBHc26qAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAB1SURBVCiRzdO5DcAgDAVQGxjAYgTvxlDIu1FTIRYAp8qlFISkSH7l5kk+ZIwxKiI2mIyqWoeILYRgZ7GINDOLjnmF3VqklKCUMgTee2DmM661Qs55iI3Zm/1u5h9sm4ig9z4ERHTFzLyd4G4+nFlVrYg8+qoF/c0kdpeMsmcAAAAASUVORK5CYII=); + background-repeat: no-repeat; + background-position: 0 .15em; + padding-left: 1.5em; +} +.done3 { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAxQAAAMUBHc26qAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABoSURBVCiR7dOxDcAgDATA/0DtUdiKoZC3YhLkHjkVKF3idJHiztKfvrHZWnOSE8Fx95RJzlprimJVnXktvXeY2S0SEZRSAAAbmxnGGKH2I5T+8VfxPhIReQSuuY3XyYWa3T2p6quvOgGrvSFGlewuUAAAAABJRU5ErkJggg==); + background-repeat: no-repeat; + background-position: 0 .15em; + padding-left: 1.5em; +} +.done4 { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAzgAAAM4BlP6ToAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIISURBVDiNnZQ9SFtRFMd/773kpTaGJoQk1im4VDpWQcTNODhkFBcVTCNCF0NWyeDiIIiCm82QoIMIUkHUxcFBg1SEQoZszSat6cdTn1qNue92CMbEr9Sey+XC/Z/zu+f8h6ukUil3sVg0+M+4cFxk42/jH2wAqqqKSCSiPQdwcHHAnDHH9s/tN1h8V28ETdP+eU8fT9Nt62ancYdIPvJNtsu87bmjrJlrTDVM4RROJs1JrHPrD4Bar7A6cpc54iKOaTdJXCUI2UMVrQZ0Js7YPN18ECKkYNQcJe/OE/4dZsw7VqNXQMvHy3QZXQypQ6ycrtwDjf8aJ+PNEDSCzLpn7+m2pD8ZKHlKarYhy6XjEoCYGcN95qansQeA3fNdki+SaJZGTMQIOoL3W/Z89rxv+tokubNajlvk/vm+LFpF2XnUKZHI0I+QrI7Dw0OZTqdzUkpsM7mZTyfy5OPGyw1tK7AFSvmB/Ks8w8YwbUYbe6/3QEKv0vugfxWPnMLJun+d/kI/WLdizpNjMbAIKrhMF4OuwadBALqqs+RfInwUvuNi+fBd+wjogfogAFVRmffO02q01mZZ0HHdgXIzdz0QQLPezIQygX6llxNKKgOFARYCC49CqhoHIUTlss/Vx2phlYwjw8j1CAlfAiwQiJpiy7o1VHnsG5FISkoJu7Q/2YmmaV+i0ei7v38L2CBguSi5AAAAAElFTkSuQmCC); + background-repeat: no-repeat; + background-position: 0 .15em; + padding-left: 1.5em; +} + +code { + font-family: Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + padding: 0px 3px; + display: inline-block; + color: #52595d; + border: 1px solid #ccc; + background-color: #f9f9f9; +} diff --git a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/tags.vim b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/tags.vim new file mode 100644 index 0000000..e802bce --- /dev/null +++ b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/tags.vim @@ -0,0 +1,342 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki autoload plugin file + + +let s:TAGS_METADATA_FILE_NAME = '.tags' + + + +" Tags metadata in-memory format: +" metadata := { 'pagename': [entries, ...] } +" entry := { 'tagname':..., 'lineno':..., 'link':... } + +" Tags metadata in-file format: +" +" Is based on CTags format (see |tags-file-format|). +" +" {tagaddress} is set to lineno. We'll let vim search by exact line number; we +" can afford that, we assume metadata file is always updated before use. +" +" Pagename and link are not saved in standard ctags fields, so we'll add +" an optional field, "vimwiki:". In this field, we encode tab-separated values +" of missing parameters -- "pagename" and "link". + + + +" Update tags metadata. +" a:full_rebuild == 1: re-scan entire wiki +" a:full_rebuild == 0: only re-scan current page +" a:all_files == '': only if the file is newer than .tags +function! vimwiki#tags#update_tags(full_rebuild, all_files) + let all_files = a:all_files != '' + if !a:full_rebuild + " Updating for one page (current) + let page_name = vimwiki#vars#get_bufferlocal('subdir') . expand('%:t:r') + " Collect tags in current file + let tags = s:scan_tags(getline(1, '$'), page_name) + " Load metadata file + let metadata = s:load_tags_metadata() + " Drop old tags + let metadata = s:remove_page_from_tags(metadata, page_name) + " Merge in the new ones + let metadata = s:merge_tags(metadata, page_name, tags) + " Save + call s:write_tags_metadata(metadata) + else " full rebuild + let files = vimwiki#base#find_files(vimwiki#vars#get_bufferlocal('wiki_nr'), 0) + let wiki_base_dir = vimwiki#vars#get_wikilocal('path') + let tags_file_last_modification = getftime(vimwiki#tags#metadata_file_path()) + let metadata = s:load_tags_metadata() + for file in files + if all_files || getftime(file) >= tags_file_last_modification + let subdir = vimwiki#base#subdir(wiki_base_dir, file) + let page_name = subdir . fnamemodify(file, ':t:r') + let tags = s:scan_tags(readfile(file), page_name) + let metadata = s:remove_page_from_tags(metadata, page_name) + let metadata = s:merge_tags(metadata, page_name, tags) + endif + endfor + call s:write_tags_metadata(metadata) + endif +endfunction + + +" Scans the list of text lines (argument) and produces tags metadata as a list of tag entries. +function! s:scan_tags(lines, page_name) + + let entries = [] + + " Code wireframe to scan for headers -- borrowed from + " vimwiki#base#get_anchors(), with minor modifications. + + let rxheader = vimwiki#vars#get_syntaxlocal('header_search') + let rxtag = vimwiki#vars#get_syntaxlocal('tag_search') + + let anchor_level = ['', '', '', '', '', '', ''] + let current_complete_anchor = '' + + let PROXIMITY_LINES_NR = 2 + let header_line_nr = - (2 * PROXIMITY_LINES_NR) + + for line_nr in range(1, len(a:lines)) + let line = a:lines[line_nr - 1] + + " process headers + let h_match = matchlist(line, rxheader) + if !empty(h_match) " got a header + let header_line_nr = line_nr + let header = vimwiki#u#trim(h_match[2]) + let level = len(h_match[1]) + let anchor_level[level-1] = header + for l in range(level, 6) + let anchor_level[l] = '' + endfor + if level == 1 + let current_complete_anchor = header + else + let current_complete_anchor = '' + for l in range(level-1) + if anchor_level[l] != '' + let current_complete_anchor .= anchor_level[l].'#' + endif + endfor + let current_complete_anchor .= header + endif + continue " tags are not allowed in headers + endif + + " TODO ignore verbatim blocks + + " Scan line for tags. There can be many of them. + let str = line + while 1 + let tag_group = matchstr(str, rxtag) + if tag_group == '' + break + endif + let tagend = matchend(str, rxtag) + let str = str[(tagend):] + for tag in split(tag_group, ':') + " Create metadata entry + let entry = {} + let entry.tagname = tag + let entry.lineno = line_nr + if line_nr <= PROXIMITY_LINES_NR && header_line_nr < 0 + " Tag appeared at the top of the file + let entry.link = a:page_name + elseif line_nr <= (header_line_nr + PROXIMITY_LINES_NR) + " Tag appeared right below a header + let entry.link = a:page_name . '#' . current_complete_anchor + else + " Tag stands on its own + let entry.link = a:page_name . '#' . tag + endif + call add(entries, entry) + endfor + endwhile + + endfor " loop over lines + return entries +endfunction + + +" Returns tags metadata file path +function! vimwiki#tags#metadata_file_path() abort + return fnamemodify(vimwiki#path#join_path(vimwiki#vars#get_wikilocal('path'), + \ s:TAGS_METADATA_FILE_NAME), ':p') +endfunction + + +" Loads tags metadata from file, returns a dictionary +function! s:load_tags_metadata() abort + let metadata_path = vimwiki#tags#metadata_file_path() + if !filereadable(metadata_path) + return {} + endif + let metadata = {} + for line in readfile(metadata_path) + if line =~ '^!_TAG_FILE_' + continue + endif + let parts = matchlist(line, '^\(.\{-}\);"\(.*\)$') + if parts[0] == '' || parts[1] == '' || parts[2] == '' + throw 'VimwikiTags1: Metadata file corrupted' + endif + let std_fields = split(parts[1], '\t') + if len(std_fields) != 3 + throw 'VimwikiTags2: Metadata file corrupted' + endif + let vw_part = parts[2] + if vw_part[0] != "\t" + throw 'VimwikiTags3: Metadata file corrupted' + endif + let vw_fields = split(vw_part[1:], "\t") + if len(vw_fields) != 1 || vw_fields[0] !~ '^vimwiki:' + throw 'VimwikiTags4: Metadata file corrupted' + endif + let vw_data = substitute(vw_fields[0], '^vimwiki:', '', '') + let vw_data = substitute(vw_data, '\\n', "\n", 'g') + let vw_data = substitute(vw_data, '\\r', "\r", 'g') + let vw_data = substitute(vw_data, '\\t', "\t", 'g') + let vw_data = substitute(vw_data, '\\\\', "\\", 'g') + let vw_fields = split(vw_data, "\t") + if len(vw_fields) != 2 + throw 'VimwikiTags5: Metadata file corrupted' + endif + let pagename = vw_fields[0] + let entry = {} + let entry.tagname = std_fields[0] + let entry.lineno = std_fields[2] + let entry.link = vw_fields[1] + if has_key(metadata, pagename) + call add(metadata[pagename], entry) + else + let metadata[pagename] = [entry] + endif + endfor + return metadata +endfunction + + +" Removes all entries for given page from metadata in-place. Returns updated +" metadata (just in case). +function! s:remove_page_from_tags(metadata, page_name) + if has_key(a:metadata, a:page_name) + call remove(a:metadata, a:page_name) + return a:metadata + else + return a:metadata + endif +endfunction + + +" Merges metadata of one file into a:metadata +function! s:merge_tags(metadata, pagename, file_metadata) + let metadata = a:metadata + let metadata[a:pagename] = a:file_metadata + return metadata +endfunction + + +" Compares two actual lines from tags file. Return value is in strcmp style. +" See help on sort() -- that's what this function is going to be used for. +" See also s:write_tags_metadata below -- that's where we compose these tags +" file lines. +" +" This function is needed for tags sorting, since plain sort() compares line +" numbers as strings, not integers, and so, for example, tag at line 14 +" preceeds the same tag on the same page at line 9. (Because string "14" is +" alphabetically 'less than' string "9".) +function! s:tags_entry_cmp(i1, i2) + let items = [] + for orig_item in [a:i1, a:i2] + let fields = split(orig_item, "\t") + let item = {} + let item.text = fields[0]."\t".fields[1] + let item.lineno = 0 + matchstr(fields[2], '\m\d\+') + call add(items, item) + endfor + if items[0].text ># items[1].text + return 1 + elseif items[0].text <# items[1].text + return -1 + elseif items[0].lineno > items[1].lineno + return 1 + elseif items[0].lineno < items[1].lineno + return -1 + else + return 0 + endif +endfunction + + +" Saves metadata object into a file. Throws exceptions in case of problems. +function! s:write_tags_metadata(metadata) + let metadata_path = vimwiki#tags#metadata_file_path() + let tags = [] + for pagename in keys(a:metadata) + for entry in a:metadata[pagename] + let entry_data = pagename . "\t" . entry.link + let entry_data = substitute(entry_data, "\\", '\\\\', 'g') + let entry_data = substitute(entry_data, "\t", '\\t', 'g') + let entry_data = substitute(entry_data, "\r", '\\r', 'g') + let entry_data = substitute(entry_data, "\n", '\\n', 'g') + call add(tags, + \ entry.tagname . "\t" + \ . pagename . vimwiki#vars#get_wikilocal('ext') . "\t" + \ . entry.lineno + \ . ';"' + \ . "\t" . "vimwiki:" . entry_data + \) + endfor + endfor + call sort(tags, "s:tags_entry_cmp") + call insert(tags, "!_TAG_FILE_SORTED\t1\t") + call writefile(tags, metadata_path) +endfunction + + +" Returns list of unique tags found in the .tags file +function! vimwiki#tags#get_tags() + let metadata = s:load_tags_metadata() + let tags = {} + for entries in values(metadata) + for entry in entries + let tags[entry.tagname] = 1 + endfor + endfor + return keys(tags) +endfunction + + +" Similar to vimwiki#base#generate_links. In the current buffer, appends +" tags and references to all their instances. If no arguments (tags) are +" specified, outputs all tags. +function! vimwiki#tags#generate_tags(...) abort + let need_all_tags = (a:0 == 0) + let specific_tags = a:000 + + let metadata = s:load_tags_metadata() + + " make a dictionary { tag_name: [tag_links, ...] } + let tags_entries = {} + for entries in values(metadata) + for entry in entries + if has_key(tags_entries, entry.tagname) + call add(tags_entries[entry.tagname], entry.link) + else + let tags_entries[entry.tagname] = [entry.link] + endif + endfor + endfor + + let lines = [] + let bullet = repeat(' ', vimwiki#lst#get_list_margin()).vimwiki#lst#default_symbol().' ' + for tagname in sort(keys(tags_entries)) + if need_all_tags || index(specific_tags, tagname) != -1 + call extend(lines, [ + \ '', + \ substitute(vimwiki#vars#get_syntaxlocal('rxH2_Template'), '__Header__', tagname, ''), + \ '' ]) + for taglink in sort(tags_entries[tagname]) + call add(lines, bullet . substitute(vimwiki#vars#get_global('WikiLinkTemplate1'), + \ '__LinkUrl__', taglink, '')) + endfor + endif + endfor + + let links_rx = '\m\%(^\s*$\)\|\%('.vimwiki#vars#get_syntaxlocal('rxH2').'\)\|\%(^\s*' + \ .vimwiki#u#escape(vimwiki#lst#default_symbol()).' ' + \ .vimwiki#vars#get_syntaxlocal('rxWikiLink').'$\)' + + call vimwiki#base#update_listing_in_buffer(lines, 'Generated Tags', links_rx, line('$')+1, 1) +endfunction + + +function! vimwiki#tags#complete_tags(ArgLead, CmdLine, CursorPos) abort + " We can safely ignore args if we use -custom=complete option, Vim engine + " will do the job of filtering. + let taglist = vimwiki#tags#get_tags() + return join(taglist, "\n") +endfunction + diff --git a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/tbl.vim b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/tbl.vim index 77d5397..1c049ce 100644 --- a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/tbl.vim +++ b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/tbl.vim @@ -1,31 +1,36 @@ -" vim:tabstop=2:shiftwidth=2:expandtab:foldmethod=marker:textwidth=79 +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 " Vimwiki autoload plugin file -" Desc: Tables +" Description: Tables " | Easily | manageable | text | tables | ! | -" |--------+------------+-------+--------+---------| +" |--------|------------|-------|--------|---------| " | Have | fun! | Drink | tea | Period. | " -" Author: Maxim Kim -" Home: http://code.google.com/p/vimwiki/ +" Home: https://github.com/vimwiki/vimwiki/ + + -" Load only once {{{ if exists("g:loaded_vimwiki_tbl_auto") || &cp finish endif let g:loaded_vimwiki_tbl_auto = 1 -"}}} + let s:textwidth = &tw -" Misc functions {{{ -function! s:wide_len(str) "{{{ + +function! s:rxSep() + return vimwiki#vars#get_syntaxlocal('rxTableSep') +endfunction + + +function! s:wide_len(str) " vim73 has new function that gives correct string width. if exists("*strdisplaywidth") return strdisplaywidth(a:str) endif " get str display width in vim ver < 7.2 - if !g:vimwiki_CJK_length + if !vimwiki#vars#get_global('CJK_length') let ret = strlen(substitute(a:str, '.', 'x', 'g')) else let savemodified = &modified @@ -38,26 +43,49 @@ function! s:wide_len(str) "{{{ let &modified = savemodified endif return ret -endfunction "}}} +endfunction + + +function! s:cell_splitter() + return '\s*'.s:rxSep().'\s*' +endfunction + + +function! s:sep_splitter() + return '-'.s:rxSep().'-' +endfunction + + +function! s:is_table(line) + return s:is_separator(a:line) || + \ (a:line !~# s:rxSep().s:rxSep() && a:line =~# '^\s*'.s:rxSep().'.\+'.s:rxSep().'\s*$') +endfunction + + +function! s:is_separator(line) + return a:line =~# '^\s*'.s:rxSep().'\(--\+'.s:rxSep().'\)\+\s*$' +endfunction + -function! s:is_table(line) "{{{ - return a:line =~ '^\s*\%(|[^|]\+\)\+|\s*$' || s:is_separator(a:line) -endfunction "}}} +function! s:is_separator_tail(line) + return a:line =~# '^\{-1}\%(\s*\|-*\)\%('.s:rxSep().'-\+\)\+'.s:rxSep().'\s*$' +endfunction -function! s:is_separator(line) "{{{ - return a:line =~ '^\s*[|+]\s*--[-|+]\+' -endfunction "}}} -function! s:is_last_column(lnum, cnum) "{{{ - return strpart(getline(a:lnum), a:cnum - 1) =~ '^[^|]*|\s*$' -endfunction "}}} +function! s:is_last_column(lnum, cnum) + let line = strpart(getline(a:lnum), a:cnum - 1) + return line =~# s:rxSep().'\s*$' && line !~# s:rxSep().'.*'.s:rxSep().'\s*$' +endfunction -function! s:is_first_column(lnum, cnum) "{{{ + +function! s:is_first_column(lnum, cnum) let line = strpart(getline(a:lnum), 0, a:cnum - 1) - return line =~ '^\s*|[^|]*$' || line =~ '^\s*$' -endfunction "}}} + return line =~# '^\s*$' || + \ (line =~# '^\s*'.s:rxSep() && line !~# '^\s*'.s:rxSep().'.*'.s:rxSep()) +endfunction + -function! s:count_separators_up(lnum) "{{{ +function! s:count_separators_up(lnum) let lnum = a:lnum - 1 while lnum > 1 if !s:is_separator(getline(lnum)) @@ -67,9 +95,10 @@ function! s:count_separators_up(lnum) "{{{ endwhile return (a:lnum-lnum) -endfunction "}}} +endfunction -function! s:count_separators_down(lnum) "{{{ + +function! s:count_separators_down(lnum) let lnum = a:lnum + 1 while lnum < line('$') if !s:is_separator(getline(lnum)) @@ -79,54 +108,93 @@ function! s:count_separators_down(lnum) "{{{ endwhile return (lnum-a:lnum) -endfunction "}}} +endfunction + -function! s:create_empty_row(cols) "{{{ - let first_cell = "| |" - let cell = " |" - let row = first_cell +function! s:create_empty_row(cols) + let row = s:rxSep() + let cell = " ".s:rxSep() - for c in range(a:cols - 1) + for c in range(a:cols) let row .= cell endfor return row -endfunction "}}} +endfunction -function! s:create_row_sep(cols) "{{{ - let first_cell = "|---+" - let cell = "---+" - let last_cell = "---|" - if a:cols < 2 - return "|---|" - endif - - let row = first_cell +function! s:create_row_sep(cols) + let row = s:rxSep() + let cell = "---".s:rxSep() - for c in range(a:cols - 2) + for c in range(a:cols) let row .= cell endfor - let row .= last_cell - return row -endfunction "}}} - -function! s:get_values(line) "{{{ - return split(a:line, '\s*|\s*', 1)[1:-2] -endfunction "}}} +endfunction + + +function! vimwiki#tbl#get_cells(line) + let result = [] + let cell = '' + let quote = '' + let state = 'NONE' + + " 'Simple' FSM + for idx in range(strlen(a:line)) + " The only way I know Vim can do Unicode... + let ch = a:line[idx] + if state ==# 'NONE' + if ch == '|' + let state = 'CELL' + endif + elseif state ==# 'CELL' + if ch == '[' || ch == '{' + let state = 'BEFORE_QUOTE_START' + let quote = ch + elseif ch == '|' + call add(result, vimwiki#u#trim(cell)) + let cell = "" + else + let cell .= ch + endif + elseif state ==# 'BEFORE_QUOTE_START' + if ch == '[' || ch == '{' + let state = 'QUOTE' + let quote .= ch + else + let state = 'CELL' + let cell .= quote.ch + let quote = '' + endif + elseif state ==# 'QUOTE' + if ch == ']' || ch == '}' + let state = 'BEFORE_QUOTE_END' + endif + let quote .= ch + elseif state ==# 'BEFORE_QUOTE_END' + if ch == ']' || ch == '}' + let state = 'CELL' + endif + let cell .= quote.ch + let quote = '' + endif + endfor -function! s:col_count(lnum) "{{{ - let line = getline(a:lnum) - if !s:is_separator(line) - return len(split(line, '\s*|\s*', 1)[1:-2]) - else - return len(split(line, '-+-', 1)) + if cell.quote != '' + call add(result, vimwiki#u#trim(cell.quote, '|')) endif -endfunction "}}} + return result +endfunction -function! s:get_indent(lnum) "{{{ + +function! s:col_count(lnum) + return len(vimwiki#tbl#get_cells(getline(a:lnum))) +endfunction + + +function! s:get_indent(lnum) if !s:is_table(getline(a:lnum)) return endif @@ -144,9 +212,10 @@ function! s:get_indent(lnum) "{{{ endwhile return indent -endfunction " }}} +endfunction + -function! s:get_rows(lnum) "{{{ +function! s:get_rows(lnum) if !s:is_table(getline(a:lnum)) return endif @@ -155,7 +224,7 @@ function! s:get_rows(lnum) "{{{ let lower_rows = [] let lnum = a:lnum - 1 - while lnum > 1 + while lnum >= 1 let line = getline(lnum) if s:is_table(line) call add(upper_rows, [lnum, line]) @@ -178,15 +247,16 @@ function! s:get_rows(lnum) "{{{ endwhile return upper_rows + lower_rows -endfunction "}}} +endfunction + -function! s:get_cell_max_lens(lnum) "{{{ +function! s:get_cell_max_lens(lnum, ...) let max_lens = {} for [lnum, row] in s:get_rows(a:lnum) if s:is_separator(row) continue endif - let cells = s:get_values(row) + let cells = a:0 > 1 ? a:1[lnum - a:2] : vimwiki#tbl#get_cells(row) for idx in range(len(cells)) let value = cells[idx] if has_key(max_lens, idx) @@ -197,50 +267,52 @@ function! s:get_cell_max_lens(lnum) "{{{ endfor endfor return max_lens -endfunction "}}} +endfunction -function! s:get_aligned_rows(lnum, col1, col2) "{{{ - let max_lens = s:get_cell_max_lens(a:lnum) - let rows = [] - for [lnum, row] in s:get_rows(a:lnum) + +function! s:get_aligned_rows(lnum, col1, col2) + let rows = s:get_rows(a:lnum) + let startlnum = rows[0][0] + let cells = [] + for [lnum, row] in rows + call add(cells, vimwiki#tbl#get_cells(row)) + endfor + let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum) + let result = [] + for [lnum, row] in rows if s:is_separator(row) let new_row = s:fmt_sep(max_lens, a:col1, a:col2) else - let new_row = s:fmt_row(row, max_lens, a:col1, a:col2) + let new_row = s:fmt_row(cells[lnum - startlnum], max_lens, a:col1, a:col2) endif - call add(rows, [lnum, new_row]) + call add(result, [lnum, new_row]) endfor - return rows -endfunction "}}} + return result +endfunction + " Number of the current column. Starts from 0. -function! s:cur_column() "{{{ +function! s:cur_column() let line = getline('.') if !s:is_table(line) return -1 endif - if s:is_separator(line) - let sep = '[+|]' - else - let sep = '|' - endif + " TODO: do we need conditional: if s:is_separator(line) let curs_pos = col('.') - let mpos = match(line, '|', 0) + let mpos = match(line, s:rxSep(), 0) let col = -1 while mpos < curs_pos && mpos != -1 - let mpos = match(line, sep, mpos+1) + let mpos = match(line, s:rxSep(), mpos+1) if mpos != -1 let col += 1 endif endwhile return col -endfunction "}}} +endfunction -" }}} -" Format functions {{{ -function! s:fmt_cell(cell, max_len) "{{{ +function! s:fmt_cell(cell, max_len) let cell = ' '.a:cell.' ' let diff = a:max_len - s:wide_len(a:cell) @@ -250,139 +322,205 @@ function! s:fmt_cell(cell, max_len) "{{{ let cell .= repeat(' ', diff) return cell -endfunction "}}} +endfunction + -function! s:fmt_row(line, max_lens, col1, col2) "{{{ - let new_line = '|' - let cells = s:get_values(a:line) - for idx in range(len(cells)) +function! s:fmt_row(cells, max_lens, col1, col2) + let new_line = s:rxSep() + for idx in range(len(a:cells)) if idx == a:col1 let idx = a:col2 elseif idx == a:col2 let idx = a:col1 endif - let value = cells[idx] - let new_line .= s:fmt_cell(value, a:max_lens[idx]).'|' + let value = a:cells[idx] + let new_line .= s:fmt_cell(value, a:max_lens[idx]).s:rxSep() endfor - let idx = len(cells) + let idx = len(a:cells) while idx < len(a:max_lens) - let new_line .= s:fmt_cell('', a:max_lens[idx]).'|' + let new_line .= s:fmt_cell('', a:max_lens[idx]).s:rxSep() let idx += 1 endwhile return new_line -endfunction "}}} +endfunction -function! s:fmt_cell_sep(max_len) "{{{ + +function! s:fmt_cell_sep(max_len) if a:max_len == 0 return repeat('-', 3) else return repeat('-', a:max_len+2) endif -endfunction "}}} +endfunction + -function! s:fmt_sep(max_lens, col1, col2) "{{{ - let sep = '|' +function! s:fmt_sep(max_lens, col1, col2) + let new_line = s:rxSep() for idx in range(len(a:max_lens)) if idx == a:col1 let idx = a:col2 elseif idx == a:col2 let idx = a:col1 endif - let sep .= s:fmt_cell_sep(a:max_lens[idx]).'+' + let new_line .= s:fmt_cell_sep(a:max_lens[idx]).s:rxSep() endfor - let sep = substitute(sep, '+$', '|', '') - return sep -endfunction "}}} -"}}} + return new_line +endfunction + -" Keyboard functions "{{{ -function! s:kbd_create_new_row(cols, goto_first) "{{{ +function! s:kbd_create_new_row(cols, goto_first) let cmd = "\ o".s:create_empty_row(a:cols) let cmd .= "\ :call vimwiki#tbl#format(line('.'))\ " + let cmd .= "\ 0" if a:goto_first - let cmd .= "\ 0:call search('|', 'c', line('.'))\ la" + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'c', line('.'))\ " else - let cmd .= "0".(col('.')-1)."lT|a" + let cmd .= (col('.')-1)."l" + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\ " endif + let cmd .= "a" + return cmd -endfunction "}}} +endfunction -function! s:kbd_goto_next_row() "{{{ - let cmd = "\ jt|T|a" + +function! s:kbd_goto_next_row() + let cmd = "\ j" + let cmd .= ":call search('.\\(".s:rxSep()."\\)', 'c', line('.'))\ " + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\ " + let cmd .= "a" return cmd -endfunction "}}} +endfunction + -function! s:kbd_goto_prev_row() "{{{ - let cmd = "\ jt|T|a" +function! s:kbd_goto_prev_row() + let cmd = "\ k" + let cmd .= ":call search('.\\(".s:rxSep()."\\)', 'c', line('.'))\ " + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\ " + let cmd .= "a" return cmd -endfunction "}}} +endfunction + + +" Used in s:kbd_goto_next_col +function! vimwiki#tbl#goto_next_col() + let curcol = virtcol('.') + let lnum = line('.') + let newcol = s:get_indent(lnum) + let max_lens = s:get_cell_max_lens(lnum) + for cell_len in values(max_lens) + if newcol >= curcol-1 + break + endif + let newcol += cell_len + 3 " +3 == 2 spaces + 1 separator | ... + endfor + let newcol += 2 " +2 == 1 separator + 1 space | la" - else - let cmd = "\ :call search('|', 'c', line('.'))\ la" + let cmd .= seps."j0" endif + let cmd .= ":call vimwiki#tbl#goto_next_col()\ a" return cmd -endfunction "}}} +endfunction + -function! s:kbd_goto_prev_col(first) "{{{ - if a:first +" Used in s:kbd_goto_prev_col +function! vimwiki#tbl#goto_prev_col() + let curcol = virtcol('.') + let lnum = line('.') + let newcol = s:get_indent(lnum) + let max_lens = s:get_cell_max_lens(lnum) + let prev_cell_len = 0 + for cell_len in values(max_lens) + let delta = cell_len + 3 " +3 == 2 spaces + 1 separator | ... + if newcol + delta > curcol-1 + let newcol -= (prev_cell_len + 3) " +3 == 2 spaces + 1 separator | ... + break + elseif newcol + delta == curcol-1 + break + endif + let prev_cell_len = cell_len + let newcol += delta + endfor + let newcol += 2 " +2 == 1 separator + 1 space | la" - else - let cmd = "\ 2F|la" + let cmd .= seps."k" + let cmd .= "$" endif + let cmd .= ":call vimwiki#tbl#goto_prev_col()\ a" + " let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'b', line('.'))\ " + " let cmd .= "a" + "echomsg "DEBUG kbd_goto_prev_col> ".cmd return cmd -endfunction "}}} +endfunction -"}}} -" Global functions {{{ -function! vimwiki#tbl#kbd_cr() "{{{ +function! vimwiki#tbl#kbd_cr() let lnum = line('.') if !s:is_table(getline(lnum)) - return "\ " + return "" endif if s:is_separator(getline(lnum+1)) || !s:is_table(getline(lnum+1)) - let cols = len(s:get_values(getline(lnum))) + let cols = len(vimwiki#tbl#get_cells(getline(lnum))) return s:kbd_create_new_row(cols, 0) else return s:kbd_goto_next_row() endif -endfunction "}}} +endfunction + -function! vimwiki#tbl#kbd_tab() "{{{ +function! vimwiki#tbl#kbd_tab() let lnum = line('.') if !s:is_table(getline(lnum)) return "\ " endif let last = s:is_last_column(lnum, col('.')) - if last && !s:is_table(getline(lnum+1)) - let cols = len(s:get_values(getline(lnum))) + let is_sep = s:is_separator_tail(getline(lnum)) + "echomsg "DEBUG kbd_tab> last=".last.", is_sep=".is_sep + if (is_sep || last) && !s:is_table(getline(lnum+1)) + let cols = len(vimwiki#tbl#get_cells(getline(lnum))) return s:kbd_create_new_row(cols, 1) endif - return s:kbd_goto_next_col(last) -endfunction "}}} + return s:kbd_goto_next_col(is_sep || last) +endfunction + -function! vimwiki#tbl#kbd_shift_tab() "{{{ +function! vimwiki#tbl#kbd_shift_tab() let lnum = line('.') if !s:is_table(getline(lnum)) return "\ " endif let first = s:is_first_column(lnum, col('.')) - if first && !s:is_table(getline(lnum-1)) + let is_sep = s:is_separator_tail(getline(lnum)) + "echomsg "DEBUG kbd_tab> ".first + if (is_sep || first) && !s:is_table(getline(lnum-1)) return "" endif - return s:kbd_goto_prev_col(first) -endfunction "}}} + return s:kbd_goto_prev_col(is_sep || first) +endfunction -function! vimwiki#tbl#format(lnum, ...) "{{{ + +function! vimwiki#tbl#format(lnum, ...) + if !(&filetype ==? 'vimwiki') + return + endif let line = getline(a:lnum) if !s:is_table(line) return @@ -397,16 +535,22 @@ function! vimwiki#tbl#format(lnum, ...) "{{{ endif let indent = s:get_indent(a:lnum) + if &expandtab + let indentstring = repeat(' ', indent) + else + let indentstring = repeat(' ', indent / &tabstop) . repeat(' ', indent % &tabstop) + endif for [lnum, row] in s:get_aligned_rows(a:lnum, col1, col2) - let row = repeat(' ', indent).row + let row = indentstring.row call setline(lnum, row) endfor - + let &tw = s:textwidth -endfunction "}}} +endfunction -function! vimwiki#tbl#create(...) "{{{ + +function! vimwiki#tbl#create(...) if a:0 > 1 let cols = a:1 let rows = a:2 @@ -437,32 +581,42 @@ function! vimwiki#tbl#create(...) "{{{ for r in range(rows - 1) call add(lines, row) endfor - + call append(line('.'), lines) -endfunction "}}} +endfunction -function! vimwiki#tbl#align_or_cmd(cmd) "{{{ + +function! vimwiki#tbl#align_or_cmd(cmd) if s:is_table(getline('.')) call vimwiki#tbl#format(line('.')) else exe 'normal! '.a:cmd endif -endfunction "}}} +endfunction + -function! vimwiki#tbl#reset_tw(lnum) "{{{ +function! vimwiki#tbl#reset_tw(lnum) + if !(&filetype ==? 'vimwiki') + return + endif let line = getline(a:lnum) if !s:is_table(line) return endif - + let s:textwidth = &tw let &tw = 0 -endfunction "}}} +endfunction + + +" TODO: move_column_left and move_column_right are good candidates to be refactored. +function! vimwiki#tbl#move_column_left() -" TODO: move_column_left and move_column_right are good candidates to be -" refactored. -function! vimwiki#tbl#move_column_left() "{{{ - if !s:is_table(getline('.')) + "echomsg "DEBUG move_column_left: " + + let line = getline('.') + + if !s:is_table(line) return endif @@ -472,18 +626,30 @@ function! vimwiki#tbl#move_column_left() "{{{ endif if cur_col > 0 - call vimwiki#tbl#format(line('.'), cur_col-1, cur_col) + call vimwiki#tbl#format(line('.'), cur_col-1, cur_col) call cursor(line('.'), 1) - if !s:is_separator(getline('.')) - call search('\%(|[^|]\+\)\{'.(cur_col-1).'}| .', 'eW') - else - call search('|\%([^+]\++\)\{'.(cur_col-1).'}--', 'eW') - endif + + let sep = '\('.s:rxSep().'\).\zs' + let mpos = -1 + let col = -1 + while col < cur_col-1 + let mpos = match(line, sep, mpos+1) + if mpos != -1 + let col += 1 + else + break + endif + endwhile + endif -endfunction "}}} +endfunction + + +function! vimwiki#tbl#move_column_right() -function! vimwiki#tbl#move_column_right() "{{{ - if !s:is_table(getline('.')) + let line = getline('.') + + if !s:is_table(line) return endif @@ -493,18 +659,45 @@ function! vimwiki#tbl#move_column_right() "{{{ endif if cur_col < s:col_count(line('.'))-1 - call vimwiki#tbl#format(line('.'), cur_col, cur_col+1) + call vimwiki#tbl#format(line('.'), cur_col, cur_col+1) call cursor(line('.'), 1) - if !s:is_separator(getline('.')) - call search('\%(|[^|]\+\)\{'.(cur_col+1).'}| .', 'eW') - else - call search('|\%([^+]\++\)\{'.(cur_col+1).'}--', 'eW') - endif + + let sep = '\('.s:rxSep().'\).\zs' + let mpos = -1 + let col = -1 + while col < cur_col+1 + let mpos = match(line, sep, mpos+1) + if mpos != -1 + let col += 1 + else + break + endif + endwhile endif -endfunction "}}} +endfunction + -function! vimwiki#tbl#get_rows(lnum) "{{{ +function! vimwiki#tbl#get_rows(lnum) return s:get_rows(a:lnum) -endfunction "}}} +endfunction + + +function! vimwiki#tbl#is_table(line) + return s:is_table(a:line) +endfunction + + +function! vimwiki#tbl#is_separator(line) + return s:is_separator(a:line) +endfunction + + +function! vimwiki#tbl#cell_splitter() + return s:cell_splitter() +endfunction + + +function! vimwiki#tbl#sep_splitter() + return s:sep_splitter() +endfunction -"}}} diff --git a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/u.vim b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/u.vim new file mode 100644 index 0000000..c8f62ee --- /dev/null +++ b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/u.vim @@ -0,0 +1,72 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki autoload plugin file +" Description: Utility functions +" Home: https://github.com/vimwiki/vimwiki/ + +function! vimwiki#u#trim(string, ...) + let chars = '' + if a:0 > 0 + let chars = a:1 + endif + let res = substitute(a:string, '^[[:space:]'.chars.']\+', '', '') + let res = substitute(res, '[[:space:]'.chars.']\+$', '', '') + return res +endfunction + + +" Builtin cursor doesn't work right with unicode characters. +function! vimwiki#u#cursor(lnum, cnum) + exe a:lnum + exe 'normal! 0'.a:cnum.'|' +endfunction + + +function! vimwiki#u#is_windows() + return has("win32") || has("win64") || has("win95") || has("win16") +endfunction + + +function! vimwiki#u#is_macos() + if has("mac") || has("macunix") || has("gui_mac") + return 1 + endif + " that still doesn't mean we are not on Mac OS + let os = substitute(system('uname'), '\n', '', '') + return os == 'Darwin' || os == 'Mac' +endfunction + + +function! vimwiki#u#count_first_sym(line) + let first_sym = matchstr(a:line, '\S') + return len(matchstr(a:line, first_sym.'\+')) +endfunction + + +function! vimwiki#u#escape(string) + return escape(a:string, '~.*[]\^$') +endfunction + + +" Load concrete Wiki syntax: sets regexes and templates for headers and links +function vimwiki#u#reload_regexes() + execute 'runtime! syntax/vimwiki_'.vimwiki#vars#get_wikilocal('syntax').'.vim' +endfunction + + +" Load syntax-specific functionality +function vimwiki#u#reload_regexes_custom() + execute 'runtime! syntax/vimwiki_'.vimwiki#vars#get_wikilocal('syntax').'_custom.vim' +endfunction + + +" Backward compatible version of the built-in function shiftwidth() +if exists('*shiftwidth') + func vimwiki#u#sw() + return shiftwidth() + endfunc +else + func vimwiki#u#sw() + return &sw + endfunc +endif + diff --git a/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/vars.vim b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/vars.vim new file mode 100644 index 0000000..d60a561 --- /dev/null +++ b/etc/soft/nvim/+plugins/vimwiki/autoload/vimwiki/vars.vim @@ -0,0 +1,850 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki autoload plugin file +" Home: https://github.com/vimwiki/vimwiki/ + + + +" ------------------------------------------------------------------------------------------------ +" This file provides functions to manage the various state variables which are needed during a +" Vimwiki session. +" They consist of: +" +" - global variables. These are stored in the dict g:vimwiki_global_vars. They consist mainly of +" global user variables and syntax stuff which is the same for every syntax. +" +" - wiki-local variables. They are stored in g:vimwiki_wikilocal_vars which is a list of +" dictionaries, one dict for every registered wiki. The last dictionary contains default values +" (used for temporary wikis). +" +" - syntax variables. Stored in the dict g:vimwiki_syntax_variables which holds all the regexes and +" other stuff which is needed for highlighting. +" +" - buffer-local variables. They are stored as buffer variables directly (b:foo) + +" As a developer, you should, if possible, only use the get_ and set_ functions for these types of +" variables, not the underlying dicts! +" ------------------------------------------------------------------------------------------------ + + +function! s:populate_global_variables() + + let g:vimwiki_global_vars = {} + + call s:read_global_settings_from_user() + call s:normalize_global_settings() + + " non-configurable global variables: + + " Scheme regexes must be defined even if syntax file is not loaded yet cause users should be + " able to w w without opening any vimwiki file first + let g:vimwiki_global_vars.schemes = join(['wiki\d\+', 'diary', 'local'], '\|') + let g:vimwiki_global_vars.web_schemes1 = join(['http', 'https', 'file', 'ftp', 'gopher', + \ 'telnet', 'nntp', 'ldap', 'rsync', 'imap', 'pop', 'irc', 'ircs', 'cvs', 'svn', 'svn+ssh', + \ 'git', 'ssh', 'fish', 'sftp'], '\|') + let web_schemes2 = + \ join(['mailto', 'news', 'xmpp', 'sip', 'sips', 'doi', 'urn', 'tel', 'data'], '\|') + + let g:vimwiki_global_vars.rxSchemes = '\%('. + \ g:vimwiki_global_vars.schemes . '\|'. + \ g:vimwiki_global_vars.web_schemes1 . '\|'. + \ web_schemes2 . + \ '\)' + + " match URL for common protocols; see http://en.wikipedia.org/wiki/URI_scheme + " http://tools.ietf.org/html/rfc3986 + let rxWebProtocols = + \ '\%('. + \ '\%('. + \ '\%('.g:vimwiki_global_vars.web_schemes1 . '\):'. + \ '\%(//\)'. + \ '\)'. + \ '\|'. + \ '\%('.web_schemes2.'\):'. + \ '\)' + + let g:vimwiki_global_vars.rxWeblinkUrl = rxWebProtocols . '\S\{-1,}'. '\%(([^ \t()]*)\)\=' + + let wikilink_prefix = '[[' + let wikilink_suffix = ']]' + let wikilink_separator = '|' + let g:vimwiki_global_vars.rx_wikilink_prefix = vimwiki#u#escape(wikilink_prefix) + let g:vimwiki_global_vars.rx_wikilink_suffix = vimwiki#u#escape(wikilink_suffix) + let g:vimwiki_global_vars.rx_wikilink_separator = vimwiki#u#escape(wikilink_separator) + + " templates for the creation of wiki links + " [[URL]] + let g:vimwiki_global_vars.WikiLinkTemplate1 = wikilink_prefix . '__LinkUrl__'. wikilink_suffix + " [[URL|DESCRIPTION]] + let g:vimwiki_global_vars.WikiLinkTemplate2 = wikilink_prefix . '__LinkUrl__'. wikilink_separator + \ . '__LinkDescription__' . wikilink_suffix + + let valid_chars = '[^\\\]]' + let g:vimwiki_global_vars.rxWikiLinkUrl = valid_chars.'\{-}' + let g:vimwiki_global_vars.rxWikiLinkDescr = valid_chars.'\{-}' + + " this regexp defines what can form a link when the user presses in the + " buffer (and not on a link) to create a link + " basically, it's Ascii alphanumeric characters plus #|./@-_~ plus all + " non-Ascii characters, except that . is not accepted as the last character + let g:vimwiki_global_vars.rxWord = '[^[:blank:]!"$%&''()*+,:;<=>?\[\]\\^`{}]*[^[:blank:]!"$%&''()*+.,:;<=>?\[\]\\^`{}]' + + let g:vimwiki_global_vars.rx_wikilink_prefix1 = g:vimwiki_global_vars.rx_wikilink_prefix . + \ g:vimwiki_global_vars.rxWikiLinkUrl . g:vimwiki_global_vars.rx_wikilink_separator + let g:vimwiki_global_vars.rx_wikilink_suffix1 = g:vimwiki_global_vars.rx_wikilink_suffix + + let g:vimwiki_global_vars.rxWikiInclPrefix = '{{' + let g:vimwiki_global_vars.rxWikiInclSuffix = '}}' + let g:vimwiki_global_vars.rxWikiInclSeparator = '|' + " '{{__LinkUrl__}}' + let g:vimwiki_global_vars.WikiInclTemplate1 = g:vimwiki_global_vars.rxWikiInclPrefix + \ .'__LinkUrl__'. g:vimwiki_global_vars.rxWikiInclSuffix + " '{{__LinkUrl____LinkDescription__}}' + let g:vimwiki_global_vars.WikiInclTemplate2 = g:vimwiki_global_vars.rxWikiInclPrefix + \ . '__LinkUrl__' . g:vimwiki_global_vars.rxWikiInclSeparator . '__LinkDescription__' + \ . g:vimwiki_global_vars.rxWikiInclSuffix + + let valid_chars = '[^\\\}]' + let g:vimwiki_global_vars.rxWikiInclUrl = valid_chars.'\{-}' + let g:vimwiki_global_vars.rxWikiInclArg = valid_chars.'\{-}' + let g:vimwiki_global_vars.rxWikiInclArgs = '\%('. g:vimwiki_global_vars.rxWikiInclSeparator. + \ g:vimwiki_global_vars.rxWikiInclArg. '\)'.'\{-}' + + " *. {{URL}[{...}]} - i.e. {{URL}}, {{URL|ARG1}}, {{URL|ARG1|ARG2}}, etc. + " *a) match {{URL}[{...}]} + let g:vimwiki_global_vars.rxWikiIncl = g:vimwiki_global_vars.rxWikiInclPrefix. + \ g:vimwiki_global_vars.rxWikiInclUrl. + \ g:vimwiki_global_vars.rxWikiInclArgs. g:vimwiki_global_vars.rxWikiInclSuffix + " *b) match URL within {{URL}[{...}]} + let g:vimwiki_global_vars.rxWikiInclMatchUrl = g:vimwiki_global_vars.rxWikiInclPrefix. + \ '\zs'. g:vimwiki_global_vars.rxWikiInclUrl . '\ze'. + \ g:vimwiki_global_vars.rxWikiInclArgs . g:vimwiki_global_vars.rxWikiInclSuffix + + let g:vimwiki_global_vars.rxWikiInclPrefix1 = g:vimwiki_global_vars.rxWikiInclPrefix. + \ g:vimwiki_global_vars.rxWikiInclUrl . g:vimwiki_global_vars.rxWikiInclSeparator + let g:vimwiki_global_vars.rxWikiInclSuffix1 = g:vimwiki_global_vars.rxWikiInclArgs. + \ g:vimwiki_global_vars.rxWikiInclSuffix + + let g:vimwiki_global_vars.rxTodo = '\C\<\%(TODO\|DONE\|STARTED\|FIXME\|FIXED\|XXX\)\>' + + " default colors when headers of different levels are highlighted differently + " not making it yet another option; needed by ColorScheme autocommand + let g:vimwiki_global_vars.hcolor_guifg_light = ['#aa5858', '#507030', '#1030a0', '#103040' + \ , '#505050', '#636363'] + let g:vimwiki_global_vars.hcolor_ctermfg_light = ['DarkRed', 'DarkGreen', 'DarkBlue', 'Black' + \ , 'Black', 'Black'] + let g:vimwiki_global_vars.hcolor_guifg_dark = ['#e08090', '#80e090', '#6090e0', '#c0c0f0' + \ , '#e0e0f0', '#f0f0f0'] + let g:vimwiki_global_vars.hcolor_ctermfg_dark = ['Red', 'Green', 'Blue', 'White', 'White' + \ , 'White'] +endfunction + + +function! s:read_global_settings_from_user() + let global_settings = { + \ 'CJK_length': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'auto_chdir': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'autowriteall': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, + \ 'conceallevel': {'type': type(0), 'default': 2, 'min': 0, 'max': 3}, + \ 'diary_months': {'type': type({}), 'default': + \ { + \ 1: 'January', 2: 'February', 3: 'March', + \ 4: 'April', 5: 'May', 6: 'June', + \ 7: 'July', 8: 'August', 9: 'September', + \ 10: 'October', 11: 'November', 12: 'December' + \ }}, + \ 'dir_link': {'type': type(''), 'default': ''}, + \ 'ext2syntax': {'type': type({}), 'default': {}}, + \ 'folding': {'type': type(''), 'default': '', 'possible_values': ['', 'expr', 'syntax', + \ 'list', 'custom', ':quick', 'expr:quick', 'syntax:quick', 'list:quick', + \ 'custom:quick']}, + \ 'global_ext': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, + \ 'hl_cb_checked': {'type': type(0), 'default': 0, 'min': 0, 'max': 2}, + \ 'hl_headers': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'html_header_numbering': {'type': type(0), 'default': 0, 'min': 0, 'max': 6}, + \ 'html_header_numbering_sym': {'type': type(''), 'default': ''}, + \ 'list_ignore_newline': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, + \ 'text_ignore_newline': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, + \ 'listsyms': {'type': type(''), 'default': ' .oOX', 'min_length': 2}, + \ 'listsym_rejected': {'type': type(''), 'default': '-', 'length': 1}, + \ 'map_prefix': {'type': type(''), 'default': ' w'}, + \ 'menu': {'type': type(''), 'default': 'Vimwiki'}, + \ 'table_auto_fmt': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, + \ 'table_mappings': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, + \ 'toc_header': {'type': type(''), 'default': 'Contents', 'min_length': 1}, + \ 'url_maxsave': {'type': type(0), 'default': 15, 'min': 0}, + \ 'use_calendar': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, + \ 'use_mouse': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'user_htmls': {'type': type(''), 'default': ''}, + \ 'valid_html_tags': {'type': type(''), 'default': + \ 'b,i,s,u,sub,sup,kbd,br,hr,div,center,strong,em'}, + \ 'w32_dir_enc': {'type': type(''), 'default': ''}, + \ } + + " copy the user's settings from variables of the form g:vimwiki_