dotfiles

<-- duh.
Log | Files | Refs | LICENSE

commit f458b6c01e6f343d176242febb21d6c05ffc07b3
parent fbd0b79b0e8711a4d944f31321e5da22e24ecd32
Author: Hayden Hamilton <hayden@haydenvh.com>
Date:   Wed, 11 Mar 2020 22:38:19 +0000

nvim is coming along again

Diffstat:
A.config/nvim/autoload/vimwiki/base.vim | 2096+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/customwiki2html.sh | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/default.tpl | 11+++++++++++
A.config/nvim/autoload/vimwiki/diary.vim | 327+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/html.vim | 1664+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/lst.vim | 1697+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/markdown_base.vim | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/path.vim | 183+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/style.css | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/tags.vim | 342+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/tbl.vim | 703+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/u.vim | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/autoload/vimwiki/vars.vim | 850+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M.config/nvim/init.vim | 45+++++++++++++++++++++++++++++----------------
M.config/nvim/modules/abbrs.vim | 2++
D.config/nvim/modules/buffs.vim | 3---
A.config/nvim/modules/edit.vim | 28++++++++++++++++++++++++++++
A.config/nvim/modules/message.vim | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/modules/openc.vim | 15+++++++++++++++
M.config/nvim/modules/splits.vim | 18++++--------------
M.config/nvim/modules/statusline.vim | 4++--
M.config/nvim/modules/tabs.vim | 9++++++++-
M.config/nvim/modules/theme.vim | 7+++++++
A.config/nvim/modules/wiki.vim | 12++++++++++++
A.config/nvim/modules/window.vim | 19+++++++++++++++++++
A.config/nvim/plugin/vimwiki.vim | 398+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/startup.greet | 24++++++++++++++++++++++++
A.config/nvim/syntax/greet.vim | 12++++++++++++
A.config/nvim/syntax/recent.vim | 10++++++++++
A.config/nvim/syntax/vimwiki.vim | 487+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/syntax/vimwiki_default.vim | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/syntax/vimwiki_markdown.vim | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/syntax/vimwiki_markdown_custom.vim | 194+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.config/nvim/syntax/vimwiki_media.vim | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M.config/zsh/functions | 24+++++++++++++-----------
A.scripts/bin/misc/drefresh | 4++++
36 files changed, 9923 insertions(+), 47 deletions(-)

diff --git a/.config/nvim/autoload/vimwiki/base.vim b/.config/nvim/autoload/vimwiki/base.vim @@ -0,0 +1,2096 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki autoload plugin file +" Desc: Basic functionality +" Home: https://github.com/vimwiki/vimwiki/ + +if exists("g:loaded_vimwiki_auto") || &cp + finish +endif +let g:loaded_vimwiki_auto = 1 + + +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! s:vimwiki_get_known_syntaxes() + " Getting all syntaxes that different wikis could have + let syntaxes = {} + let syntaxes['default'] = 1 + for wiki_nr in range(vimwiki#vars#number_of_wikis()) + let wiki_syntax = vimwiki#vars#get_wikilocal('syntax', wiki_nr) + let syntaxes[wiki_syntax] = 1 + endfor + " also consider the syntaxes from g:vimwiki_ext2syntax + for syn in values(vimwiki#vars#get_global('ext2syntax')) + let syntaxes[syn] = 1 + endfor + return keys(syntaxes) +endfunction + + +function! vimwiki#base#file_pattern(files) + " Get search regex from glob() + " string. Aim to support *all* special characters, forcing the user to choose + " names that are compatible with any external restrictions that they + " encounter (e.g. filesystem, wiki conventions, other syntaxes, ...). + " See: https://github.com/vimwiki-backup/vimwiki/issues/316 + " Change / to [/\\] to allow "Windows paths" + return '\V\%('.join(a:files, '\|').'\)\m' +endfunction + + +"FIXME TODO slow and faulty +function! vimwiki#base#subdir(path, filename) + let path = a:path + " ensure that we are not fooled by a symbolic link + "FIXME if we are not "fooled", we end up in a completely different wiki? + if a:filename !~# '^scp:' + let filename = resolve(a:filename) + else + let filename = a:filename + endif + let idx = 0 + "FIXME this can terminate in the middle of a path component! + while path[idx] ==? filename[idx] + let idx = idx + 1 + endwhile + + let p = split(strpart(filename, idx), '[/\\]') + let res = join(p[:-2], '/') + if len(res) > 0 + let res = res.'/' + endif + return res +endfunction + + +function! vimwiki#base#current_subdir() + return vimwiki#base#subdir(vimwiki#vars#get_wikilocal('path'), expand('%:p')) +endfunction + + +function! vimwiki#base#invsubdir(subdir) + return substitute(a:subdir, '[^/\.]\+/', '../', 'g') +endfunction + + +" Returns: the number of the wiki a file belongs to or -1 if it doesn't belong +" to any registered wiki. +" The path can be the full path or just the directory of the file +function! vimwiki#base#find_wiki(path) + let bestmatch = -1 + let bestlen = 0 + let path = vimwiki#path#path_norm(vimwiki#path#chomp_slash(a:path)) + for idx in range(vimwiki#vars#number_of_wikis()) + let idx_path = expand(vimwiki#vars#get_wikilocal('path', idx)) + let idx_path = vimwiki#path#path_norm(vimwiki#path#chomp_slash(idx_path)) + let common_pfx = vimwiki#path#path_common_pfx(idx_path, path) + if vimwiki#path#is_equal(common_pfx, idx_path) + if len(common_pfx) > bestlen + let bestlen = len(common_pfx) + let bestmatch = idx + endif + endif + endfor + + return bestmatch +endfunction + + +" THE central function of Vimwiki. Extract infos about the target from a link. +" If the second parameter is present, which should be an absolute file path, it +" is assumed that the link appears in that file. Without it, the current file +" is used. +function! vimwiki#base#resolve_link(link_text, ...) + if a:0 + let source_wiki = vimwiki#base#find_wiki(a:1) + let source_file = a:1 + else + let source_wiki = vimwiki#vars#get_bufferlocal('wiki_nr') + let source_file = vimwiki#path#current_wiki_file() + endif + + let link_text = a:link_text + + + let link_infos = { + \ 'index': -1, + \ 'scheme': '', + \ 'filename': '', + \ 'anchor': '', + \ } + + if link_text == '' + return link_infos + endif + + let scheme = matchstr(link_text, '^\zs'.vimwiki#vars#get_global('rxSchemes').'\ze:') + if scheme == '' + let link_infos.scheme = 'wiki'.source_wiki + else + let link_infos.scheme = scheme + + if link_infos.scheme !~# '\mwiki\d\+\|diary\|local\|file' + let link_infos.filename = link_text " unknown scheme, may be a weblink + return link_infos + endif + + let link_text = matchstr(link_text, '^'.vimwiki#vars#get_global('rxSchemes').':\zs.*\ze') + endif + + let is_wiki_link = link_infos.scheme =~# '\mwiki\d\+' || link_infos.scheme ==# 'diary' + + " extract anchor + if is_wiki_link + let split_lnk = split(link_text, '#', 1) + let link_text = split_lnk[0] + if len(split_lnk) > 1 && split_lnk[-1] != '' + let link_infos.anchor = join(split_lnk[1:], '#') + endif + if link_text == '' " because the link was of the form '#anchor' + let expected_ext = vimwiki#u#escape(vimwiki#vars#get_wikilocal('ext')).'$' + if source_file =~# expected_ext + " Source file has expected extension. Remove it, it will be added later on + let ext_len = strlen(vimwiki#vars#get_wikilocal('ext')) + let link_text = fnamemodify(source_file, ':p:t')[:-ext_len-1] + endif + + endif + endif + + " check if absolute or relative path + if is_wiki_link && link_text[0] == '/' + if link_text != '/' + let link_text = link_text[1:] + endif + let is_relative = 0 + elseif !is_wiki_link && vimwiki#path#is_absolute(link_text) + let is_relative = 0 + else + let is_relative = 1 + let root_dir = fnamemodify(source_file, ':p:h') . '/' + endif + + + " extract the other items depending on the scheme + if link_infos.scheme =~# '\mwiki\d\+' + let link_infos.index = eval(matchstr(link_infos.scheme, '\D\+\zs\d\+\ze')) + if link_infos.index < 0 || link_infos.index >= vimwiki#vars#number_of_wikis() + let link_infos.index = -1 + let link_infos.filename = '' + return link_infos + endif + + if !is_relative || link_infos.index != source_wiki + let root_dir = vimwiki#vars#get_wikilocal('path', link_infos.index) + endif + + let link_infos.filename = root_dir . link_text + + if vimwiki#path#is_link_to_dir(link_text) + if vimwiki#vars#get_global('dir_link') != '' + let link_infos.filename .= vimwiki#vars#get_global('dir_link') . + \ vimwiki#vars#get_wikilocal('ext', link_infos.index) + endif + else + let link_infos.filename .= vimwiki#vars#get_wikilocal('ext', link_infos.index) + endif + + elseif link_infos.scheme ==# 'diary' + let link_infos.index = source_wiki + + let link_infos.filename = + \ vimwiki#vars#get_wikilocal('path', link_infos.index) . + \ vimwiki#vars#get_wikilocal('diary_rel_path', link_infos.index) . + \ link_text . + \ vimwiki#vars#get_wikilocal('ext', link_infos.index) + elseif (link_infos.scheme ==# 'file' || link_infos.scheme ==# 'local') && is_relative + let link_infos.filename = simplify(root_dir . link_text) + else " absolute file link + " collapse repeated leading "/"'s within a link + let link_text = substitute(link_text, '\m^/\+', '/', '') + " expand ~/ + let link_text = fnamemodify(link_text, ':p') + let link_infos.filename = simplify(link_text) + endif + + let link_infos.filename = vimwiki#path#normalize(link_infos.filename) + return link_infos +endfunction + + +function! vimwiki#base#system_open_link(url) + " handlers + function! s:win32_handler(url) + "Disable shellslash for cmd and command.com, but enable for all other shells + "See Issue #560 + if (&shell =~? "cmd") || (&shell =~? "command.com") + + if exists('+shellslash') + let old_ssl = &shellslash + set noshellslash + let url = shellescape(a:url, 1) + let &shellslash = old_ssl + else + let url = shellescape(a:url, 1) + endif + execute 'silent ! start "Title" /B ' . url + + else + + if exists('+shellslash') + let old_ssl = &shellslash + set shellslash + let url = shellescape(a:url, 1) + let &shellslash = old_ssl + else + let url = shellescape(a:url, 1) + endif + execute 'silent ! start ' . url + + endif + endfunction + function! s:macunix_handler(url) + call system('open ' . shellescape(a:url).' &') + endfunction + function! s:linux_handler(url) + call system('xdg-open ' . shellescape(a:url).' &') + endfunction + try + if vimwiki#u#is_windows() + call s:win32_handler(a:url) + return + elseif vimwiki#u#is_macos() + call s:macunix_handler(a:url) + return + else + call s:linux_handler(a:url) + return + endif + endtry + echomsg 'Vimwiki Error: Default Vimwiki link handler was unable to open the HTML file!' +endfunction + + +function! vimwiki#base#open_link(cmd, link, ...) + let link_infos = {} + if a:0 + let link_infos = vimwiki#base#resolve_link(a:link, a:1) + else + let link_infos = vimwiki#base#resolve_link(a:link) + endif + + if link_infos.filename == '' + if link_infos.index == -1 + echomsg 'Vimwiki Error: No registered wiki ''' . link_infos.scheme . '''.' + else + echomsg 'Vimwiki Error: Unable to resolve link!' + endif + return + endif + + let is_wiki_link = link_infos.scheme =~# '\mwiki\d\+' || link_infos.scheme =~# 'diary' + + let update_prev_link = is_wiki_link && + \ !vimwiki#path#is_equal(link_infos.filename, vimwiki#path#current_wiki_file()) + + let vimwiki_prev_link = [] + " update previous link for wiki pages + if update_prev_link + if a:0 + let vimwiki_prev_link = [a:1, []] + elseif &ft ==# 'vimwiki' + let vimwiki_prev_link = [vimwiki#path#current_wiki_file(), getpos('.')] + endif + endif + + " open/edit + if is_wiki_link + call vimwiki#base#edit_file(a:cmd, link_infos.filename, link_infos.anchor, + \ vimwiki_prev_link, update_prev_link) + else + call vimwiki#base#system_open_link(link_infos.filename) + endif +endfunction + + +function! vimwiki#base#get_globlinks_escaped() abort + " only get links from the current dir + " change to the directory of the current file + let orig_pwd = getcwd() + lcd! %:h + " all path are relative to the current file's location + let globlinks = glob('*'.vimwiki#vars#get_wikilocal('ext'), 1)."\n" + " remove extensions + let globlinks = substitute(globlinks, '\'.vimwiki#vars#get_wikilocal('ext').'\ze\n', '', 'g') + " restore the original working directory + exe 'lcd! '.orig_pwd + " convert to a List + let lst = split(globlinks, '\n') + " Apply fnameescape() to each item + call map(lst, 'fnameescape(v:val)') + " Convert back to newline-separated list + let globlinks = join(lst, "\n") + " return all escaped links as a single newline-separated string + return globlinks +endfunction + + +function! vimwiki#base#generate_links() + let lines = [] + + let links = vimwiki#base#get_wikilinks(vimwiki#vars#get_bufferlocal('wiki_nr'), 0) + call sort(links) + + let bullet = repeat(' ', vimwiki#lst#get_list_margin()) . vimwiki#lst#default_symbol().' ' + for link in links + let abs_filepath = vimwiki#path#abs_path_of_link(link) + if !s:is_diary_file(abs_filepath) + call add(lines, bullet. + \ s:safesubstitute(vimwiki#vars#get_global('WikiLinkTemplate1'), + \ '__LinkUrl__', link, '')) + endif + endfor + + let links_rx = '\m^\s*'.vimwiki#u#escape(vimwiki#lst#default_symbol()).' ' + + call vimwiki#base#update_listing_in_buffer(lines, 'Generated Links', links_rx, line('$')+1, 1) +endfunction + + +function! vimwiki#base#goto(...) + let key = a:1 + let anchor = a:0 > 1 ? a:2 : '' + + call vimwiki#base#edit_file(':e', + \ vimwiki#vars#get_wikilocal('path') . key . vimwiki#vars#get_wikilocal('ext'), + \ anchor) +endfunction + + +function! vimwiki#base#backlinks() + let current_filename = expand("%:p") + let locations = [] + for idx in range(vimwiki#vars#number_of_wikis()) + let syntax = vimwiki#vars#get_wikilocal('syntax', idx) + let wikifiles = vimwiki#base#find_files(idx, 0) + for source_file in wikifiles + let links = s:get_links(source_file, idx) + for [target_file, _, lnum, col] in links + " don't include links from the current file to itself + if vimwiki#path#is_equal(target_file, current_filename) && + \ !vimwiki#path#is_equal(target_file, source_file) + call add(locations, {'filename':source_file, 'lnum':lnum, 'col':col}) + endif + endfor + endfor + endfor + + if empty(locations) + echomsg 'Vimwiki: No other file links to this file' + else + call setloclist(0, locations, 'r') + lopen + endif +endfunction + + +" Returns: a list containing all files of the given wiki as absolute file path. +" If the given wiki number is negative, the diary of the current wiki is used +" If the second argument is not zero, only directories are found +function! vimwiki#base#find_files(wiki_nr, directories_only) + let wiki_nr = a:wiki_nr + if wiki_nr >= 0 + let root_directory = vimwiki#vars#get_wikilocal('path', wiki_nr) + else + let root_directory = vimwiki#vars#get_wikilocal('path') . + \ vimwiki#vars#get_wikilocal('diary_rel_path') + let wiki_nr = vimwiki#vars#get_bufferlocal('wiki_nr') + endif + if a:directories_only + let ext = '/' + else + let ext = vimwiki#vars#get_wikilocal('ext', wiki_nr) + endif + " if current wiki is temporary -- was added by an arbitrary wiki file then do + " not search wiki files in subdirectories. Or it would hang the system if + " wiki file was created in $HOME or C:/ dirs. + if vimwiki#vars#get_wikilocal('is_temporary_wiki', wiki_nr) + let pattern = '*'.ext + else + let pattern = '**/*'.ext + endif + return split(globpath(root_directory, pattern), '\n') +endfunction + + +" Returns: a list containing the links to get from the current file to all wiki +" files in the given wiki. +" If the given wiki number is negative, the diary of the current wiki is used. +" If also_absolute_links is nonzero, also return links of the form /file +function! vimwiki#base#get_wikilinks(wiki_nr, also_absolute_links) + let files = vimwiki#base#find_files(a:wiki_nr, 0) + if a:wiki_nr == vimwiki#vars#get_bufferlocal('wiki_nr') + let cwd = vimwiki#path#wikify_path(expand('%:p:h')) + elseif a:wiki_nr < 0 + let cwd = vimwiki#vars#get_wikilocal('path') . vimwiki#vars#get_wikilocal('diary_rel_path') + else + let cwd = vimwiki#vars#get_wikilocal('path', a:wiki_nr) + endif + let result = [] + for wikifile in files + let wikifile = fnamemodify(wikifile, ':r') " strip extension + let wikifile = vimwiki#path#relpath(cwd, wikifile) + call add(result, wikifile) + endfor + if a:also_absolute_links + for wikifile in files + if a:wiki_nr == vimwiki#vars#get_bufferlocal('wiki_nr') + let cwd = vimwiki#vars#get_wikilocal('path') + elseif a:wiki_nr < 0 + let cwd = vimwiki#vars#get_wikilocal('path') . vimwiki#vars#get_wikilocal('diary_rel_path') + endif + let wikifile = fnamemodify(wikifile, ':r') " strip extension + let wikifile = '/'.vimwiki#path#relpath(cwd, wikifile) + call add(result, wikifile) + endfor + endif + return result +endfunction + + +" Returns: a list containing the links to all directories from the current file +function! vimwiki#base#get_wiki_directories(wiki_nr) + let dirs = vimwiki#base#find_files(a:wiki_nr, 1) + if a:wiki_nr == vimwiki#vars#get_bufferlocal('wiki_nr') + let cwd = vimwiki#path#wikify_path(expand('%:p:h')) + let root_dir = vimwiki#vars#get_wikilocal('path') + else + let cwd = vimwiki#vars#get_wikilocal('path', a:wiki_nr) + endif + let result = ['./'] + for wikidir in dirs + let wikidir_relative = vimwiki#path#relpath(cwd, wikidir) + call add(result, wikidir_relative) + if a:wiki_nr == vimwiki#vars#get_bufferlocal('wiki_nr') + let wikidir_absolute = '/'.vimwiki#path#relpath(root_dir, wikidir) + call add(result, wikidir_absolute) + endif + endfor + return result +endfunction + + +function! vimwiki#base#get_anchors(filename, syntax) + if !filereadable(a:filename) + return [] + endif + + let rxheader = vimwiki#vars#get_syntaxlocal('header_search', a:syntax) + let rxbold = vimwiki#vars#get_syntaxlocal('bold_search', a:syntax) + let rxtag = vimwiki#vars#get_syntaxlocal('tag_search', a:syntax) + + let anchor_level = ['', '', '', '', '', '', ''] + let anchors = [] + let current_complete_anchor = '' + for line in readfile(a:filename) + + " collect headers + let h_match = matchlist(line, rxheader) + if !empty(h_match) + let header = vimwiki#u#trim(h_match[2]) + let level = len(h_match[1]) + call add(anchors, header) + 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 + call add(anchors, current_complete_anchor) + endif + endif + + " collect bold text (there can be several in one line) + let bold_count = 1 + while 1 + let bold_text = matchstr(line, rxbold, 0, bold_count) + if bold_text == '' + break + endif + call add(anchors, bold_text) + if current_complete_anchor != '' + call add(anchors, current_complete_anchor.'#'.bold_text) + endif + let bold_count += 1 + endwhile + + " collect tags text (there can be several in one line) + let tag_count = 1 + while 1 + let tag_group_text = matchstr(line, rxtag, 0, tag_count) + if tag_group_text == '' + break + endif + for tag_text in split(tag_group_text, ':') + call add(anchors, tag_text) + if current_complete_anchor != '' + call add(anchors, current_complete_anchor.'#'.tag_text) + endif + endfor + let tag_count += 1 + endwhile + + endfor + + return anchors +endfunction + + +function! s:jump_to_anchor(anchor) + let oldpos = getpos('.') + call cursor(1, 1) + + let anchor = vimwiki#u#escape(a:anchor) + + let segments = split(anchor, '#', 0) + + for segment in segments + + let anchor_header = s:safesubstitute( + \ vimwiki#vars#get_syntaxlocal('header_match'), + \ '__Header__', segment, '') + let anchor_bold = s:safesubstitute( + \ vimwiki#vars#get_syntaxlocal('bold_match'), + \ '__Text__', segment, '') + let anchor_tag = s:safesubstitute( + \ vimwiki#vars#get_syntaxlocal('tag_match'), + \ '__Tag__', segment, '') + + if !search(anchor_tag, 'Wc') && !search(anchor_header, 'Wc') && !search(anchor_bold, 'Wc') + call setpos('.', oldpos) + break + endif + let oldpos = getpos('.') + endfor +endfunction + + +" Params: full path to a wiki file and its wiki number +" Returns: a list of all links inside the wiki file +" Every list item has the form +" [target file, anchor, line number of the link in source file, column number] +function! s:get_links(wikifile, idx) + if !filereadable(a:wikifile) + return [] + endif + + let syntax = vimwiki#vars#get_wikilocal('syntax', a:idx) + let rx_link = vimwiki#vars#get_syntaxlocal('wikilink', syntax) + let links = [] + let lnum = 0 + + for line in readfile(a:wikifile) + let lnum += 1 + + let link_count = 1 + while 1 + let col = match(line, rx_link, 0, link_count)+1 + let link_text = matchstr(line, rx_link, 0, link_count) + if link_text == '' + break + endif + let link_count += 1 + let target = vimwiki#base#resolve_link(link_text, a:wikifile) + if target.filename != '' && target.scheme =~# '\mwiki\d\+\|diary\|file\|local' + call add(links, [target.filename, target.anchor, lnum, col]) + endif + endwhile + endfor + + return links +endfunction + + +function! vimwiki#base#check_links() + let anchors_of_files = {} + let links_of_files = {} + let errors = [] + for idx in range(vimwiki#vars#number_of_wikis()) + let syntax = vimwiki#vars#get_wikilocal('syntax', idx) + let wikifiles = vimwiki#base#find_files(idx, 0) + for wikifile in wikifiles + let links_of_files[wikifile] = s:get_links(wikifile, idx) + let anchors_of_files[wikifile] = vimwiki#base#get_anchors(wikifile, syntax) + endfor + endfor + + for wikifile in keys(links_of_files) + for [target_file, target_anchor, lnum, col] in links_of_files[wikifile] + if target_file == '' && target_anchor == '' + call add(errors, {'filename':wikifile, 'lnum':lnum, 'col':col, + \ 'text': "numbered scheme refers to a non-existent wiki"}) + elseif has_key(anchors_of_files, target_file) + if target_anchor != '' && index(anchors_of_files[target_file], target_anchor) < 0 + call add(errors, {'filename':wikifile, 'lnum':lnum, 'col':col, + \'text': "there is no such anchor: ".target_anchor}) + endif + else + if target_file =~ '\m/$' " maybe it's a link to a directory + if !isdirectory(target_file) + call add(errors, {'filename':wikifile, 'lnum':lnum, 'col':col, + \'text': "there is no such directory: ".target_file}) + endif + else " maybe it's a non-wiki file + if filereadable(target_file) + let anchors_of_files[target_file] = [] + else + call add(errors, {'filename':wikifile, 'lnum':lnum, 'col':col, + \'text': "there is no such file: ".target_file}) + endif + endif + endif + endfor + endfor + + + " Check which wiki files are reachable from at least one of the index files. + " First, all index files are marked as reachable. Then, pick a reachable file + " and mark all files to which it links as reachable, too. Repeat until the + " links of all reachable files have been checked. + + " Map every wiki file to a number. 0 means not reachable from any index file, + " 1 means reachable, but the outgoing links are not checked yet, 2 means + " reachable and done. + let reachable_wikifiles = {} + + " first, all files are considered not reachable + for wikifile in keys(links_of_files) + let reachable_wikifiles[wikifile] = 0 + endfor + + " mark every index file as reachable + for idx in range(vimwiki#vars#number_of_wikis()) + let index_file = vimwiki#vars#get_wikilocal('path', idx) . + \ vimwiki#vars#get_wikilocal('index', idx) . vimwiki#vars#get_wikilocal('ext', idx) + if filereadable(index_file) + let reachable_wikifiles[index_file] = 1 + endif + endfor + + while 1 + let next_unvisited_wikifile = '' + for wf in keys(reachable_wikifiles) + if reachable_wikifiles[wf] == 1 + let next_unvisited_wikifile = wf + let reachable_wikifiles[wf] = 2 + break + endif + endfor + if next_unvisited_wikifile == '' + break + endif + for [target_file, target_anchor, lnum, col] in links_of_files[next_unvisited_wikifile] + if has_key(reachable_wikifiles, target_file) && reachable_wikifiles[target_file] == 0 + let reachable_wikifiles[target_file] = 1 + endif + endfor + endwhile + + for wf in keys(reachable_wikifiles) + if reachable_wikifiles[wf] == 0 + call add(errors, {'text':wf." is not reachable from the index file"}) + endif + endfor + + if empty(errors) + echomsg 'Vimwiki: All links are OK' + else + call setqflist(errors, 'r') + copen + endif +endfunction + + +function! vimwiki#base#edit_file(command, filename, anchor, ...) + let fname = escape(a:filename, '% *|#`') + let dir = fnamemodify(a:filename, ":p:h") + + let ok = vimwiki#path#mkdir(dir, 1) + + if !ok + echomsg ' ' + echomsg 'Vimwiki Error: Unable to edit file in non-existent directory: '.dir + return + endif + + " Check if the file we want to open is already the current file + " which happens if we jump to an achor in the current file. + " This hack is necessary because apparently Vim messes up the result of + " getpos() directly after this command. Strange. + if !(a:command ==# ':e ' && vimwiki#path#is_equal(a:filename, expand('%:p'))) + if &autowriteall && !&hidden " in this case, the file is saved before switching to the + " new buffer. This causes Vim to show two messages in the command line which triggers + " the annoying hit-enter prompt. Solution: show no messages at all. + silent execute a:command fname + else + try + execute a:command fname + catch /E37:/ + echomsg 'Vimwiki: Can''t leave the current buffer, because it is modified. Hint: Take a look at' + \ ''':h g:vimwiki_autowriteall'' to see how to save automatically.' + return + catch /E325:/ + echom 'Vimwiki: Vim couldn''t open the file, probably because a swapfile already exists. See :h E325.' + return + endtry + endif + + " If the opened file was not already loaded by Vim, an autocommand is + " triggered at this point + + " Make sure no other plugin takes ownership over the new file. Vimwiki + " rules them all! Well, except for directories, which may be opened with + " Netrw + if &filetype != 'vimwiki' && fname !~ '\m/$' + setfiletype vimwiki + endif + endif + if a:anchor != '' + call s:jump_to_anchor(a:anchor) + endif + + " save previous link + " a:1 -- previous vimwiki link to save + " a:2 -- should we update previous link + if a:0 && a:2 && len(a:1) > 0 + call vimwiki#vars#set_bufferlocal('prev_link', a:1) + endif +endfunction + + +function! vimwiki#base#search_word(wikiRx, cmd) + let match_line = search(a:wikiRx, 's'.a:cmd) + if match_line == 0 + echomsg 'Vimwiki: Wiki link not found' + endif +endfunction + + +" Returns part of the line that matches wikiRX at cursor +function! vimwiki#base#matchstr_at_cursor(wikiRX) + let col = col('.') - 1 + let line = getline('.') + let ebeg = -1 + let cont = match(line, a:wikiRX, 0) + while (ebeg >= 0 || (0 <= cont) && (cont <= col)) + let contn = matchend(line, a:wikiRX, cont) + if (cont <= col) && (col < contn) + let ebeg = match(line, a:wikiRX, cont) + let elen = contn - ebeg + break + else + let cont = match(line, a:wikiRX, contn) + endif + endwh + if ebeg >= 0 + return strpart(line, ebeg, elen) + else + return "" + endif +endfunction + + +function! vimwiki#base#replacestr_at_cursor(wikiRX, sub) + let col = col('.') - 1 + let line = getline('.') + let ebeg = -1 + let cont = match(line, a:wikiRX, 0) + while (ebeg >= 0 || (0 <= cont) && (cont <= col)) + let contn = matchend(line, a:wikiRX, cont) + if (cont <= col) && (col < contn) + let ebeg = match(line, a:wikiRX, cont) + let elen = contn - ebeg + break + else + let cont = match(line, a:wikiRX, contn) + endif + endwh + if ebeg >= 0 + " TODO: There might be problems with Unicode chars... + let newline = strpart(line, 0, ebeg).a:sub.strpart(line, ebeg+elen) + call setline(line('.'), newline) + endif +endfunction + + +function! s:print_wiki_list() + let idx = 0 + while idx < vimwiki#vars#number_of_wikis() + if idx == vimwiki#vars#get_bufferlocal('wiki_nr') + let sep = ' * ' + echohl PmenuSel + else + let sep = ' ' + echohl None + endif + echo (idx + 1) . sep . vimwiki#vars#get_wikilocal('path', idx) + let idx += 1 + endwhile + echohl None +endfunction + + +function! s:update_wiki_link(fname, old, new) + echo "Updating links in ".a:fname + let has_updates = 0 + let dest = [] + for line in readfile(a:fname) + if !has_updates && match(line, a:old) != -1 + let has_updates = 1 + endif + " XXX: any other characters to escape!? + call add(dest, substitute(line, a:old, escape(a:new, "&"), "g")) + endfor + " add exception handling... + if has_updates + call rename(a:fname, a:fname.'#vimwiki_upd#') + call writefile(dest, a:fname) + call delete(a:fname.'#vimwiki_upd#') + endif +endfunction + + +function! s:update_wiki_links_dir(wiki_nr, dir, old_fname, new_fname) + let old_fname = substitute(a:old_fname, '[/\\]', '[/\\\\]', 'g') + let new_fname = a:new_fname + + let old_fname_r = vimwiki#base#apply_template( + \ vimwiki#vars#get_syntaxlocal('WikiLinkMatchUrlTemplate', + \ vimwiki#vars#get_wikilocal('syntax', a:wiki_nr)), old_fname, '', '') + + let files = split(glob(vimwiki#vars#get_wikilocal('path', a:wiki_nr).a:dir.'*'. + \ vimwiki#vars#get_wikilocal('ext', a:wiki_nr)), '\n') + for fname in l:files + call s:update_wiki_link(fname, old_fname_r, new_fname) + endfor +endfunction + + +function! s:tail_name(fname) + let result = substitute(a:fname, ":", "__colon__", "g") + let result = fnamemodify(result, ":t:r") + let result = substitute(result, "__colon__", ":", "g") + return result +endfunction + + +function! s:update_wiki_links(wiki_nr, old_fname, new_fname,old_fname_relpath) + let old_fname = a:old_fname + let new_fname = a:new_fname + + let subdirs = split(a:old_fname_relpath, '[/\\]')[: -2] + + " TODO: Use Dictionary here... + let dirs_keys = [''] + let dirs_vals = [''] + if len(subdirs) > 0 + let dirs_keys = [''] + let dirs_vals = [join(subdirs, '/').'/'] + let idx = 0 + while idx < len(subdirs) - 1 + call add(dirs_keys, join(subdirs[: idx], '/').'/') + call add(dirs_vals, join(subdirs[idx+1 :], '/').'/') + let idx = idx + 1 + endwhile + call add(dirs_keys,join(subdirs, '/').'/') + call add(dirs_vals, '') + endif + + let idx = 0 + while idx < len(dirs_keys) + let dir = dirs_keys[idx] + let new_dir = dirs_vals[idx] + call s:update_wiki_links_dir(a:wiki_nr, dir, new_dir.old_fname, new_dir.new_fname) + let idx = idx + 1 + endwhile +endfunction + + +function! s:get_wiki_buffers() + let blist = [] + let bcount = 1 + while bcount<=bufnr("$") + if bufexists(bcount) + let bname = fnamemodify(bufname(bcount), ":p") + " this may find buffers that are not part of the current wiki, but that + " doesn't hurt + if bname =~# vimwiki#vars#get_wikilocal('ext')."$" + let bitem = [bname, vimwiki#vars#get_bufferlocal('prev_link', bcount)] + call add(blist, bitem) + endif + endif + let bcount = bcount + 1 + endwhile + return blist +endfunction + + +function! s:open_wiki_buffer(item) + call vimwiki#base#edit_file(':e', a:item[0], '') + if !empty(a:item[1]) + call vimwiki#vars#set_bufferlocal('prev_link', a:item[1], a:item[0]) + endif +endfunction + + +function! vimwiki#base#nested_syntax(filetype, start, end, textSnipHl) abort +" From http://vim.wikia.com/wiki/VimTip857 + let ft=toupper(a:filetype) + let group='textGroup'.ft + if exists('b:current_syntax') + let s:current_syntax=b:current_syntax + " Remove current syntax definition, as some syntax files (e.g. cpp.vim) + " do nothing if b:current_syntax is defined. + unlet b:current_syntax + endif + + " Some syntax files set up iskeyword which might scratch vimwiki a bit. + " Let us save and restore it later. + " let b:skip_set_iskeyword = 1 + let is_keyword = &iskeyword + + try + " keep going even if syntax file is not found + execute 'syntax include @'.group.' syntax/'.a:filetype.'.vim' + execute 'syntax include @'.group.' after/syntax/'.a:filetype.'.vim' + catch + endtry + + let &iskeyword = is_keyword + + if exists('s:current_syntax') + let b:current_syntax=s:current_syntax + else + unlet b:current_syntax + endif + + " Fix issue #236: tell Vimwiki to think in maths when encountering maths + " blocks like {{$ }}$. Here, we don't want the tex highlight group, but the + " group for tex math. + if a:textSnipHl ==# 'VimwikiMath' + let group='texMathZoneGroup' + endif + + execute 'syntax region textSnip'.ft. + \ ' matchgroup='.a:textSnipHl. + \ ' start="'.a:start.'" end="'.a:end.'"'. + \ ' contains=@'.group.' keepend' + + " A workaround to Issue 115: Nested Perl syntax highlighting differs from + " regular one. + " Perl syntax file has perlFunctionName which is usually has no effect due to + " 'contained' flag. Now we have 'syntax include' that makes all the groups + " included as 'contained' into specific group. + " Here perlFunctionName (with quite an angry regexp "\h\w*[^:]") clashes with + " the rest syntax rules as now it has effect being really 'contained'. + " Clear it! + if ft =~? 'perl' + syntax clear perlFunctionName + endif +endfunction + + +" creates or updates auto-generated listings in a wiki file, like TOC, diary +" links, tags list etc. +" - the listing consists of a level 1 header and a list of strings as content +" - a:content_regex is used to determine how long a potentially existing list is +" - a:default_lnum is the line number where the new listing should be placed if +" it's not already present +" - if a:create is true, it will be created if it doesn't exist, otherwise it +" will only be updated if it already exists +function! vimwiki#base#update_listing_in_buffer(strings, start_header, + \ content_regex, default_lnum, create) + " Vim behaves strangely when files change while in diff mode + if &diff || &readonly + return + endif + + " check if the listing is already there + let already_there = 0 + + let header_rx = '\m^\s*'.substitute(vimwiki#vars#get_syntaxlocal('rxH1_Template'), + \ '__Header__', a:start_header, '') .'\s*$' + + let start_lnum = 1 + while start_lnum <= line('$') + if getline(start_lnum) =~# header_rx + let already_there = 1 + break + endif + let start_lnum += 1 + endwhile + + if !already_there && !a:create + return + endif + + let winview_save = winsaveview() + let cursor_line = winview_save.lnum + let is_cursor_after_listing = 0 + + let is_fold_closed = 1 + + let lines_diff = 0 + + if already_there + let is_fold_closed = ( foldclosed(start_lnum) > -1 ) + " delete the old listing + let whitespaces_in_first_line = matchstr(getline(start_lnum), '\m^\s*') + let end_lnum = start_lnum + 1 + while end_lnum <= line('$') && getline(end_lnum) =~# a:content_regex + let end_lnum += 1 + endwhile + let is_cursor_after_listing = ( cursor_line >= end_lnum ) + " We'll be removing a range. But, apparently, if folds are enabled, Vim + " won't let you remove a range that overlaps with closed fold -- the entire + " fold gets deleted. So we temporarily disable folds, and then reenable + " them right back. + let foldenable_save = &l:foldenable + setlocal nofoldenable + silent exe 'keepjumps ' . start_lnum.','.string(end_lnum - 1).'delete _' + let &l:foldenable = foldenable_save + let lines_diff = 0 - (end_lnum - start_lnum) + else + let start_lnum = a:default_lnum + let is_cursor_after_listing = ( cursor_line > a:default_lnum ) + let whitespaces_in_first_line = '' + endif + + let start_of_listing = start_lnum + + " write new listing + let new_header = whitespaces_in_first_line + \ . s:safesubstitute(vimwiki#vars#get_syntaxlocal('rxH1_Template'), + \ '__Header__', a:start_header, '') + keepjumps call append(start_lnum - 1, new_header) + let start_lnum += 1 + let lines_diff += 1 + len(a:strings) + for string in a:strings + keepjumps call append(start_lnum - 1, string) + let start_lnum += 1 + endfor + " append an empty line if there is not one + if start_lnum <= line('$') && getline(start_lnum) !~# '\m^\s*$' + keepjumps call append(start_lnum - 1, '') + let lines_diff += 1 + endif + + " Open fold, if needed + if !is_fold_closed && ( foldclosed(start_of_listing) > -1 ) + exe start_of_listing + norm! zo + endif + + if is_cursor_after_listing + let winview_save.lnum += lines_diff + endif + call winrestview(winview_save) +endfunction + + +function! vimwiki#base#find_next_link() + call vimwiki#base#search_word(vimwiki#vars#get_syntaxlocal('rxAnyLink'), '') +endfunction + + +function! vimwiki#base#find_prev_link() + "Jump 2 times if the cursor is in the middle of a link + if synIDattr(synID(line('.'), col('.'), 0), "name") =~# "VimwikiLink.*" && + \ synIDattr(synID(line('.'), col('.')-1, 0), "name") =~# "VimwikiLink.*" + call vimwiki#base#search_word(vimwiki#vars#get_syntaxlocal('rxAnyLink'), 'b') + endif + call vimwiki#base#search_word(vimwiki#vars#get_syntaxlocal('rxAnyLink'), 'b') +endfunction + + +function! vimwiki#base#follow_link(split, ...) + let reuse_other_split_window = a:0 >= 1 ? a:1 : 0 + let move_cursor_to_new_window = a:0 >= 2 ? a:2 : 1 + + " Parse link at cursor and pass to VimwikiLinkHandler, or failing that, the + " default open_link handler + + " try WikiLink + let lnk = matchstr(vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWikiLink')), + \ vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchUrl')) + " try WikiIncl + if lnk == "" + let lnk = matchstr(vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_global('rxWikiIncl')), + \ vimwiki#vars#get_global('rxWikiInclMatchUrl')) + endif + " try Weblink + if lnk == "" + let lnk = matchstr(vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWeblink')), + \ vimwiki#vars#get_syntaxlocal('rxWeblinkMatchUrl')) + endif + + if lnk != "" " cursor is indeed on a link + let processed_by_user_defined_handler = VimwikiLinkHandler(lnk) + if processed_by_user_defined_handler + return + endif + + if a:split ==# "hsplit" + let cmd = ":split " + elseif a:split ==# "vsplit" + let cmd = ":vsplit " + elseif a:split ==# "tab" + let cmd = ":tabnew " + else + let cmd = ":e " + endif + + " if we want to and can reuse a split window, jump to that window and open + " the new file there + if (a:split ==# 'hsplit' || a:split ==# 'vsplit') && reuse_other_split_window + let previous_window_nr = winnr('#') + if previous_window_nr > 0 && previous_window_nr != winnr() + execute previous_window_nr . 'wincmd w' + let cmd = ':e' + endif + endif + + + if vimwiki#vars#get_wikilocal('syntax') == 'markdown' + let processed_by_markdown_reflink = vimwiki#markdown_base#open_reflink(lnk) + if processed_by_markdown_reflink + return + endif + + " remove the extension from the filename if exists, because non-vimwiki + " markdown files usually include the extension in links + let lnk = substitute(lnk, '\'.vimwiki#vars#get_wikilocal('ext').'$', '', '') + endif + + let current_tab_page = tabpagenr() + + call vimwiki#base#open_link(cmd, lnk) + + if !move_cursor_to_new_window + if (a:split ==# 'hsplit' || a:split ==# 'vsplit') + execute 'wincmd p' + elseif a:split ==# 'tab' + execute 'tabnext ' . current_tab_page + endif + endif + + else + if a:0 >= 3 + execute "normal! ".a:3 + else + call vimwiki#base#normalize_link(0) + endif + endif +endfunction + + +function! vimwiki#base#go_back_link() + let prev_link = vimwiki#vars#get_bufferlocal('prev_link') + if !empty(prev_link) + " go back to saved wiki link + call vimwiki#base#edit_file(':e ', prev_link[0], '') + call setpos('.', prev_link[1]) + else + " maybe we came here by jumping to a tag -> pop from the tag stack + silent! pop! + endif +endfunction + + +function! vimwiki#base#goto_index(wnum, ...) + if a:wnum > vimwiki#vars#number_of_wikis() + echomsg 'Vimwiki Error: Wiki '.a:wnum.' is not registered in your Vimwiki settings!' + return + endif + + " usually a:wnum is greater then 0 but with the following command it is == 0: + " vim -n -c ":VimwikiIndex" + if a:wnum > 0 + let idx = a:wnum - 1 + else + let idx = 0 + endif + + if a:0 + if a:1 == 1 + let cmd = 'tabedit' + elseif a:1 == 2 + let cmd = 'split' + elseif a:1 == 3 + let cmd = 'vsplit' + endif + else + let cmd = 'edit' + endif + + let index_file = vimwiki#vars#get_wikilocal('path', idx). + \ vimwiki#vars#get_wikilocal('index', idx). + \ vimwiki#vars#get_wikilocal('ext', idx) + + call vimwiki#base#edit_file(cmd, index_file, '') +endfunction + + +function! vimwiki#base#delete_link() + " Delete wiki file you are in from filesystem + let val = input('Delete "'.expand('%').'" [y]es/[N]o? ') + if val !~? '^y' + return + endif + let fname = expand('%:p') + try + call delete(fname) + catch /.*/ + echomsg 'Vimwiki Error: Cannot delete "'.expand('%:t:r').'"!' + return + endtry + + call vimwiki#base#go_back_link() + execute "bdelete! ".escape(fname, " ") + + " reread buffer => deleted wiki link should appear as non-existent + if expand('%:p') != "" + execute "e" + endif +endfunction + + +" Rename current file, update all links to it +function! vimwiki#base#rename_link() + let subdir = vimwiki#vars#get_bufferlocal('subdir') + let old_fname = subdir.expand('%:t') + + " there is no file (new one maybe) + if glob(expand('%:p')) == '' + echomsg 'Vimwiki Error: Cannot rename "'.expand('%:p'). + \'". It does not exist! (New file? Save it before renaming.)' + return + endif + + let val = input('Rename "'.expand('%:t:r').'" [y]es/[N]o? ') + if val !~? '^y' + return + endif + + let new_link = input('Enter new name: ') + + if new_link =~# '[/\\]' + echomsg 'Vimwiki Error: Cannot rename to a filename with path!' + return + endif + + if substitute(new_link, '\s', '', 'g') == '' + echomsg 'Vimwiki Error: Cannot rename to an empty filename!' + return + endif + + let url = matchstr(new_link, vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchUrl')) + if url != '' + let new_link = url + endif + + let new_link = subdir.new_link + let wiki_nr = vimwiki#vars#get_bufferlocal("wiki_nr") + let new_fname = vimwiki#vars#get_wikilocal('path') . new_link . vimwiki#vars#get_wikilocal('ext') + + " do not rename if file with such name exists + let fname = glob(new_fname) + if fname != '' + echomsg 'Vimwiki Error: Cannot rename to "'.new_fname.'". File with that name exist!' + return + endif + " rename wiki link file + try + echomsg 'Vimwiki: Renaming '.vimwiki#vars#get_wikilocal('path').old_fname.' to '.new_fname + let res = rename(expand('%:p'), expand(new_fname)) + if res != 0 + throw "Cannot rename!" + end + catch /.*/ + echomsg 'Vimwiki Error: Cannot rename "'.expand('%:t:r').'" to "'.new_fname.'"' + return + endtry + + let &buftype="nofile" + + let cur_buffer = [expand('%:p'), vimwiki#vars#get_bufferlocal('prev_link')] + + let blist = s:get_wiki_buffers() + + " save wiki buffers + for bitem in blist + execute ':b '.escape(bitem[0], ' ') + execute ':update' + endfor + + execute ':b '.escape(cur_buffer[0], ' ') + + " remove wiki buffers + for bitem in blist + execute 'bwipeout '.escape(bitem[0], ' ') + endfor + + let setting_more = &more + setlocal nomore + + " update links + call s:update_wiki_links(wiki_nr, s:tail_name(old_fname), s:tail_name(new_link),old_fname) + + " restore wiki buffers + for bitem in blist + if !vimwiki#path#is_equal(bitem[0], cur_buffer[0]) + call s:open_wiki_buffer(bitem) + endif + endfor + + call s:open_wiki_buffer([new_fname, cur_buffer[1]]) + " execute 'bwipeout '.escape(cur_buffer[0], ' ') + + echomsg 'Vimwiki: '.old_fname.' is renamed to '.new_fname + + let &more = setting_more +endfunction + + +function! vimwiki#base#ui_select() + call s:print_wiki_list() + let idx = input("Select Wiki (specify number): ") + if idx == "" + return + endif + call vimwiki#base#goto_index(idx) +endfunction + + +function! vimwiki#base#TO_header(inner, including_subheaders, count) + let headers = s:collect_headers() + if empty(headers) + return + endif + + let current_line = line('.') + + let current_header_index = s:current_header(headers, current_line) + + if current_header_index < 0 + return + endif + + " from which to which header + if !a:including_subheaders && a:count <= 1 + let first_line = headers[current_header_index][0] + let last_line = current_header_index == len(headers)-1 ? line('$') : + \ headers[current_header_index + 1][0] - 1 + else + let first_header_index = current_header_index + for _ in range(a:count - 1) + let parent = s:get_another_header(headers, first_header_index, -1, '<') + if parent < 0 + break + else + let first_header_index = parent + endif + endfor + + let next_sibling_or_higher = s:get_another_header(headers, first_header_index, +1, '<=') + + let first_line = headers[first_header_index][0] + let last_line = + \ next_sibling_or_higher >= 0 ? headers[next_sibling_or_higher][0] - 1 : line('$') + endif + + if a:inner + let first_line += 1 + let last_line = prevnonblank(last_line) + endif + + if first_line > last_line + " this can happen e.g. when doing vih on a header with another header in the very next line + return + endif + + call cursor(first_line, 1) + normal! V + call cursor(last_line, 1) +endfunction + + +function! vimwiki#base#TO_table_cell(inner, visual) + if col('.') == col('$')-1 + return + endif + + if a:visual + normal! `> + let sel_end = getpos('.') + normal! `< + let sel_start = getpos('.') + + let firsttime = sel_start == sel_end + + if firsttime + if !search('|\|\(-+-\)', 'cb', line('.')) + return + endif + if getline('.')[virtcol('.')] == '+' + normal! l + endif + if a:inner + normal! 2l + endif + let sel_start = getpos('.') + endif + + normal! `> + call search('|\|\(-+-\)', '', line('.')) + if getline('.')[virtcol('.')] == '+' + normal! l + endif + if a:inner + if firsttime || abs(sel_end[2] - getpos('.')[2]) != 2 + normal! 2h + endif + endif + let sel_end = getpos('.') + + call setpos('.', sel_start) + exe "normal! \<C-v>" + call setpos('.', sel_end) + + " XXX: WORKAROUND. + " if blockwise selection is ended at | character then pressing j to extend + " selection further fails. But if we shake the cursor left and right then + " it works. + normal! hl + else + if !search('|\|\(-+-\)', 'cb', line('.')) + return + endif + if a:inner + normal! 2l + endif + normal! v + call search('|\|\(-+-\)', '', line('.')) + if !a:inner && getline('.')[virtcol('.')-1] == '|' + normal! h + elseif a:inner + normal! 2h + endif + endif +endfunction + + +function! vimwiki#base#TO_table_col(inner, visual) + let t_rows = vimwiki#tbl#get_rows(line('.')) + if empty(t_rows) + return + endif + + " TODO: refactor it! + if a:visual + normal! `> + let sel_end = getpos('.') + normal! `< + let sel_start = getpos('.') + + let firsttime = sel_start == sel_end + + if firsttime + " place cursor to the top row of the table + call vimwiki#u#cursor(t_rows[0][0], virtcol('.')) + " do not accept the match at cursor position if cursor is next to column + " separator of the table separator (^ is a cursor): + " |-----^-+-------| + " | bla | bla | + " |-------+-------| + " or it will select wrong column. + if strpart(getline('.'), virtcol('.')-1) =~# '^-+' + let s_flag = 'b' + else + let s_flag = 'cb' + endif + " search the column separator backwards + if !search('|\|\(-+-\)', s_flag, line('.')) + return + endif + " -+- column separator is matched --> move cursor to the + sign + if getline('.')[virtcol('.')] == '+' + normal! l + endif + " inner selection --> reduce selection + if a:inner + normal! 2l + endif + let sel_start = getpos('.') + endif + + normal! `> + if !firsttime && getline('.')[virtcol('.')] == '|' + normal! l + elseif a:inner && getline('.')[virtcol('.')+1] =~# '[|+]' + normal! 2l + endif + " search for the next column separator + call search('|\|\(-+-\)', '', line('.')) + " Outer selection selects a column without border on the right. So we move + " our cursor left if the previous search finds | border, not -+-. + if getline('.')[virtcol('.')] != '+' + normal! h + endif + if a:inner + " reduce selection a bit more if inner. + normal! h + endif + " expand selection to the bottom line of the table + call vimwiki#u#cursor(t_rows[-1][0], virtcol('.')) + let sel_end = getpos('.') + + call setpos('.', sel_start) + exe "normal! \<C-v>" + call setpos('.', sel_end) + + else + " place cursor to the top row of the table + call vimwiki#u#cursor(t_rows[0][0], virtcol('.')) + " do not accept the match at cursor position if cursor is next to column + " separator of the table separator (^ is a cursor): + " |-----^-+-------| + " | bla | bla | + " |-------+-------| + " or it will select wrong column. + if strpart(getline('.'), virtcol('.')-1) =~# '^-+' + let s_flag = 'b' + else + let s_flag = 'cb' + endif + " search the column separator backwards + if !search('|\|\(-+-\)', s_flag, line('.')) + return + endif + " -+- column separator is matched --> move cursor to the + sign + if getline('.')[virtcol('.')] == '+' + normal! l + endif + " inner selection --> reduce selection + if a:inner + normal! 2l + endif + + exe "normal! \<C-V>" + + " search for the next column separator + call search('|\|\(-+-\)', '', line('.')) + " Outer selection selects a column without border on the right. So we move + " our cursor left if the previous search finds | border, not -+-. + if getline('.')[virtcol('.')] != '+' + normal! h + endif + " reduce selection a bit more if inner. + if a:inner + normal! h + endif + " expand selection to the bottom line of the table + call vimwiki#u#cursor(t_rows[-1][0], virtcol('.')) + endif +endfunction + + +function! vimwiki#base#AddHeaderLevel() + let lnum = line('.') + let line = getline(lnum) + let rxHdr = vimwiki#vars#get_syntaxlocal('rxH') + if line =~# '^\s*$' + return + endif + + if line =~# vimwiki#vars#get_syntaxlocal('rxHeader') + let level = vimwiki#u#count_first_sym(line) + if level < 6 + if vimwiki#vars#get_syntaxlocal('symH') + let line = substitute(line, '\('.rxHdr.'\+\).\+\1', rxHdr.'&'.rxHdr, '') + else + let line = substitute(line, '\('.rxHdr.'\+\).\+', rxHdr.'&', '') + endif + call setline(lnum, line) + endif + else + let line = substitute(line, '^\s*', '&'.rxHdr.' ', '') + if vimwiki#vars#get_syntaxlocal('symH') + let line = substitute(line, '\s*$', ' '.rxHdr.'&', '') + endif + call setline(lnum, line) + endif +endfunction + + +function! vimwiki#base#RemoveHeaderLevel() + let lnum = line('.') + let line = getline(lnum) + let rxHdr = vimwiki#vars#get_syntaxlocal('rxH') + if line =~# '^\s*$' + return + endif + + if line =~# vimwiki#vars#get_syntaxlocal('rxHeader') + let level = vimwiki#u#count_first_sym(line) + let old = repeat(rxHdr, level) + let new = repeat(rxHdr, level - 1) + + let chomp = line =~# rxHdr.'\s' + + if vimwiki#vars#get_syntaxlocal('symH') + let line = substitute(line, old, new, 'g') + else + let line = substitute(line, old, new, '') + endif + + if level == 1 && chomp + let line = substitute(line, '^\s', '', 'g') + let line = substitute(line, '\s$', '', 'g') + endif + + let line = substitute(line, '\s*$', '', '') + + call setline(lnum, line) + endif +endfunction + + + +" Returns all the headers in the current buffer as a list of the form +" [[line_number, header_level, header_text], [...], [...], ...] +function! s:collect_headers() + let is_inside_pre_or_math = 0 " 1: inside pre, 2: inside math, 0: outside + let headers = [] + for lnum in range(1, line('$')) + let line_content = getline(lnum) + if (is_inside_pre_or_math == 1 && line_content =~# vimwiki#vars#get_syntaxlocal('rxPreEnd')) || + \ (is_inside_pre_or_math == 2 && line_content =~# vimwiki#vars#get_syntaxlocal('rxMathEnd')) + let is_inside_pre_or_math = 0 + continue + endif + if is_inside_pre_or_math > 0 + continue + endif + if line_content =~# vimwiki#vars#get_syntaxlocal('rxPreStart') + let is_inside_pre_or_math = 1 + continue + endif + if line_content =~# vimwiki#vars#get_syntaxlocal('rxMathStart') + let is_inside_pre_or_math = 2 + continue + endif + if line_content !~# vimwiki#vars#get_syntaxlocal('rxHeader') + continue + endif + let header_level = vimwiki#u#count_first_sym(line_content) + let header_text = + \ vimwiki#u#trim(matchstr(line_content, vimwiki#vars#get_syntaxlocal('rxHeader'))) + call add(headers, [lnum, header_level, header_text]) + endfor + + return headers +endfunction + + +function! s:current_header(headers, line_number) + if empty(a:headers) + return -1 + endif + + if a:line_number >= a:headers[-1][0] + return len(a:headers) - 1 + endif + + let current_header_index = -1 + while a:headers[current_header_index+1][0] <= a:line_number + let current_header_index += 1 + endwhile + return current_header_index +endfunction + + +function! s:get_another_header(headers, current_index, direction, operation) + if empty(a:headers) || a:current_index < 0 + return -1 + endif + let current_level = a:headers[a:current_index][1] + let index = a:current_index + a:direction + + while 1 + if index < 0 || index >= len(a:headers) + return -1 + endif + if eval('a:headers[index][1] ' . a:operation . ' current_level') + return index + endif + let index += a:direction + endwhile +endfunction + + +function! vimwiki#base#goto_parent_header() + let headers = s:collect_headers() + let current_header_index = s:current_header(headers, line('.')) + let parent_header = s:get_another_header(headers, current_header_index, -1, '<') + if parent_header >= 0 + call cursor(headers[parent_header][0], 1) + else + echo 'Vimwiki: no parent header found' + endif +endfunction + + +function! vimwiki#base#goto_next_header() + let headers = s:collect_headers() + let current_header_index = s:current_header(headers, line('.')) + if current_header_index >= 0 && current_header_index < len(headers) - 1 + call cursor(headers[current_header_index + 1][0], 1) + elseif current_header_index < 0 && !empty(headers) " we're above the first header + call cursor(headers[0][0], 1) + else + echo 'Vimwiki: no next header found' + endif +endfunction + + +function! vimwiki#base#goto_prev_header() + let headers = s:collect_headers() + let current_header_index = s:current_header(headers, line('.')) + " if the cursor already was on a header, jump to the previous one + if current_header_index >= 1 && headers[current_header_index][0] == line('.') + let current_header_index -= 1 + endif + if current_header_index >= 0 + call cursor(headers[current_header_index][0], 1) + else + echo 'Vimwiki: no previous header found' + endif +endfunction + + +function! vimwiki#base#goto_sibling(direction) + let headers = s:collect_headers() + let current_header_index = s:current_header(headers, line('.')) + let next_potential_sibling = + \ s:get_another_header(headers, current_header_index, a:direction, '<=') + if next_potential_sibling >= 0 && headers[next_potential_sibling][1] == + \ headers[current_header_index][1] + call cursor(headers[next_potential_sibling][0], 1) + else + echo 'Vimwiki: no sibling header found' + endif +endfunction + + +" a:create == 1: creates or updates TOC in current file +" a:create == 0: update if TOC exists +function! vimwiki#base#table_of_contents(create) + let headers = s:collect_headers() + let toc_header_text = vimwiki#vars#get_global('toc_header') + + if !a:create + " Do nothing if there is no TOC to update. (This is a small performance optimization -- if + " auto_toc == 1, but the current buffer has no TOC but is long, saving the buffer could + " otherwise take a few seconds for nothing.) + let toc_already_present = 0 + for entry in headers + if entry[2] ==# toc_header_text + let toc_already_present = 1 + break + endif + endfor + if !toc_already_present + return + endif + endif + + let numbering = vimwiki#vars#get_global('html_header_numbering') + let headers_levels = [['', 0], ['', 0], ['', 0], ['', 0], ['', 0], ['', 0]] + let complete_header_infos = [] + for header in headers + let h_text = header[2] + let h_level = header[1] + if h_text ==# toc_header_text " don't include the TOC's header itself + continue + endif + let headers_levels[h_level-1] = [h_text, headers_levels[h_level-1][1]+1] + for idx in range(h_level, 5) | let headers_levels[idx] = ['', 0] | endfor + + let h_complete_id = '' + for l in range(h_level-1) + if headers_levels[l][0] != '' + let h_complete_id .= headers_levels[l][0].'#' + endif + endfor + let h_complete_id .= headers_levels[h_level-1][0] + + if numbering > 0 && numbering <= h_level + let h_number = join(map(copy(headers_levels[numbering-1 : h_level-1]), 'v:val[1]'), '.') + let h_number .= vimwiki#vars#get_global('html_header_numbering_sym') + let h_text = h_number.' '.h_text + endif + + call add(complete_header_infos, [h_level, h_complete_id, h_text]) + endfor + + let lines = [] + let startindent = repeat(' ', vimwiki#lst#get_list_margin()) + let indentstring = repeat(' ', vimwiki#u#sw()) + let bullet = vimwiki#lst#default_symbol().' ' + for [lvl, link, desc] in complete_header_infos + if vimwiki#vars#get_wikilocal('syntax') == 'markdown' + let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink1Template') + else + let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate2') + endif + let link = s:safesubstitute(link_tpl, '__LinkUrl__', + \ '#'.link, '') + let link = s:safesubstitute(link, '__LinkDescription__', desc, '') + call add(lines, startindent.repeat(indentstring, lvl-1).bullet.link) + endfor + + let links_rx = '\m^\s*'.vimwiki#u#escape(vimwiki#lst#default_symbol()).' ' + + call vimwiki#base#update_listing_in_buffer(lines, toc_header_text, links_rx, 1, a:create) +endfunction + + +" Construct a regular expression matching from template (with special +" characters properly escaped), by substituting rxUrl for __LinkUrl__, rxDesc +" for __LinkDescription__, and rxStyle for __LinkStyle__. The three +" arguments rxUrl, rxDesc, and rxStyle are copied verbatim, without any +" special character escapes or substitutions. +function! vimwiki#base#apply_template(template, rxUrl, rxDesc, rxStyle) + let lnk = a:template + if a:rxUrl != "" + let lnk = s:safesubstitute(lnk, '__LinkUrl__', a:rxUrl, 'g') + endif + if a:rxDesc != "" + let lnk = s:safesubstitute(lnk, '__LinkDescription__', a:rxDesc, 'g') + endif + if a:rxStyle != "" + let lnk = s:safesubstitute(lnk, '__LinkStyle__', a:rxStyle, 'g') + endif + return lnk +endfunction + + +function! s:clean_url(url) + " remove protocol and tld + let url = substitute(a:url, '^\a\+\d*:', '', '') + let url = substitute(url, '^//', '', '') + let url = substitute(url, '^\([^/]\+\)\.\a\{2,4}/', '\1/', '') + let url = split(url, '/\|=\|-\|&\|?\|\.') + let url = filter(url, 'v:val !=# ""') + if url[0] == "www" + let url = url[1:] + endif + if url[-1] =~ '^\(htm\|html\|php\)$' + let url = url[0:-2] + endif + " remove words consisting of only hexadecimal digits or non-word characters + let url = filter(url, 'v:val !~ "^\\A\\{4,}$"') + let url = filter(url, 'v:val !~ "^\\x\\{4,}$" || v:val !~ "\\d"') + return join(url, " ") +endfunction + + +function! s:is_diary_file(filename) + let file_path = vimwiki#path#path_norm(a:filename) + let rel_path = vimwiki#vars#get_wikilocal('diary_rel_path') + let diary_path = vimwiki#path#path_norm(vimwiki#vars#get_wikilocal('path') . rel_path) + return rel_path != '' && file_path =~# '^'.vimwiki#u#escape(diary_path) +endfunction + + +function! vimwiki#base#normalize_link_helper(str, rxUrl, rxDesc, template) + let url = matchstr(a:str, a:rxUrl) + let descr = matchstr(a:str, a:rxDesc) + if descr == "" + let descr = s:clean_url(url) + endif + let lnk = s:safesubstitute(a:template, '__LinkDescription__', descr, '') + let lnk = s:safesubstitute(lnk, '__LinkUrl__', url, '') + return lnk +endfunction + + +function! vimwiki#base#normalize_imagelink_helper(str, rxUrl, rxDesc, rxStyle, template) + let lnk = vimwiki#base#normalize_link_helper(a:str, a:rxUrl, a:rxDesc, a:template) + let style = matchstr(a:str, a:rxStyle) + let lnk = s:safesubstitute(lnk, '__LinkStyle__', style, '') + return lnk +endfunction + + +function! s:normalize_link_in_diary(lnk) + let link = a:lnk . vimwiki#vars#get_wikilocal('ext') + let link_wiki = vimwiki#vars#get_wikilocal('path') . '/' . link + let link_diary = vimwiki#vars#get_wikilocal('path') . '/' + \ . vimwiki#vars#get_wikilocal('diary_rel_path') . '/' . link + let link_exists_in_diary = filereadable(link_diary) + let link_exists_in_wiki = filereadable(link_wiki) + let link_is_date = a:lnk =~# '\d\d\d\d-\d\d-\d\d' + + if link_exists_in_diary || link_is_date + let str = a:lnk + let rxUrl = vimwiki#vars#get_global('rxWord') + let rxDesc = '' + let template = vimwiki#vars#get_global('WikiLinkTemplate1') + elseif link_exists_in_wiki + let depth = len(split(vimwiki#vars#get_wikilocal('diary_rel_path'), '/')) + let str = repeat('../', depth) . a:lnk . '|' . a:lnk + let rxUrl = '^.*\ze|' + let rxDesc = '|\zs.*$' + let template = vimwiki#vars#get_global('WikiLinkTemplate2') + else + let str = a:lnk + let rxUrl = '.*' + let rxDesc = '' + let template = vimwiki#vars#get_global('WikiLinkTemplate1') + endif + + return vimwiki#base#normalize_link_helper(str, rxUrl, rxDesc, template) +endfunction + + +function! s:normalize_link_syntax_n() + + " try WikiLink + let lnk = vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWikiLink')) + 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('rxWikiLink'), sub) + return + endif + + " try WikiIncl + let lnk = vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_global('rxWikiIncl')) + if !empty(lnk) + " NO-OP !! + 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, + \ lnk, '', vimwiki#vars#get_global('WikiLinkTemplate2')) + 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) + if s:is_diary_file(expand("%:p")) + let sub = s:normalize_link_in_diary(lnk) + else + let sub = s:safesubstitute( + \ vimwiki#vars#get_global('WikiLinkTemplate1'), '__LinkUrl__', lnk, '') + endif + call vimwiki#base#replacestr_at_cursor('\V'.lnk, sub) + return + endif + +endfunction + + +function! s:normalize_link_syntax_v() + let sel_save = &selection + let &selection = "old" + let default_register_save = @" + let registertype_save = getregtype('"') + + try + " Save selected text to register " + normal! gv""y + + " Set substitution + if s:is_diary_file(expand("%:p")) + let sub = s:normalize_link_in_diary(@") + else + let sub = s:safesubstitute(vimwiki#vars#get_global('WikiLinkTemplate1'), + \ '__LinkUrl__', @", '') + endif + + " Put substitution in register " and change text + call setreg('"', substitute(sub, '\n', '', ''), visualmode()) + normal! `>""pgvd + finally + call setreg('"', default_register_save, registertype_save) + let &selection = sel_save + endtry +endfunction + + +function! vimwiki#base#normalize_link(is_visual_mode) + if exists('*vimwiki#'.vimwiki#vars#get_wikilocal('syntax').'_base#normalize_link') + " Syntax-specific links + call vimwiki#{vimwiki#vars#get_wikilocal('syntax')}_base#normalize_link(a:is_visual_mode) + 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 + + +function! vimwiki#base#detect_nested_syntax() + let last_word = '\v.*<(\w+)\s*$' + let lines = map(filter(getline(1, "$"), 'v:val =~ "\\%({{{\\|```\\)" && v:val =~ last_word'), + \ 'substitute(v:val, last_word, "\\=submatch(1)", "")') + let dict = {} + for elem in lines + let dict[elem] = elem + endfor + return dict +endfunction + + +function! vimwiki#base#complete_links_escaped(ArgLead, CmdLine, CursorPos) abort + " We can safely ignore args if we use -custom=complete option, Vim engine + " will do the job of filtering. + return vimwiki#base#get_globlinks_escaped() +endfunction + + +" ------------------------------------------------------------------------- +" Load syntax-specific Wiki functionality +for s:syn in s:vimwiki_get_known_syntaxes() + execute 'runtime! autoload/vimwiki/'.s:syn.'_base.vim' +endfor +" ------------------------------------------------------------------------- + diff --git a/.config/nvim/autoload/vimwiki/customwiki2html.sh b/.config/nvim/autoload/vimwiki/customwiki2html.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# +# This script converts markdown into html, to be used with vimwiki's +# "customwiki2html" option. Experiment with the two proposed methods by +# commenting / uncommenting the relevant lines below. +# +# NEW! An alternative converter was developed by Jason6Anderson, and can +# be located at https://github.com/vimwiki-backup/vimwiki/issues/384 +# +# +# To use this script, you must have the Discount converter installed. +# +# http://www.pell.portland.or.us/~orc/Code/discount/ +# +# To verify your installation, check that the commands markdown and mkd2text, +# are on your path. +# +# Also verify that this file is executable. +# +# Then, in your .vimrc file, set: +# +# g:vimwiki_customwiki2html=$HOME.'/.vim/autoload/vimwiki/customwiki2html.sh' +# +# On your next restart, Vimwiki will run this script instead of using the +# internal wiki2html converter. +# + +MARKDOWN=markdown +MKD2HTML=mkd2html + + +FORCE="$1" +SYNTAX="$2" +EXTENSION="$3" +OUTPUTDIR="$4" +INPUT="$5" +CSSFILE="$6" + +FORCEFLAG= + +[ $FORCE -eq 0 ] || { FORCEFLAG="-f"; }; +[ $SYNTAX = "markdown" ] || { echo "Error: Unsupported syntax"; exit -2; }; + +OUTPUT="$OUTPUTDIR"/$(basename "$INPUT" .$EXTENSION).html + +# # Method 1: +# # markdown [-d] [-T] [-V] [-b url-base] [-C prefix] [-F bitmap] [-f flags] [-o file] [-s text] [-t text] [textfile] +# +# URLBASE=http://example.com +# $MARKDOWN -T -b $URLBASE -o $OUTPUT $INPUT + + +# Method 2: +# mkd2html [-css file] [-header string] [-footer string] [file] + +$MKD2HTML -css "$CSSFILE" "$INPUT" +OUTPUTTMP=$(dirname "$INPUT")/$(basename "$INPUT" ."$EXTENSION").html +mv -f "$OUTPUTTMP" "$OUTPUT" + + + diff --git a/.config/nvim/autoload/vimwiki/default.tpl b/.config/nvim/autoload/vimwiki/default.tpl @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="Stylesheet" type="text/css" href="%root_path%%css%"> +<title>%title%</title> +<meta http-equiv="Content-Type" content="text/html; charset=%encoding%"> +</head> +<body> +%content% +</body> +</html> diff --git a/.config/nvim/autoload/vimwiki/diary.vim b/.config/nvim/autoload/vimwiki/diary.vim @@ -0,0 +1,327 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki autoload plugin file +" Description: Handle diary notes +" Home: https://github.com/vimwiki/vimwiki/ + + +if exists("g:loaded_vimwiki_diary_auto") || &cp + finish +endif +let g:loaded_vimwiki_diary_auto = 1 + + +let s:vimwiki_max_scan_for_caption = 5 + + +function! s:prefix_zero(num) + if a:num < 10 + return '0'.a:num + endif + return a:num +endfunction + + +function! s:diary_path(...) + let idx = a:0 == 0 ? vimwiki#vars#get_bufferlocal('wiki_nr') : a:1 + return vimwiki#vars#get_wikilocal('path', idx).vimwiki#vars#get_wikilocal('diary_rel_path', idx) +endfunction + + +function! s:diary_index(...) + let idx = a:0 == 0 ? vimwiki#vars#get_bufferlocal('wiki_nr') : a:1 + return s:diary_path(idx).vimwiki#vars#get_wikilocal('diary_index', idx). + \ vimwiki#vars#get_wikilocal('ext', idx) +endfunction + + +function! vimwiki#diary#diary_date_link(...) + if a:0 + return strftime('%Y-%m-%d', a:1) + else + return strftime('%Y-%m-%d') + endif +endfunction + + +function! s:get_position_links(link) + let idx = -1 + let links = [] + if a:link =~# '^\d\{4}-\d\d-\d\d' + let links = map(s:get_diary_files(), 'fnamemodify(v:val, ":t:r")') + " include 'today' into links + if index(links, vimwiki#diary#diary_date_link()) == -1 + call add(links, vimwiki#diary#diary_date_link()) + endif + call sort(links) + let idx = index(links, a:link) + endif + return [idx, links] +endfunction + + +function! s:get_month_name(month) + return vimwiki#vars#get_global('diary_months')[str2nr(a:month)] +endfunction + + +function! s:read_captions(files) + let result = {} + let rx_header = vimwiki#vars#get_syntaxlocal('rxHeader') + for fl in a:files + " remove paths and extensions + let fl_key = substitute(fnamemodify(fl, ':t'), vimwiki#vars#get_wikilocal('ext').'$', '', '') + + if filereadable(fl) + for line in readfile(fl, '', s:vimwiki_max_scan_for_caption) + if line =~# rx_header && !has_key(result, fl_key) + let result[fl_key] = vimwiki#u#trim(matchstr(line, rx_header)) + endif + endfor + endif + + if !has_key(result, fl_key) + let result[fl_key] = '' + endif + + endfor + return result +endfunction + + +function! s:get_diary_files() + let rx = '^\d\{4}-\d\d-\d\d' + let s_files = glob(vimwiki#vars#get_wikilocal('path'). + \ vimwiki#vars#get_wikilocal('diary_rel_path').'*'.vimwiki#vars#get_wikilocal('ext')) + let files = split(s_files, '\n') + call filter(files, 'fnamemodify(v:val, ":t") =~# "'.escape(rx, '\').'"') + + " remove backup files (.wiki~) + call filter(files, 'v:val !~# ''.*\~$''') + + return files +endfunction + + +function! s:group_links(links) + let result = {} + let p_year = 0 + let p_month = 0 + for fl in sort(keys(a:links)) + let year = strpart(fl, 0, 4) + let month = strpart(fl, 5, 2) + if p_year != year + let result[year] = {} + let p_month = 0 + endif + if p_month != month + let result[year][month] = {} + endif + let result[year][month][fl] = a:links[fl] + let p_year = year + let p_month = month + endfor + return result +endfunction + + +function! s:sort(lst) + if vimwiki#vars#get_wikilocal('diary_sort') ==? 'desc' + return reverse(sort(a:lst)) + else + return sort(a:lst) + endif +endfunction + + +function! s:format_diary() + let result = [] + + let links_with_captions = s:read_captions(s:get_diary_files()) + let g_files = s:group_links(links_with_captions) + + for year in s:sort(keys(g_files)) + call add(result, '') + call add(result, + \ substitute(vimwiki#vars#get_syntaxlocal('rxH2_Template'), '__Header__', year , '')) + + for month in s:sort(keys(g_files[year])) + call add(result, '') + call add(result, substitute(vimwiki#vars#get_syntaxlocal('rxH3_Template'), + \ '__Header__', s:get_month_name(month), '')) + + for [fl, cap] in s:sort(items(g_files[year][month])) + let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate2') + + if vimwiki#vars#get_wikilocal('syntax') == 'markdown' + let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink1Template') + + if empty(cap) " When using markdown syntax, we should ensure we always have a link description. + let cap = fl + endif + elseif empty(cap) + let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate1') + endif + + let entry = substitute(link_tpl, '__LinkUrl__', fl, '') + let entry = substitute(entry, '__LinkDescription__', cap, '') + call add(result, repeat(' ', vimwiki#lst#get_list_margin()).'* '.entry) + endfor + + endfor + endfor + + return result +endfunction + + +" The given wiki number a:wnum is 1 for the first wiki, 2 for the second and so on. This is in +" contrast to most other places, where counting starts with 0. When a:wnum is 0, the current wiki +" is used. +function! vimwiki#diary#make_note(wnum, ...) + if a:wnum == 0 + let wiki_nr = vimwiki#vars#get_bufferlocal('wiki_nr') + if wiki_nr < 0 " this happens when e.g. VimwikiMakeDiaryNote was called outside a wiki buffer + let wiki_nr = 0 + endif + else + let wiki_nr = a:wnum - 1 + endif + + if wiki_nr >= vimwiki#vars#number_of_wikis() + echomsg 'Vimwiki Error: Wiki '.wiki_nr.' is not registered in g:vimwiki_list!' + return + endif + + " TODO: refactor it. base#goto_index uses the same + + call vimwiki#path#mkdir(vimwiki#vars#get_wikilocal('path', wiki_nr). + \ vimwiki#vars#get_wikilocal('diary_rel_path', wiki_nr)) + + let cmd = 'edit' + if a:0 + if a:1 == 1 + let cmd = 'tabedit' + elseif a:1 == 2 + let cmd = 'split' + elseif a:1 == 3 + let cmd = 'vsplit' + endif + endif + if a:0>1 + let link = 'diary:'.a:2 + else + let link = 'diary:'.vimwiki#diary#diary_date_link() + endif + + call vimwiki#base#open_link(cmd, link, s:diary_index(wiki_nr)) +endfunction + + +function! vimwiki#diary#goto_diary_index(wnum) + if a:wnum > vimwiki#vars#number_of_wikis() + echomsg 'Vimwiki Error: Wiki '.a:wnum.' is not registered in g:vimwiki_list!' + return + endif + + " TODO: refactor it. base#goto_index uses the same + if a:wnum > 0 + let idx = a:wnum - 1 + else + let idx = 0 + endif + + call vimwiki#base#edit_file('e', s:diary_index(idx), '') + + if vimwiki#vars#get_wikilocal('auto_diary_index') + call vimwiki#diary#generate_diary_section() + write! " save changes + endif +endfunction + + +function! vimwiki#diary#goto_next_day() + let link = '' + let [idx, links] = s:get_position_links(expand('%:t:r')) + + if idx == (len(links) - 1) + return + endif + + if idx != -1 && idx < len(links) - 1 + let link = 'diary:'.links[idx+1] + else + " goto today + let link = 'diary:'.vimwiki#diary#diary_date_link() + endif + + if len(link) + call vimwiki#base#open_link(':e ', link) + endif +endfunction + + +function! vimwiki#diary#goto_prev_day() + let link = '' + let [idx, links] = s:get_position_links(expand('%:t:r')) + + if idx == 0 + return + endif + + if idx > 0 + let link = 'diary:'.links[idx-1] + else + " goto today + let link = 'diary:'.vimwiki#diary#diary_date_link() + endif + + if len(link) + call vimwiki#base#open_link(':e ', link) + endif +endfunction + + +function! vimwiki#diary#generate_diary_section() + let current_file = vimwiki#path#path_norm(expand("%:p")) + let diary_file = vimwiki#path#path_norm(s:diary_index()) + if vimwiki#path#is_equal(current_file, diary_file) + let content_rx = '^\%(\s*\* \)\|\%(^\s*$\)\|\%('.vimwiki#vars#get_syntaxlocal('rxHeader').'\)' + call vimwiki#base#update_listing_in_buffer(s:format_diary(), + \ vimwiki#vars#get_wikilocal('diary_header'), content_rx, line('$')+1, 1) + else + echomsg 'Vimwiki Error: You can generate diary links only in a diary index page!' + endif +endfunction + + +" Callback function for Calendar.vim +function! vimwiki#diary#calendar_action(day, month, year, week, dir) + let day = s:prefix_zero(a:day) + let month = s:prefix_zero(a:month) + + let link = a:year.'-'.month.'-'.day + if winnr('#') == 0 + if a:dir ==? 'V' + vsplit + else + split + endif + else + wincmd p + if !&hidden && &modified + new + endif + endif + + call vimwiki#diary#make_note(0, 0, link) +endfunction + + +function vimwiki#diary#calendar_sign(day, month, year) + let day = s:prefix_zero(a:day) + let month = s:prefix_zero(a:month) + let sfile = vimwiki#vars#get_wikilocal('path').vimwiki#vars#get_wikilocal('diary_rel_path'). + \ a:year.'-'.month.'-'.day.vimwiki#vars#get_wikilocal('ext') + return filereadable(expand(sfile)) +endfunction + diff --git a/.config/nvim/autoload/vimwiki/html.vim b/.config/nvim/autoload/vimwiki/html.vim @@ -0,0 +1,1664 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki autoload plugin file +" Description: HTML export +" Home: https://github.com/vimwiki/vimwiki/ + + +if exists("g:loaded_vimwiki_html_auto") || &cp + finish +endif +let g:loaded_vimwiki_html_auto = 1 + + +function! s:root_path(subdir) + return repeat('../', len(split(a:subdir, '[/\\]'))) +endfunction + + +function! s:syntax_supported() + return vimwiki#vars#get_wikilocal('syntax') ==? "default" +endfunction + + +function! s:remove_blank_lines(lines) + while !empty(a:lines) && a:lines[-1] =~# '^\s*$' + call remove(a:lines, -1) + endwhile +endfunction + + +function! s:is_web_link(lnk) + if a:lnk =~# '^\%(https://\|http://\|www.\|ftp://\|file://\|mailto:\)' + return 1 + endif + return 0 +endfunction + + +function! s:is_img_link(lnk) + if tolower(a:lnk) =~# '\.\%(png\|jpg\|gif\|jpeg\)$' + return 1 + endif + return 0 +endfunction + + +function! s:has_abs_path(fname) + if a:fname =~# '\(^.:\)\|\(^/\)' + return 1 + endif + return 0 +endfunction + + +function! s:find_autoload_file(name) + for path in split(&runtimepath, ',') + let fname = path.'/autoload/vimwiki/'.a:name + if glob(fname) != '' + return fname + endif + endfor + return '' +endfunction + + +function! s:default_CSS_full_name(path) + let path = expand(a:path) + let css_full_name = path . vimwiki#vars#get_wikilocal('css_name') + return css_full_name +endfunction + + +function! s:create_default_CSS(path) + let css_full_name = s:default_CSS_full_name(a:path) + if glob(css_full_name) == "" + call vimwiki#path#mkdir(fnamemodify(css_full_name, ':p:h')) + let default_css = s:find_autoload_file('style.css') + if default_css != '' + let lines = readfile(default_css) + call writefile(lines, css_full_name) + return 1 + endif + endif + return 0 +endfunction + + +function! s:template_full_name(name) + if a:name == '' + let name = vimwiki#vars#get_wikilocal('template_default') + else + let name = a:name + endif + + let fname = expand(vimwiki#vars#get_wikilocal('template_path'). + \ name . vimwiki#vars#get_wikilocal('template_ext')) + + if filereadable(fname) + return fname + else + return '' + endif +endfunction + + +function! s:get_html_template(template) + " TODO: refactor it!!! + let lines=[] + + if a:template != '' + let template_name = s:template_full_name(a:template) + try + let lines = readfile(template_name) + return lines + catch /E484/ + echomsg 'Vimwiki: HTML template '.template_name. ' does not exist!' + endtry + endif + + let default_tpl = s:template_full_name('') + + if default_tpl == '' + let default_tpl = s:find_autoload_file('default.tpl') + endif + + let lines = readfile(default_tpl) + return lines +endfunction + + +function! s:safe_html_preformatted(line) + let line = substitute(a:line,'<','\&lt;', 'g') + let line = substitute(line,'>','\&gt;', 'g') + return line +endfunction + + +function! s:escape_html_attribute(string) + return substitute(a:string, '"', '\&quot;', 'g') +endfunction + + +function! s:safe_html_line(line) + " escape & < > when producing HTML text + " s:lt_pattern, s:gt_pattern depend on g:vimwiki_valid_html_tags + " and are set in vimwiki#html#Wiki2HTML() + let line = substitute(a:line, '&', '\&amp;', 'g') + let line = substitute(line,s:lt_pattern,'\&lt;', 'g') + let line = substitute(line,s:gt_pattern,'\&gt;', 'g') + + return line +endfunction + + +function! s:delete_html_files(path) + let htmlfiles = split(glob(a:path.'**/*.html'), '\n') + for fname in htmlfiles + " ignore user html files, e.g. search.html,404.html + if stridx(vimwiki#vars#get_global('user_htmls'), fnamemodify(fname, ":t")) >= 0 + continue + endif + + " delete if there is no corresponding wiki file + let subdir = vimwiki#base#subdir(vimwiki#vars#get_wikilocal('path_html'), fname) + let wikifile = vimwiki#vars#get_wikilocal('path').subdir. + \fnamemodify(fname, ":t:r").vimwiki#vars#get_wikilocal('ext') + if filereadable(wikifile) + continue + endif + + try + call delete(fname) + catch + echomsg 'Vimwiki Error: Cannot delete '.fname + endtry + endfor +endfunction + + +function! s:mid(value, cnt) + return strpart(a:value, a:cnt, len(a:value) - 2 * a:cnt) +endfunction + + +function! s:subst_func(line, regexp, func, ...) + " Substitute text found by regexp with result of + " func(matched) function. + + let pos = 0 + let lines = split(a:line, a:regexp, 1) + let res_line = "" + for line in lines + let res_line = res_line.line + let matched = matchstr(a:line, a:regexp, pos) + if matched != "" + if a:0 + let res_line = res_line.{a:func}(matched, a:1) + else + let res_line = res_line.{a:func}(matched) + endif + endif + let pos = matchend(a:line, a:regexp, pos) + endfor + return res_line +endfunction + + +function! s:process_date(placeholders, default_date) + if !empty(a:placeholders) + for [placeholder, row, idx] in a:placeholders + let [type, param] = placeholder + if type ==# 'date' && !empty(param) + return param + endif + endfor + endif + return a:default_date +endfunction + + +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) + return param + endif + endfor + endif + return a:default_title +endfunction + + +function! s:is_html_uptodate(wikifile) + let tpl_time = -1 + + let tpl_file = s:template_full_name('') + if tpl_file != '' + let tpl_time = getftime(tpl_file) + endif + + let wikifile = fnamemodify(a:wikifile, ":p") + 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 + + +function! s:html_insert_contents(html_lines, content) + let lines = [] + for line in a:html_lines + if line =~# '%content%' + let parts = split(line, '%content%', 1) + if empty(parts) + call extend(lines, a:content) + else + for idx in range(len(parts)) + call add(lines, parts[idx]) + if idx < len(parts) - 1 + call extend(lines, a:content) + endif + endfor + endif + else + call add(lines, line) + endif + endfor + return lines +endfunction + + +function! s:tag_eqin(value) + " mathJAX wants \( \) for inline maths + return '\('.s:mid(a:value, 1).'\)' +endfunction + + +function! s:tag_em(value) + return '<em>'.s:mid(a:value, 1).'</em>' +endfunction + + +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 '<span id="'.s:escape_html_attribute(complete_id).'"></span><strong id="' + \ .id.'">'.text.'</strong>' +endfunction + + +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, '<span id="'.complete_id.'-'.id.'"></span><span class="tag" id="' + \ .id.'">'.tag.'</span>') + endfor + return join(result) +endfunction + + +function! s:tag_todo(value) + return '<span class="todo">'.a:value.'</span>' +endfunction + + +function! s:tag_strike(value) + return '<del>'.s:mid(a:value, 2).'</del>' +endfunction + + +function! s:tag_super(value) + return '<sup><small>'.s:mid(a:value, 1).'</small></sup>' +endfunction + + +function! s:tag_sub(value) + return '<sub><small>'.s:mid(a:value, 2).'</small></sub>' +endfunction + + +function! s:tag_code(value) + return '<code>'.s:safe_html_preformatted(s:mid(a:value, 1)).'</code>' +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 '<a'.src_str.'>'.descr_str.'</a>' +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 '<img'.src_str.descr_str.verbatim_str.' />' +endfunction + + +function! s:tag_weblink(value) + " Weblink Template -> <a href="url">descr</a> + 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}} -> <img src="imgurl"/> + " {{imgurl|descr|style="A"}} -> <img src="imgurl" alt="descr" style="A" /> + " {{imgurl|descr|class="B"}} -> <img src="imgurl" alt="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 url = link_infos.filename + endif + + let url = escape(url, '#') + let line = s:linkify_image(url, descr, verbatim_str) + endif + return line +endfunction + + +function! s:tag_wikilink(value) + " [[url]] -> <a href="url.html">url</a> + " [[url|descr]] -> <a href="url.html">descr</a> + " [[url|{{...}}]] -> <a href="url.html"> ... </a> + " [[fileurl.ext|descr]] -> <a href="fileurl.ext">descr</a> + " [[dirurl/|descr]] -> <a href="dirurl/index.html">descr</a> + " [[url#a1#a2]] -> <a href="url.html#a1-a2">url#a1#a2</a> + " [[#a1#a2]] -> <a href="#a1-a2">#a1#a2</a> + 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 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 + + +function! s:tag_remove_internal_link(value) + let value = s:mid(a:value, 2) + + let line = '' + if value =~# '|' + let link_parts = split(value, "|", 1) + else + let link_parts = split(value, "][", 1) + endif + + if len(link_parts) > 1 + if len(link_parts) < 3 + let style = "" + else + let style = link_parts[2] + endif + let line = link_parts[1] + else + let line = value + endif + return line +endfunction + + +function! s:tag_remove_external_link(value) + 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 + let line = rest + elseif s:is_img_link(value) + let line = '<img src="'.value.'" />' + else + " [alskfj sfsf] shouldn't be a link. So return it as it was -- + " enclosed in [...] + let line = '['.value.']' + endif + return line +endfunction + + +function! s:make_tag(line, regexp, func, ...) + " Make tags for a given matched regexp. + " Exclude preformatted text and href links. + " FIXME + let patt_splitter = '\(`[^`]\+`\)\|'. + \ '\('.vimwiki#vars#get_syntaxlocal('rxPreStart').'.\+'. + \ vimwiki#vars#get_syntaxlocal('rxPreEnd').'\)\|'. + \ '\(<a href.\{-}</a>\)\|'. + \ '\(<img src.\{-}/>\)\|'. + \ '\(<pre.\{-}</pre>\)\|'. + \ '\('.vimwiki#vars#get_syntaxlocal('rxEqIn').'\)' + + "FIXME FIXME !!! these can easily occur on the same line! + "XXX {{{ }}} ??? obsolete + if '`[^`]\+`' ==# a:regexp || '{{{.\+}}}' ==# a:regexp || + \ vimwiki#vars#get_syntaxlocal('rxEqIn') ==# a:regexp + let res_line = s:subst_func(a:line, a:regexp, a:func) + else + let pos = 0 + " split line with patt_splitter to have parts of line before and after + " href links, preformatted text + " ie: + " hello world `is just a` simple <a href="link.html">type of</a> prg. + " result: + " ['hello world ', ' simple ', 'type of', ' prg'] + let lines = split(a:line, patt_splitter, 1) + let res_line = "" + for line in lines + if a:0 + let res_line = res_line.s:subst_func(line, a:regexp, a:func, a:1) + else + let res_line = res_line.s:subst_func(line, a:regexp, a:func) + endif + let res_line = res_line.matchstr(a:line, patt_splitter, pos) + let pos = matchend(a:line, patt_splitter, pos) + endfor + endif + return res_line +endfunction + + +function! s:process_tags_remove_links(line) + let line = a:line + let line = s:make_tag(line, '\[\[.\{-}\]\]', 's:tag_remove_internal_link') + let line = s:make_tag(line, '\[.\{-}\]', 's:tag_remove_external_link') + return line +endfunction + + +function! s:process_tags_typefaces(line, header_ids) + let line = a:line + let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxItalic'), 's:tag_em') + let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxBold'), 's:tag_strong', a:header_ids) + let line = s:make_tag(line, vimwiki#vars#get_global('rxTodo'), 's:tag_todo') + let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxDelText'), 's:tag_strike') + let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxSuperScript'), 's:tag_super') + let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxSubScript'), 's:tag_sub') + let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxCode'), 's:tag_code') + let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxEqIn'), 's:tag_eqin') + let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxTags'), 's:tag_tags', a:header_ids) + return line +endfunction + + +function! s:process_tags_links(line) + let line = a:line + let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxWikiLink'), 's:tag_wikilink') + let line = s:make_tag(line, vimwiki#vars#get_global('rxWikiIncl'), 's:tag_wikiincl') + let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxWeblink'), 's:tag_weblink') + return line +endfunction + + +function! s:process_inline_tags(line, header_ids) + let line = s:process_tags_links(a:line) + let line = s:process_tags_typefaces(line, a:header_ids) + return line +endfunction + + +function! s:close_tag_pre(pre, ldest) + if a:pre[0] + call insert(a:ldest, "</pre>") + return 0 + endif + return a:pre +endfunction + + +function! s:close_tag_math(math, ldest) + if a:math[0] + call insert(a:ldest, "\\\]") + return 0 + endif + return a:math +endfunction + + +function! s:close_tag_quote(quote, ldest) + if a:quote + call insert(a:ldest, "</blockquote>") + return 0 + endif + return a:quote +endfunction + + +function! s:close_tag_para(para, ldest) + if a:para + call insert(a:ldest, "</p>") + return 0 + endif + return a:para +endfunction + + +function! s:close_tag_table(table, ldest, header_ids) + " The first element of table list is a string which tells us if table should be centered. + " The rest elements are rows which are lists of columns: + " ['center', + " [ CELL1, CELL2, CELL3 ], + " [ CELL1, CELL2, CELL3 ], + " [ CELL1, CELL2, CELL3 ], + " ] + " And CELLx is: { 'body': 'col_x', 'rowspan': r, 'colspan': c } + + function! s:sum_rowspan(table) + let table = a:table + + " Get max cells + let max_cells = 0 + for row in table[1:] + let n_cells = len(row) + if n_cells > max_cells + let max_cells = n_cells + end + endfor + + " Sum rowspan + for cell_idx in range(max_cells) + let rows = 1 + + for row_idx in range(len(table)-1, 1, -1) + if cell_idx >= len(table[row_idx]) + let rows = 1 + continue + endif + + if table[row_idx][cell_idx].rowspan == 0 + let rows += 1 + else " table[row_idx][cell_idx].rowspan == 1 + let table[row_idx][cell_idx].rowspan = rows + let rows = 1 + endif + endfor + endfor + endfunction + + function! s:sum_colspan(table) + for row in a:table[1:] + let cols = 1 + + for cell_idx in range(len(row)-1, 0, -1) + if row[cell_idx].colspan == 0 + let cols += 1 + else "row[cell_idx].colspan == 1 + let row[cell_idx].colspan = cols + let cols = 1 + endif + endfor + endfor + endfunction + + function! s:close_tag_row(row, header, ldest, header_ids) + call add(a:ldest, '<tr>') + + " Set tag element of columns + if a:header + let tag_name = 'th' + else + let tag_name = 'td' + end + + " Close tag of columns + for cell in a:row + if cell.rowspan == 0 || cell.colspan == 0 + continue + endif + + if cell.rowspan > 1 + let rowspan_attr = ' rowspan="' . cell.rowspan . '"' + else "cell.rowspan == 1 + let rowspan_attr = '' + endif + if cell.colspan > 1 + let colspan_attr = ' colspan="' . cell.colspan . '"' + else "cell.colspan == 1 + let colspan_attr = '' + endif + + call add(a:ldest, '<' . tag_name . rowspan_attr . colspan_attr .'>') + call add(a:ldest, s:process_inline_tags(cell.body, a:header_ids)) + call add(a:ldest, '</'. tag_name . '>') + endfor + + call add(a:ldest, '</tr>') + endfunction + + let table = a:table + let ldest = a:ldest + if len(table) + call s:sum_rowspan(table) + call s:sum_colspan(table) + + if table[0] ==# 'center' + call add(ldest, "<table class='center'>") + else + call add(ldest, "<table>") + endif + + " Empty lists are table separators. + " Search for the last empty list. All the above rows would be a table header. + " We should exclude the first element of the table list as it is a text tag + " that shows if table should be centered or not. + let head = 0 + for idx in range(len(table)-1, 1, -1) + if empty(table[idx]) + let head = idx + break + endif + endfor + if head > 0 + for row in table[1 : head-1] + if !empty(filter(row, '!empty(v:val)')) + call s:close_tag_row(row, 1, ldest, a:header_ids) + endif + endfor + for row in table[head+1 :] + call s:close_tag_row(row, 0, ldest, a:header_ids) + endfor + else + for row in table[1 :] + call s:close_tag_row(row, 0, ldest, a:header_ids) + endfor + endif + call add(ldest, "</table>") + let table = [] + endif + return table +endfunction + + +function! s:close_tag_list(lists, ldest) + while len(a:lists) + let item = remove(a:lists, 0) + call insert(a:ldest, item[0]) + endwhile +endfunction + + +function! s:close_tag_def_list(deflist, ldest) + if a:deflist + call insert(a:ldest, "</dl>") + return 0 + endif + return a:deflist +endfunction + + +function! s:process_tag_pre(line, pre) + " pre is the list of [is_in_pre, indent_of_pre] + "XXX always outputs a single line or empty list! + let lines = [] + let pre = a:pre + let processed = 0 + "XXX huh? + "if !pre[0] && a:line =~# '^\s*{{{[^\(}}}\)]*\s*$' + if !pre[0] && a:line =~# '^\s*{{{' + let class = matchstr(a:line, '{{{\zs.*$') + "FIXME class cannot contain arbitrary strings + let class = substitute(class, '\s\+$', '', 'g') + if class != "" + call add(lines, "<pre ".class.">") + else + call add(lines, "<pre>") + endif + let pre = [1, len(matchstr(a:line, '^\s*\ze{{{'))] + let processed = 1 + elseif pre[0] && a:line =~# '^\s*}}}\s*$' + let pre = [0, 0] + call add(lines, "</pre>") + let processed = 1 + elseif pre[0] + let processed = 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 + + +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) + let lines = [] + let quote = a:quote + let processed = 0 + if a:line =~# '^\s\{4,}\S' + if !quote + call add(lines, "<blockquote>") + let quote = 1 + endif + let processed = 1 + call add(lines, substitute(a:line, '^\s*', '', '')) + elseif quote + call add(lines, "</blockquote>") + let quote = 0 + endif + return [processed, lines, quote] +endfunction + + +function! s:process_tag_list(line, lists) + + function! s:add_checkbox(line, rx_list) + let st_tag = '<li>' + let chk = matchlist(a:line, a:rx_list) + 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 = '<li class="done0">' + elseif completion == -1 && chk[1] == vimwiki#vars#get_global('listsym_rejected') + let st_tag = '<li class="rejected">' + elseif completion > 0 && completion < n + let completion = float2nr(round(completion / (n-1.0) * 3.0 + 0.5 )) + let st_tag = '<li class="done'.completion.'">' + endif + endif + 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, '^\s*'.vimwiki#vars#get_syntaxlocal('rxBold')) + if pos != -1 + return [0, []] + endif + endif + + let lines = [] + let processed = 0 + + if a:line =~# '^\s*'.s:bullets.'\s' + let lstSym = matchstr(a:line, s:bullets) + let lstTagOpen = '<ul>' + let lstTagClose = '</ul>' + let lstRegExp = '^\s*'.s:bullets.'\s' + elseif a:line =~# '^\s*'.s:numbers.'\s' + let lstSym = matchstr(a:line, s:numbers) + let lstTagOpen = '<ol>' + let lstTagClose = '</ol>' + let lstRegExp = '^\s*'.s:numbers.'\s' + else + let lstSym = '' + let lstTagOpen = '' + let lstTagClose = '' + let lstRegExp = '' + endif + + if lstSym != '' + " To get proper indent level 'retab' the line -- change all tabs + " to spaces*tabstop + 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) + + if !in_list + call add(a:lists, [lstTagClose, indent]) + call add(lines, lstTagOpen) + elseif (in_list && indent > a:lists[-1][1]) + let item = remove(a:lists, -1) + call add(lines, item[0]) + + call add(a:lists, [lstTagClose, indent]) + call add(lines, lstTagOpen) + elseif (in_list && indent < a:lists[-1][1]) + while len(a:lists) && indent < a:lists[-1][1] + let item = remove(a:lists, -1) + call add(lines, item[0]) + endwhile + elseif in_list + let item = remove(a:lists, -1) + call add(lines, item[0]) + endif + + call add(a:lists, [en_tag, indent]) + call add(lines, st_tag) + call add(lines, substitute(a:line, lstRegExp.'\%('.checkbox.'\)\?', '', '')) + let processed = 1 + elseif in_list && a:line =~# '^\s\+\S\+' + if vimwiki#vars#get_global('list_ignore_newline') + call add(lines, a:line) + else + call add(lines, '<br />'.a:line) + endif + let processed = 1 + else + call s:close_tag_list(a:lists, lines) + endif + return [processed, lines] +endfunction + + +function! s:process_tag_def_list(line, deflist) + let lines = [] + let deflist = a:deflist + let processed = 0 + let matches = matchlist(a:line, '\(^.*\)::\%(\s\|$\)\(.*\)') + if !deflist && len(matches) > 0 + call add(lines, "<dl>") + let deflist = 1 + endif + if deflist && len(matches) > 0 + if matches[1] != '' + call add(lines, "<dt>".matches[1]."</dt>") + endif + if matches[2] != '' + call add(lines, "<dd>".matches[2]."</dd>") + endif + let processed = 1 + elseif deflist + let deflist = 0 + call add(lines, "</dl>") + endif + return [processed, lines, deflist] +endfunction + + +function! s:process_tag_para(line, para) + let lines = [] + let para = a:para + let processed = 0 + if a:line =~# '^\s\{,3}\S' + if !para + call add(lines, "<p>") + let para = 1 + endif + let processed = 1 + if vimwiki#vars#get_global('text_ignore_newline') + call add(lines, a:line) + else + call add(lines, a:line."<br />") + endif + elseif para && a:line =~# '^\s*$' + call add(lines, "</p>") + let para = 0 + endif + return [processed, lines, para] +endfunction + + +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 =~# vimwiki#vars#get_syntaxlocal('rxHeader') + let h_level = vimwiki#u#count_first_sym(a:line) + endif + if h_level > 0 + + 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') + + if h_text !=# vimwiki#vars#get_global('toc_header') + + 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 + + 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 = '<div id="'.h_complete_id.'">' + let h_part .= '<h'.h_level.' id="'.h_id.'" class="header">' + let h_part .= '<a href="#'.h_complete_id.'"' + + else + + let h_part = '<div id="'.h_id.'" class="toc"><h1 id="'.h_id.'"' + + endif + + if centered + let h_part .= ' class="justcenter">' + else + let h_part .= '>' + endif + + let h_text = s:process_inline_tags(h_text, a:id) + + let line = h_part.h_text.'</a></h'.h_level.'></div>' + + let processed = 1 + endif + return [processed, line] +endfunction + + +function! s:process_tag_hr(line) + let line = a:line + let processed = 0 + if a:line =~# '^-----*$' + let line = '<hr />' + let processed = 1 + endif + return [processed, line] +endfunction + + +function! s:process_tag_table(line, table, header_ids) + function! s:table_empty_cell(value) + let cell = {} + + if a:value =~# '^\s*\\/\s*$' + let cell.body = '' + let cell.rowspan = 0 + let cell.colspan = 1 + elseif a:value =~# '^\s*&gt;\s*$' + let cell.body = '' + let cell.rowspan = 1 + let cell.colspan = 0 + elseif a:value =~# '^\s*$' + let cell.body = '&nbsp;' + let cell.rowspan = 1 + let cell.colspan = 1 + else + let cell.body = a:value + let cell.rowspan = 1 + let cell.colspan = 1 + endif + + return cell + endfunction + + function! s:table_add_row(table, line) + if empty(a:table) + if a:line =~# '^\s\+' + let row = ['center', []] + else + let row = ['normal', []] + endif + else + let row = [[]] + endif + return row + endfunction + + let table = a:table + let lines = [] + let processed = 0 + + if vimwiki#tbl#is_separator(a:line) + call extend(table, s:table_add_row(a:table, a:line)) + let processed = 1 + 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, 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, a:header_ids) + endif + return [processed, lines, table] +endfunction + + +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.header_ids = a:state.header_ids + + let res_lines = [] + + 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 =~# vimwiki#vars#get_syntaxlocal('rxComment') + let processed = 1 + endif + endif + + " nohtml -- placeholder + if !processed + if line =~# '\m^\s*%nohtml\s*$' + let processed = 1 + let state.placeholder = ['nohtml'] + endif + endif + + " title -- placeholder + if !processed + if line =~# '\m^\s*%title\%(\s.*\)\?$' + let processed = 1 + let param = matchstr(line, '\m^\s*%title\s\+\zs.*') + let state.placeholder = ['title', param] + endif + endif + + " date -- placeholder + if !processed + if line =~# '\m^\s*%date\%(\s.*\)\?$' + let processed = 1 + let param = matchstr(line, '\m^\s*%date\s\+\zs.*') + let state.placeholder = ['date', param] + endif + endif + + " html template -- placeholder + if !processed + if line =~# '\m^\s*%template\%(\s.*\)\?$' + let processed = 1 + let param = matchstr(line, '\m^\s*%template\s\+\zs.*') + let state.placeholder = ['template', param] + endif + endif + + + " tables + if !processed + let [processed, lines, state.table] = s:process_tag_table(line, state.table, state.header_ids) + call extend(res_lines, lines) + endif + + + " lists + if !processed + let [processed, lines] = s:process_tag_list(line, state.lists) + if processed && state.quote + let state.quote = s:close_tag_quote(state.quote, lines) + 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 && 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.para + let state.para = s:close_tag_para(state.para, lines) + endif + + call map(lines, 's:process_inline_tags(v:val, state.header_ids)') + + call extend(res_lines, lines) + endif + + + " headers + if !processed + 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, 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) + + call add(res_lines, line) + endif + endif + + + " quotes + if !processed + let [processed, lines, state.quote] = s:process_tag_quote(line, state.quote) + if processed && len(state.lists) + call s:close_tag_list(state.lists, lines) + endif + if processed && state.deflist + 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, 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, state.header_ids)') + + call extend(res_lines, lines) + endif + + + " 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, 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 + if !processed + let [processed, lines, state.deflist] = s:process_tag_def_list(line, state.deflist) + + call map(lines, 's:process_inline_tags(v:val, state.header_ids)') + + call extend(res_lines, lines) + endif + + + "" P + if !processed + let [processed, lines, state.para] = s:process_tag_para(line, state.para) + if processed && len(state.lists) + call s:close_tag_list(state.lists, lines) + endif + if processed && state.quote + let state.quote = s:close_tag_quote(state.quote, res_lines) + endif + 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, state.header_ids) + endif + + call map(lines, 's:process_inline_tags(v:val, state.header_ids)') + + call extend(res_lines, lines) + endif + + + "" add the rest + if !processed + call add(res_lines, line) + endif + + return [res_lines, state] + +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 path_html = expand(a:path_html).vimwiki#vars#get_bufferlocal('subdir') + let htmlfile = fnamemodify(wikifile, ":t:r").'.html' + + " 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 + + if s:use_custom_wiki2html() + let force = 1 + call vimwiki#html#CustomWiki2HTML(path_html, wikifile, force) + let done = 1 + endif + + 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 + + " prepare regexps for lists + let s:bullets = '[*-]' + let s:numbers = '\C\%(#\|\d\+)\|\d\+\.\|[ivxlcdm]\+)\|[IVXLCDM]\+)\|\l\{1,2})\|\u\{1,2})\)' + + 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)]) + endif + let state.placeholder = [] + endif + + 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) + + let title = s:process_title(placeholders, fnamemodify(a:wikifile, ":t:r")) + let date = s:process_date(placeholders, strftime('%Y-%m-%d')) + + let html_lines = s:get_html_template(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, "%date%", "'. date .'", "g")') + call map(html_lines, 'substitute(v:val, "%root_path%", "'. + \ s:root_path(vimwiki#vars#get_bufferlocal('subdir')) .'", "g")') + + 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 + + return path_html.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_html) + if !s:syntax_supported() && !s:use_custom_wiki2html() + echomsg 'Vimwiki Error: Conversion to HTML is not supported for this syntax' + return + endif + + echomsg 'Vimwiki: Saving Vimwiki files ...' + let save_eventignore = &eventignore + let &eventignore = "all" + try + wall + catch + " just ignore errors + endtry + let &eventignore = save_eventignore + + let path_html = expand(a:path_html) + call vimwiki#path#mkdir(path_html) + + echomsg 'Vimwiki: Deleting non-wiki html files ...' + call s:delete_html_files(path_html) + + echomsg 'Vimwiki: Converting wiki to html files ...' + let setting_more = &more + setlocal nomore + + " 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 'Vimwiki: Processing '.wikifile + + call s:convert_file(path_html, wikifile) + else + echomsg 'Vimwiki: Skipping '.wikifile + endif + endfor + " 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 + + +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/.config/nvim/autoload/vimwiki/lst.vim b/.config/nvim/autoload/vimwiki/lst.vim @@ -0,0 +1,1697 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki autoload plugin file +" 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_list_auto = 1 + + +" --------------------------------------------------------- +" incrementation functions for the various kinds of numbers +" --------------------------------------------------------- + +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 + return list_margin + endif +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 + + +"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 + + +"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 + + endif + 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 + 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 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 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 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 + + 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: 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 cur_item.lnum > line('$') || cur_item.lnum <= 0 || s:get_level(cur_item.lnum) <= org_lvl + return s:empty_item() + endif + 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 + endwhile + 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 s:empty_item() +endfunction + + +"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 + 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 + + +"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 cur_ln = next_line + endwhile +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 + + 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 + + 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 + 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 + + +"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 +endfunction + + +" 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 retain_closed_children = 1 + endif + + let child_item = s:get_first_child(a:item) + while 1 + if child_item.type == 0 + break + endif + 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 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 + + 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 +endfunction + + +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 + + +"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 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 + + +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 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 + + +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 + + call s:update_state(s:get_parent(first_item)) +endfunction + + + +" --------------------------------------------------------- +" 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 + call s:substitute_rx_in_line(a:lnum, '^\s*', indentstring) +endfunction + + +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 + + +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 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 + + +"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 + + +"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 + 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 + + +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 + + +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! gix + 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 <CR> + 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/.config/nvim/autoload/vimwiki/markdown_base.vim b/.config/nvim/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/.config/nvim/autoload/vimwiki/path.vim b/.config/nvim/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/.config/nvim/autoload/vimwiki/style.css b/.config/nvim/autoload/vimwiki/style.css @@ -0,0 +1,83 @@ +body {font-family: Tahoma, Geneva, sans-serif; margin: 1em 2em 1em 2em; font-size: 100%; line-height: 130%;} +h1, h2, h3, h4, h5, h6 {font-family: Trebuchet MS, Helvetica, sans-serif; font-weight: bold; line-height:100%; margin-top: 1.5em; margin-bottom: 0.5em;} +h1 {font-size: 2.6em; color: #000000;} +h2 {font-size: 2.2em; color: #404040;} +h3 {font-size: 1.8em; color: #707070;} +h4 {font-size: 1.4em; color: #909090;} +h5 {font-size: 1.3em; color: #989898;} +h6 {font-size: 1.2em; color: #9c9c9c;} +p, pre, blockquote, table, ul, ol, dl {margin-top: 1em; margin-bottom: 1em;} +ul ul, ul ol, ol ol, ol ul {margin-top: 0.5em; margin-bottom: 0.5em;} +li {margin: 0.3em auto;} +ul {margin-left: 2em; padding-left: 0.5em;} +dt {font-weight: bold;} +img {border: none;} +pre {border-left: 1px solid #ccc; margin-left: 2em; padding-left: 0.5em;} +blockquote {padding: 0.4em; background-color: #f6f5eb;} +th, td {border: 1px solid #ccc; padding: 0.3em;} +th {background-color: #f0f0f0;} +hr {border: none; border-top: 1px solid #ccc; width: 100%;} +del {text-decoration: line-through; color: #777777;} +.toc li {list-style-type: none;} +.todo {font-weight: bold; background-color: #f0ece8; color: #a03020;} +.justleft {text-align: left;} +.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 */ +.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/.config/nvim/autoload/vimwiki/tags.vim b/.config/nvim/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/.config/nvim/autoload/vimwiki/tbl.vim b/.config/nvim/autoload/vimwiki/tbl.vim @@ -0,0 +1,703 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki autoload plugin file +" Description: Tables +" | Easily | manageable | text | tables | ! | +" |--------|------------|-------|--------|---------| +" | Have | fun! | Drink | tea | Period. | +" +" Home: https://github.com/vimwiki/vimwiki/ + + + +if exists("g:loaded_vimwiki_tbl_auto") || &cp + finish +endif +let g:loaded_vimwiki_tbl_auto = 1 + + +let s:textwidth = &tw + + +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 !vimwiki#vars#get_global('CJK_length') + let ret = strlen(substitute(a:str, '.', 'x', 'g')) + else + let savemodified = &modified + let save_cursor = getpos('.') + exe "norm! o\<esc>" + call setline(line("."), a:str) + let ret = virtcol("$") - 1 + d + call setpos('.', save_cursor) + let &modified = savemodified + endif + return ret +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_separator_tail(line) + return a:line =~# '^\{-1}\%(\s*\|-*\)\%('.s:rxSep().'-\+\)\+'.s:rxSep().'\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) + let line = strpart(getline(a:lnum), 0, a:cnum - 1) + return line =~# '^\s*$' || + \ (line =~# '^\s*'.s:rxSep() && line !~# '^\s*'.s:rxSep().'.*'.s:rxSep()) +endfunction + + +function! s:count_separators_up(lnum) + let lnum = a:lnum - 1 + while lnum > 1 + if !s:is_separator(getline(lnum)) + break + endif + let lnum -= 1 + endwhile + + return (a:lnum-lnum) +endfunction + + +function! s:count_separators_down(lnum) + let lnum = a:lnum + 1 + while lnum < line('$') + if !s:is_separator(getline(lnum)) + break + endif + let lnum += 1 + endwhile + + return (lnum-a:lnum) +endfunction + + +function! s:create_empty_row(cols) + let row = s:rxSep() + let cell = " ".s:rxSep() + + for c in range(a:cols) + let row .= cell + endfor + + return row +endfunction + + +function! s:create_row_sep(cols) + let row = s:rxSep() + let cell = "---".s:rxSep() + + for c in range(a:cols) + let row .= cell + endfor + + return row +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 + + if cell.quote != '' + call add(result, vimwiki#u#trim(cell.quote, '|')) + endif + return result +endfunction + + +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 + + let indent = 0 + + let lnum = a:lnum - 1 + while lnum > 1 + let line = getline(lnum) + if !s:is_table(line) + let indent = indent(lnum+1) + break + endif + let lnum -= 1 + endwhile + + return indent +endfunction + + +function! s:get_rows(lnum) + if !s:is_table(getline(a:lnum)) + return + endif + + let upper_rows = [] + let lower_rows = [] + + let lnum = a:lnum - 1 + while lnum >= 1 + let line = getline(lnum) + if s:is_table(line) + call add(upper_rows, [lnum, line]) + else + break + endif + let lnum -= 1 + endwhile + call reverse(upper_rows) + + let lnum = a:lnum + while lnum <= line('$') + let line = getline(lnum) + if s:is_table(line) + call add(lower_rows, [lnum, line]) + else + break + endif + let lnum += 1 + endwhile + + return upper_rows + lower_rows +endfunction + + +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 = 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) + let max_lens[idx] = max([s:wide_len(value), max_lens[idx]]) + else + let max_lens[idx] = s:wide_len(value) + endif + endfor + endfor + return max_lens +endfunction + + +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(cells[lnum - startlnum], max_lens, a:col1, a:col2) + endif + call add(result, [lnum, new_row]) + endfor + return result +endfunction + + +" Number of the current column. Starts from 0. +function! s:cur_column() + let line = getline('.') + if !s:is_table(line) + return -1 + endif + " TODO: do we need conditional: if s:is_separator(line) + + let curs_pos = col('.') + let mpos = match(line, s:rxSep(), 0) + let col = -1 + while mpos < curs_pos && mpos != -1 + let mpos = match(line, s:rxSep(), mpos+1) + if mpos != -1 + let col += 1 + endif + endwhile + return col +endfunction + + +function! s:fmt_cell(cell, max_len) + let cell = ' '.a:cell.' ' + + let diff = a:max_len - s:wide_len(a:cell) + if diff == 0 && empty(a:cell) + let diff = 1 + endif + + let cell .= repeat(' ', diff) + return cell +endfunction + + +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 = a:cells[idx] + let new_line .= s:fmt_cell(value, a:max_lens[idx]).s:rxSep() + endfor + + let idx = len(a:cells) + while idx < len(a:max_lens) + let new_line .= s:fmt_cell('', a:max_lens[idx]).s:rxSep() + let idx += 1 + endwhile + return new_line +endfunction + + +function! s:fmt_cell_sep(max_len) + if a:max_len == 0 + return repeat('-', 3) + else + return repeat('-', a:max_len+2) + endif +endfunction + + +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 new_line .= s:fmt_cell_sep(a:max_lens[idx]).s:rxSep() + endfor + return new_line +endfunction + + +function! s:kbd_create_new_row(cols, goto_first) + let cmd = "\<ESC>o".s:create_empty_row(a:cols) + let cmd .= "\<ESC>:call vimwiki#tbl#format(line('.'))\<CR>" + let cmd .= "\<ESC>0" + if a:goto_first + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'c', line('.'))\<CR>" + else + let cmd .= (col('.')-1)."l" + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\<CR>" + endif + let cmd .= "a" + + return cmd +endfunction + + +function! s:kbd_goto_next_row() + let cmd = "\<ESC>j" + let cmd .= ":call search('.\\(".s:rxSep()."\\)', 'c', line('.'))\<CR>" + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\<CR>" + let cmd .= "a" + return cmd +endfunction + + +function! s:kbd_goto_prev_row() + let cmd = "\<ESC>k" + let cmd .= ":call search('.\\(".s:rxSep()."\\)', 'c', line('.'))\<CR>" + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\<CR>" + let cmd .= "a" + return cmd +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 |<space>...<space> + endfor + let newcol += 2 " +2 == 1 separator + 1 space |<space + call vimwiki#u#cursor(lnum, newcol) +endfunction + + +function! s:kbd_goto_next_col(jumpdown) + let cmd = "\<ESC>" + if a:jumpdown + let seps = s:count_separators_down(line('.')) + let cmd .= seps."j0" + endif + let cmd .= ":call vimwiki#tbl#goto_next_col()\<CR>a" + return cmd +endfunction + + +" 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 |<space>...<space> + if newcol + delta > curcol-1 + let newcol -= (prev_cell_len + 3) " +3 == 2 spaces + 1 separator |<space>...<space> + 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 |<space + call vimwiki#u#cursor(lnum, newcol) +endfunction + + +function! s:kbd_goto_prev_col(jumpup) + let cmd = "\<ESC>" + if a:jumpup + let seps = s:count_separators_up(line('.')) + let cmd .= seps."k" + let cmd .= "$" + endif + let cmd .= ":call vimwiki#tbl#goto_prev_col()\<CR>a" + " let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'b', line('.'))\<CR>" + " let cmd .= "a" + "echomsg "DEBUG kbd_goto_prev_col> ".cmd + return cmd +endfunction + + +function! vimwiki#tbl#kbd_cr() + let lnum = line('.') + if !s:is_table(getline(lnum)) + return "" + endif + + if s:is_separator(getline(lnum+1)) || !s:is_table(getline(lnum+1)) + 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 + + +function! vimwiki#tbl#kbd_tab() + let lnum = line('.') + if !s:is_table(getline(lnum)) + return "\<Tab>" + endif + + let last = s:is_last_column(lnum, col('.')) + 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(is_sep || last) +endfunction + + +function! vimwiki#tbl#kbd_shift_tab() + let lnum = line('.') + if !s:is_table(getline(lnum)) + return "\<S-Tab>" + endif + + let first = s:is_first_column(lnum, col('.')) + 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(is_sep || first) +endfunction + + +function! vimwiki#tbl#format(lnum, ...) + if !(&filetype ==? 'vimwiki') + return + endif + let line = getline(a:lnum) + if !s:is_table(line) + return + endif + + if a:0 == 2 + let col1 = a:1 + let col2 = a:2 + else + let col1 = 0 + let col2 = 0 + 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 = indentstring.row + call setline(lnum, row) + endfor + + let &tw = s:textwidth +endfunction + + +function! vimwiki#tbl#create(...) + if a:0 > 1 + let cols = a:1 + let rows = a:2 + elseif a:0 == 1 + let cols = a:1 + let rows = 2 + elseif a:0 == 0 + let cols = 5 + let rows = 2 + endif + + if cols < 1 + let cols = 5 + endif + + if rows < 1 + let rows = 2 + endif + + let lines = [] + let row = s:create_empty_row(cols) + + call add(lines, row) + if rows > 1 + call add(lines, s:create_row_sep(cols)) + endif + + for r in range(rows - 1) + call add(lines, row) + endfor + + call append(line('.'), lines) +endfunction + + +function! vimwiki#tbl#align_or_cmd(cmd) + if s:is_table(getline('.')) + call vimwiki#tbl#format(line('.')) + else + exe 'normal! '.a:cmd + endif +endfunction + + +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 + + +" TODO: move_column_left and move_column_right are good candidates to be refactored. +function! vimwiki#tbl#move_column_left() + + "echomsg "DEBUG move_column_left: " + + let line = getline('.') + + if !s:is_table(line) + return + endif + + let cur_col = s:cur_column() + if cur_col == -1 + return + endif + + if cur_col > 0 + call vimwiki#tbl#format(line('.'), cur_col-1, cur_col) + call cursor(line('.'), 1) + + 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 + + +function! vimwiki#tbl#move_column_right() + + let line = getline('.') + + if !s:is_table(line) + return + endif + + let cur_col = s:cur_column() + if cur_col == -1 + return + endif + + if cur_col < s:col_count(line('.'))-1 + call vimwiki#tbl#format(line('.'), cur_col, cur_col+1) + call cursor(line('.'), 1) + + 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 + + +function! vimwiki#tbl#get_rows(lnum) + return s:get_rows(a:lnum) +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/.config/nvim/autoload/vimwiki/u.vim b/.config/nvim/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/.config/nvim/autoload/vimwiki/vars.vim b/.config/nvim/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 <leader>w<leader>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 <CR> 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': '<Leader>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_<option> into the dict + " g:vimwiki_global_vars (or set a default value) + for key in keys(global_settings) + if exists('g:vimwiki_'.key) + let users_value = g:vimwiki_{key} + let value_infos = global_settings[key] + + call s:check_users_value(key, users_value, value_infos, 1) + + let g:vimwiki_global_vars[key] = users_value + else + let g:vimwiki_global_vars[key] = global_settings[key].default + endif + endfor + + " validate some settings individually + + let key = 'diary_months' + let users_value = g:vimwiki_global_vars[key] + for month in range(1, 12) + if !has_key(users_value, month) || type(users_value[month]) != type('') || + \ empty(users_value[month]) + echom printf('Vimwiki Error: The provided value ''%s'' of the option ''g:vimwiki_%s'' is' + \ . ' invalid. See '':h g:vimwiki_%s''.', string(users_value), key, key) + break + endif + endfor + + let key = 'ext2syntax' + let users_value = g:vimwiki_global_vars[key] + for ext in keys(users_value) + if empty(ext) || index(['markdown', 'media', 'mediawiki', 'default'], users_value[ext]) == -1 + echom printf('Vimwiki Error: The provided value ''%s'' of the option ''g:vimwiki_%s'' is' + \ . ' invalid. See '':h g:vimwiki_%s''.', string(users_value), key, key) + break + endif + endfor + +endfunction + + +function! s:normalize_global_settings() + let keys = keys(g:vimwiki_global_vars.ext2syntax) + for ext in keys + " ensure the file extensions in ext2syntax start with a dot + if ext[0] != '.' + let new_ext = '.' . ext + let g:vimwiki_global_vars.ext2syntax[new_ext] = g:vimwiki_global_vars.ext2syntax[ext] + call remove(g:vimwiki_global_vars.ext2syntax, ext) + endif + " for convenience, we also allow the term 'mediawiki' + if g:vimwiki_global_vars.ext2syntax[ext] ==# 'mediawiki' + let g:vimwiki_global_vars.ext2syntax[ext] = 'media' + endif + endfor +endfunction + + +function! s:populate_wikilocal_options() + let default_values = { + \ 'auto_diary_index': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'auto_export': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'auto_tags': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'auto_toc': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'automatic_nested_syntaxes': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, + \ 'css_name': {'type': type(''), 'default': 'style.css', 'min_length': 1}, + \ 'custom_wiki2html': {'type': type(''), 'default': ''}, + \ 'custom_wiki2html_args': {'type': type(''), 'default': ''}, + \ 'diary_header': {'type': type(''), 'default': 'Diary', 'min_length': 1}, + \ 'diary_index': {'type': type(''), 'default': 'diary', 'min_length': 1}, + \ 'diary_rel_path': {'type': type(''), 'default': 'diary/', 'min_length': 1}, + \ 'diary_sort': {'type': type(''), 'default': 'desc', 'possible_values': ['asc', 'desc']}, + \ 'ext': {'type': type(''), 'default': '.wiki', 'min_length': 1}, + \ 'index': {'type': type(''), 'default': 'index', 'min_length': 1}, + \ 'list_margin': {'type': type(0), 'default': -1, 'min': -1}, + \ 'maxhi': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'nested_syntaxes': {'type': type({}), 'default': {}}, + \ 'path': {'type': type(''), 'default': $HOME . '/vimwiki/', 'min_length': 1}, + \ 'path_html': {'type': type(''), 'default': ''}, + \ 'syntax': {'type': type(''), 'default': 'default', + \ 'possible_values': ['default', 'markdown', 'media', 'mediawiki']}, + \ 'template_default': {'type': type(''), 'default': 'default', 'min_length': 1}, + \ 'template_ext': {'type': type(''), 'default': '.tpl'}, + \ 'template_path': {'type': type(''), 'default': $HOME . '/vimwiki/templates/'}, + \ } + + let g:vimwiki_wikilocal_vars = [] + + let default_wiki_settings = {} + for key in keys(default_values) + if exists('g:vimwiki_'.key) + call s:check_users_value(key, g:vimwiki_{key}, default_values[key], 1) + let default_wiki_settings[key] = g:vimwiki_{key} + else + let default_wiki_settings[key] = default_values[key].default + endif + endfor + + " set the wiki-local variables according to g:vimwiki_list (or the default settings) + if exists('g:vimwiki_list') + for users_wiki_settings in g:vimwiki_list + let new_wiki_settings = {} + for key in keys(default_values) + if has_key(users_wiki_settings, key) + call s:check_users_value(key, users_wiki_settings[key], default_values[key], 0) + let new_wiki_settings[key] = users_wiki_settings[key] + else + let new_wiki_settings[key] = default_wiki_settings[key] + endif + endfor + + let new_wiki_settings.is_temporary_wiki = 0 + + call add(g:vimwiki_wikilocal_vars, new_wiki_settings) + endfor + else + " if the user hasn't registered any wiki, we register one wiki using the default values + let new_wiki_settings = deepcopy(default_wiki_settings) + let new_wiki_settings.is_temporary_wiki = 0 + call add(g:vimwiki_wikilocal_vars, new_wiki_settings) + endif + + " default values for temporary wikis + let temporary_wiki_settings = deepcopy(default_wiki_settings) + let temporary_wiki_settings.is_temporary_wiki = 1 + call add(g:vimwiki_wikilocal_vars, temporary_wiki_settings) + + " check some values individually + let key = 'nested_syntaxes' + for wiki_settings in g:vimwiki_wikilocal_vars + let users_value = wiki_settings[key] + for keyword in keys(users_value) + if type(keyword) != type('') || empty(keyword) || type(users_value[keyword]) != type('') || + \ empty(users_value[keyword]) + echom printf('Vimwiki Error: The provided value ''%s'' of the option ''g:vimwiki_%s'' is' + \ . ' invalid. See '':h g:vimwiki_%s''.', string(users_value), key, key) + break + endif + endfor + endfor + + call s:normalize_wikilocal_settings() +endfunction + + +function! s:check_users_value(key, users_value, value_infos, comes_from_global_variable) + let type_code_to_name = { + \ type(0): 'number', + \ type(''): 'string', + \ type([]): 'list', + \ type({}): 'dictionary'} + + let setting_origin = a:comes_from_global_variable ? + \ printf('''g:vimwiki_%s''', a:key) : + \ printf('''%s'' in g:vimwiki_list', a:key) + + if has_key(a:value_infos, 'type') && type(a:users_value) != a:value_infos.type + echom printf('Vimwiki Error: The provided value of the option %s is a %s, ' . + \ 'but expected is a %s. See '':h g:vimwiki_%s''.', setting_origin, + \ type_code_to_name[type(a:users_value)], type_code_to_name[a:value_infos.type], a:key) + endif + + if a:value_infos.type == type(0) && has_key(a:value_infos, 'min') && + \ a:users_value < a:value_infos.min + echom printf('Vimwiki Error: The provided value ''%i'' of the option %s is' + \ . ' too small. The minimum value is %i. See '':h g:vimwiki_%s''.', a:users_value, + \ setting_origin, a:value_infos.min, a:key) + endif + + if a:value_infos.type == type(0) && has_key(a:value_infos, 'max') && + \ a:users_value > a:value_infos.max + echom printf('Vimwiki Error: The provided value ''%i'' of the option %s is' + \ . ' too large. The maximum value is %i. See '':h g:vimwiki_%s''.', a:users_value, + \ setting_origin, a:value_infos.max, a:key) + endif + + if has_key(a:value_infos, 'possible_values') && + \ index(a:value_infos.possible_values, a:users_value) == -1 + echom printf('Vimwiki Error: The provided value ''%s'' of the option %s is' + \ . ' invalid. Allowed values are %s. See ''g:vimwiki_%s''.', a:users_value, + \ setting_origin, string(a:value_infos.possible_values), a:key) + endif + + if a:value_infos.type == type('') && has_key(a:value_infos, 'length') && + \ strwidth(a:users_value) != a:value_infos.length + echom printf('Vimwiki Error: The provided value ''%s'' of the option %s must' + \ . ' contain exactly %i character(s) but has %i. See '':h g:vimwiki_%s''.', + \ a:users_value, setting_origin, a:value_infos.length, strwidth(a:users_value), a:key) + endif + + if a:value_infos.type == type('') && has_key(a:value_infos, 'min_length') && + \ strwidth(a:users_value) < a:value_infos.min_length + echom printf('Vimwiki Error: The provided value ''%s'' of the option %s must' + \ . ' have at least %d character(s) but has %d. See '':h g:vimwiki_%s''.', a:users_value, + \ setting_origin, a:value_infos.min_length, strwidth(a:users_value), a:key) + endif +endfunction + + +function! s:normalize_wikilocal_settings() + for wiki_settings in g:vimwiki_wikilocal_vars + let wiki_settings['path'] = s:normalize_path(wiki_settings['path']) + + let path_html = wiki_settings['path_html'] + if !empty(path_html) + let wiki_settings['path_html'] = s:normalize_path(path_html) + else + let wiki_settings['path_html'] = s:normalize_path( + \ substitute(wiki_settings['path'], '[/\\]\+$', '', '').'_html/') + endif + + let wiki_settings['template_path'] = s:normalize_path(wiki_settings['template_path']) + let wiki_settings['diary_rel_path'] = s:normalize_path(wiki_settings['diary_rel_path']) + + let ext = wiki_settings['ext'] + if !empty(ext) && ext[0] != '.' + let wiki_settings['ext'] = '.' . ext + endif + + " for convenience, we also allow the term 'mediawiki' + if wiki_settings.syntax ==# 'mediawiki' + let wiki_settings.syntax = 'media' + endif + endfor +endfunction + + +function! s:normalize_path(path) + " trim trailing / and \ because otherwise resolve() doesn't work quite right + let path = substitute(a:path, '[/\\]\+$', '', '') + if path !~# '^scp:' + return resolve(expand(path)).'/' + else + return path.'/' + endif +endfunction + + +function! vimwiki#vars#populate_syntax_vars(syntax) + if !exists('g:vimwiki_syntax_variables') + let g:vimwiki_syntax_variables = {} + endif + + if has_key(g:vimwiki_syntax_variables, a:syntax) + return + endif + + let g:vimwiki_syntax_variables[a:syntax] = {} + + execute 'runtime! syntax/vimwiki_'.a:syntax.'.vim' + + " generic stuff + let header_symbol = g:vimwiki_syntax_variables[a:syntax].rxH + if g:vimwiki_syntax_variables[a:syntax].symH + " symmetric headers + for i in range(1,6) + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Template'] = + \ repeat(header_symbol, i).' __Header__ '.repeat(header_symbol, i) + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i] = + \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*[^'.header_symbol.']' + \ .header_symbol.'\{'.i.'}\s*$' + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Start'] = + \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*[^'.header_symbol.']' + \ .header_symbol.'\{'.i.'}\s*$' + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_End'] = + \ '^\s*'.header_symbol.'\{1,'.i.'}[^'.header_symbol.'].*[^'.header_symbol.']' + \ .header_symbol.'\{1,'.i.'}\s*$' + endfor + let g:vimwiki_syntax_variables[a:syntax].rxHeader = + \ '^\s*\('.header_symbol.'\{1,6}\)\zs[^'.header_symbol.'].*[^'.header_symbol.']\ze\1\s*$' + else + " asymmetric + for i in range(1,6) + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Template'] = + \ repeat(header_symbol, i).' __Header__' + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i] = + \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*$' + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Start'] = + \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*$' + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_End'] = + \ '^\s*'.header_symbol.'\{1,'.i.'}[^'.header_symbol.'].*$' + endfor + let g:vimwiki_syntax_variables[a:syntax].rxHeader = + \ '^\s*\('.header_symbol.'\{1,6}\)\zs[^'.header_symbol.'].*\ze$' + endif + + let g:vimwiki_syntax_variables[a:syntax].rxPreStart = + \ '^\s*'.g:vimwiki_syntax_variables[a:syntax].rxPreStart + let g:vimwiki_syntax_variables[a:syntax].rxPreEnd = + \ '^\s*'.g:vimwiki_syntax_variables[a:syntax].rxPreEnd.'\s*$' + + let g:vimwiki_syntax_variables[a:syntax].rxMathStart = + \ '^\s*'.g:vimwiki_syntax_variables[a:syntax].rxMathStart + let g:vimwiki_syntax_variables[a:syntax].rxMathEnd = + \ '^\s*'.g:vimwiki_syntax_variables[a:syntax].rxMathEnd.'\s*$' + + " list stuff + let g:vimwiki_syntax_variables[a:syntax].rx_bullet_chars = + \ '['.join(g:vimwiki_syntax_variables[a:syntax].bullet_types, '').']\+' + + let g:vimwiki_syntax_variables[a:syntax].multiple_bullet_chars = + \ g:vimwiki_syntax_variables[a:syntax].recurring_bullets + \ ? g:vimwiki_syntax_variables[a:syntax].bullet_types : [] + + let g:vimwiki_syntax_variables[a:syntax].number_kinds = [] + let g:vimwiki_syntax_variables[a:syntax].number_divisors = '' + for i in g:vimwiki_syntax_variables[a:syntax].number_types + call add(g:vimwiki_syntax_variables[a:syntax].number_kinds, i[0]) + let g:vimwiki_syntax_variables[a:syntax].number_divisors .= vimwiki#u#escape(i[1]) + endfor + + let char_to_rx = {'1': '\d\+', 'i': '[ivxlcdm]\+', 'I': '[IVXLCDM]\+', + \ 'a': '\l\{1,2}', 'A': '\u\{1,2}'} + + "create regexp for bulleted list items + if !empty(g:vimwiki_syntax_variables[a:syntax].bullet_types) + let g:vimwiki_syntax_variables[a:syntax].rxListBullet = + \ join( map(copy(g:vimwiki_syntax_variables[a:syntax].bullet_types), + \'vimwiki#u#escape(v:val).' + \ .'repeat("\\+", g:vimwiki_syntax_variables[a:syntax].recurring_bullets)' + \ ) , '\|') + else + "regex that matches nothing + let g:vimwiki_syntax_variables[a:syntax].rxListBullet = '$^' + endif + + "create regex for numbered list items + if !empty(g:vimwiki_syntax_variables[a:syntax].number_types) + let g:vimwiki_syntax_variables[a:syntax].rxListNumber = '\C\%(' + for type in g:vimwiki_syntax_variables[a:syntax].number_types[:-2] + let g:vimwiki_syntax_variables[a:syntax].rxListNumber .= char_to_rx[type[0]] . + \ vimwiki#u#escape(type[1]) . '\|' + endfor + let g:vimwiki_syntax_variables[a:syntax].rxListNumber .= + \ char_to_rx[g:vimwiki_syntax_variables[a:syntax].number_types[-1][0]]. + \ vimwiki#u#escape(g:vimwiki_syntax_variables[a:syntax].number_types[-1][1]) . '\)' + else + "regex that matches nothing + let g:vimwiki_syntax_variables[a:syntax].rxListNumber = '$^' + endif + + "the user can set the listsyms as string, but vimwiki needs a list + let g:vimwiki_syntax_variables[a:syntax].listsyms_list = + \ split(vimwiki#vars#get_global('listsyms'), '\zs') + if match(vimwiki#vars#get_global('listsyms'), vimwiki#vars#get_global('listsym_rejected')) != -1 + echomsg 'Vimwiki Warning: the value of g:vimwiki_listsym_rejected (''' + \ . vimwiki#vars#get_global('listsym_rejected') + \ . ''') must not be a part of g:vimwiki_listsyms (''' . + \ . vimwiki#vars#get_global('listsyms') . ''')' + endif + let g:vimwiki_syntax_variables[a:syntax].rxListItemWithoutCB = + \ '^\s*\%(\('.g:vimwiki_syntax_variables[a:syntax].rxListBullet.'\)\|\(' + \ .g:vimwiki_syntax_variables[a:syntax].rxListNumber.'\)\)\s' + let g:vimwiki_syntax_variables[a:syntax].rxListItem = + \ g:vimwiki_syntax_variables[a:syntax].rxListItemWithoutCB + \ . '\+\%(\[\(['.vimwiki#vars#get_global('listsyms') + \ . vimwiki#vars#get_global('listsym_rejected').']\)\]\s\)\?' + if g:vimwiki_syntax_variables[a:syntax].recurring_bullets + let g:vimwiki_syntax_variables[a:syntax].rxListItemAndChildren = + \ '^\('.g:vimwiki_syntax_variables[a:syntax].rxListBullet.'\)\s\+\[[' + \ . g:vimwiki_syntax_variables[a:syntax].listsyms_list[-1] + \ . vimwiki#vars#get_global('listsym_rejected') . ']\]\s.*\%(\n\%(\1\%(' + \ .g:vimwiki_syntax_variables[a:syntax].rxListBullet.'\).*\|^$\|\s.*\)\)*' + else + let g:vimwiki_syntax_variables[a:syntax].rxListItemAndChildren = + \ '^\(\s*\)\%('.g:vimwiki_syntax_variables[a:syntax].rxListBullet.'\|' + \ . g:vimwiki_syntax_variables[a:syntax].rxListNumber.'\)\s\+\[[' + \ . g:vimwiki_syntax_variables[a:syntax].listsyms_list[-1] + \ . vimwiki#vars#get_global('listsym_rejected') . ']\]\s.*\%(\n\%(\1\s.*\|^$\)\)*' + endif + + " 0. URL : free-standing links: keep URL UR(L) strip trailing punct: URL; URL) UR(L)) + " let g:vimwiki_rxWeblink = '[\["(|]\@<!'. g:vimwiki_rxWeblinkUrl . + " \ '\%([),:;.!?]\=\%([ \t]\|$\)\)\@=' + let g:vimwiki_syntax_variables[a:syntax].rxWeblink = + \ '\<'. g:vimwiki_global_vars.rxWeblinkUrl . '\S*' + " 0a) match URL within URL + let g:vimwiki_syntax_variables[a:syntax].rxWeblinkMatchUrl = + \ g:vimwiki_syntax_variables[a:syntax].rxWeblink + " 0b) match DESCRIPTION within URL + let g:vimwiki_syntax_variables[a:syntax].rxWeblinkMatchDescr = '' + + " template for matching all wiki links with a given target file + let g:vimwiki_syntax_variables[a:syntax].WikiLinkMatchUrlTemplate = + \ g:vimwiki_global_vars.rx_wikilink_prefix . + \ '\zs__LinkUrl__\ze\%(#.*\)\?' . + \ g:vimwiki_global_vars.rx_wikilink_suffix . + \ '\|' . + \ g:vimwiki_global_vars.rx_wikilink_prefix . + \ '\zs__LinkUrl__\ze\%(#.*\)\?' . + \ g:vimwiki_global_vars.rx_wikilink_separator . + \ '.*' . + \ g:vimwiki_global_vars.rx_wikilink_suffix + + " a) match [[URL|DESCRIPTION]] + let g:vimwiki_syntax_variables[a:syntax].rxWikiLink = g:vimwiki_global_vars.rx_wikilink_prefix. + \ g:vimwiki_global_vars.rxWikiLinkUrl.'\%('.g:vimwiki_global_vars.rx_wikilink_separator. + \ g:vimwiki_global_vars.rxWikiLinkDescr.'\)\?'.g:vimwiki_global_vars.rx_wikilink_suffix + let g:vimwiki_syntax_variables[a:syntax].rxAnyLink = + \ g:vimwiki_syntax_variables[a:syntax].rxWikiLink.'\|'. + \ g:vimwiki_global_vars.rxWikiIncl.'\|'.g:vimwiki_syntax_variables[a:syntax].rxWeblink + " b) match URL within [[URL|DESCRIPTION]] + let g:vimwiki_syntax_variables[a:syntax].rxWikiLinkMatchUrl = + \ g:vimwiki_global_vars.rx_wikilink_prefix . '\zs'. g:vimwiki_global_vars.rxWikiLinkUrl + \ .'\ze\%('. g:vimwiki_global_vars.rx_wikilink_separator + \ . g:vimwiki_global_vars.rxWikiLinkDescr.'\)\?'.g:vimwiki_global_vars.rx_wikilink_suffix + " c) match DESCRIPTION within [[URL|DESCRIPTION]] + let g:vimwiki_syntax_variables[a:syntax].rxWikiLinkMatchDescr = + \ g:vimwiki_global_vars.rx_wikilink_prefix . g:vimwiki_global_vars.rxWikiLinkUrl + \ . g:vimwiki_global_vars.rx_wikilink_separator.'\%(\zs' + \ . g:vimwiki_global_vars.rxWikiLinkDescr. '\ze\)\?' + \ . g:vimwiki_global_vars.rx_wikilink_suffix + + if a:syntax ==# 'markdown' + call s:populate_extra_markdown_vars() + endif +endfunction + + +function! s:populate_extra_markdown_vars() + let mkd_syntax = g:vimwiki_syntax_variables['markdown'] + + " 0a) match [[URL|DESCRIPTION]] + let mkd_syntax.rxWikiLink0 = mkd_syntax.rxWikiLink + " 0b) match URL within [[URL|DESCRIPTION]] + let mkd_syntax.rxWikiLink0MatchUrl = mkd_syntax.rxWikiLinkMatchUrl + " 0c) match DESCRIPTION within [[URL|DESCRIPTION]] + let mkd_syntax.rxWikiLink0MatchDescr = mkd_syntax.rxWikiLinkMatchDescr + + let wikilink_md_prefix = '[' + let wikilink_md_suffix = ']' + let wikilink_md_separator = '][' + let rx_wikilink_md_separator = vimwiki#u#escape(wikilink_md_separator) + let mkd_syntax.rx_wikilink_md_prefix = vimwiki#u#escape(wikilink_md_prefix) + let mkd_syntax.rx_wikilink_md_suffix = vimwiki#u#escape(wikilink_md_suffix) + + " [URL][] + let mkd_syntax.WikiLink1Template1 = wikilink_md_prefix . '__LinkUrl__'. + \ wikilink_md_separator. wikilink_md_suffix + " [DESCRIPTION][URL] + let mkd_syntax.WikiLink1Template2 = wikilink_md_prefix. '__LinkDescription__'. + \ wikilink_md_separator. '__LinkUrl__'. wikilink_md_suffix + let mkd_syntax.WikiLinkMatchUrlTemplate .= + \ '\|' . + \ mkd_syntax.rx_wikilink_md_prefix . + \ '.*' . + \ rx_wikilink_md_separator . + \ '\zs__LinkUrl__\ze\%(#.*\)\?' . + \ mkd_syntax.rx_wikilink_md_suffix . + \ '\|' . + \ mkd_syntax.rx_wikilink_md_prefix . + \ '\zs__LinkUrl__\ze\%(#.*\)\?' . + \ rx_wikilink_md_separator . + \ mkd_syntax.rx_wikilink_md_suffix + + let valid_chars = '[^\\\[\]]' + let mkd_syntax.rxWikiLink1Url = valid_chars.'\{-}' + let mkd_syntax.rxWikiLink1Descr = valid_chars.'\{-}' + let mkd_syntax.rxWikiLink1InvalidPrefix = '[\]\[]\@<!' + let mkd_syntax.rxWikiLink1InvalidSuffix = '[\]\[]\@!' + let mkd_syntax.rx_wikilink_md_prefix = mkd_syntax.rxWikiLink1InvalidPrefix. + \ mkd_syntax.rx_wikilink_md_prefix + let mkd_syntax.rx_wikilink_md_suffix = mkd_syntax.rx_wikilink_md_suffix. + \ mkd_syntax.rxWikiLink1InvalidSuffix + + " 1. match [URL][], [DESCRIPTION][URL] + let mkd_syntax.rxWikiLink1 = mkd_syntax.rx_wikilink_md_prefix. + \ mkd_syntax.rxWikiLink1Url. rx_wikilink_md_separator. + \ mkd_syntax.rx_wikilink_md_suffix. + \ '\|'. mkd_syntax.rx_wikilink_md_prefix. + \ mkd_syntax.rxWikiLink1Descr . rx_wikilink_md_separator. + \ mkd_syntax.rxWikiLink1Url . mkd_syntax.rx_wikilink_md_suffix + " 2. match URL within [URL][], [DESCRIPTION][URL] + let mkd_syntax.rxWikiLink1MatchUrl = mkd_syntax.rx_wikilink_md_prefix. + \ '\zs'. mkd_syntax.rxWikiLink1Url. '\ze'. rx_wikilink_md_separator. + \ mkd_syntax.rx_wikilink_md_suffix. + \ '\|'. mkd_syntax.rx_wikilink_md_prefix. + \ mkd_syntax.rxWikiLink1Descr. rx_wikilink_md_separator. + \ '\zs'. mkd_syntax.rxWikiLink1Url. '\ze'. mkd_syntax.rx_wikilink_md_suffix + " 3. match DESCRIPTION within [DESCRIPTION][URL] + let mkd_syntax.rxWikiLink1MatchDescr = mkd_syntax.rx_wikilink_md_prefix. + \ '\zs'. mkd_syntax.rxWikiLink1Descr.'\ze'. rx_wikilink_md_separator. + \ mkd_syntax.rxWikiLink1Url . mkd_syntax.rx_wikilink_md_suffix + + let mkd_syntax.rxWikiLink1Prefix1 = mkd_syntax.rx_wikilink_md_prefix + let mkd_syntax.rxWikiLink1Suffix1 = rx_wikilink_md_separator. + \ mkd_syntax.rxWikiLink1Url . mkd_syntax.rx_wikilink_md_suffix + + " 1. match ANY wikilink + let mkd_syntax.rxWikiLink = mkd_syntax.rxWikiLink0 . '\|' . mkd_syntax.rxWikiLink1 + " 2. match URL within ANY wikilink + let mkd_syntax.rxWikiLinkMatchUrl = mkd_syntax.rxWikiLink0MatchUrl . '\|' . + \ mkd_syntax.rxWikiLink1MatchUrl + " 3. match DESCRIPTION within ANY wikilink + let mkd_syntax.rxWikiLinkMatchDescr = mkd_syntax.rxWikiLink0MatchDescr . '\|' . + \ mkd_syntax.rxWikiLink1MatchDescr + + " 0. URL : free-standing links: keep URL UR(L) strip trailing punct: URL; URL) UR(L)) + let mkd_syntax.rxWeblink0 = mkd_syntax.rxWeblink + " 0a) match URL within URL + let mkd_syntax.rxWeblinkMatchUrl0 = mkd_syntax.rxWeblinkMatchUrl + " 0b) match DESCRIPTION within URL + let mkd_syntax.rxWeblinkMatchDescr0 = mkd_syntax.rxWeblinkMatchDescr + + let mkd_syntax.rxWeblink1Prefix = '[' + let mkd_syntax.rxWeblink1Suffix = ')' + let mkd_syntax.rxWeblink1Separator = '](' + " [DESCRIPTION](URL) + let mkd_syntax.Weblink1Template = mkd_syntax.rxWeblink1Prefix . '__LinkDescription__'. + \ mkd_syntax.rxWeblink1Separator. '__LinkUrl__'. + \ mkd_syntax.rxWeblink1Suffix + + let valid_chars = '[^\\]' + + let mkd_syntax.rxWeblink1Prefix = vimwiki#u#escape(mkd_syntax.rxWeblink1Prefix) + let mkd_syntax.rxWeblink1Suffix = vimwiki#u#escape(mkd_syntax.rxWeblink1Suffix) + let mkd_syntax.rxWeblink1Separator = vimwiki#u#escape(mkd_syntax.rxWeblink1Separator) + let mkd_syntax.rxWeblink1Url = valid_chars.'\{-}' + let mkd_syntax.rxWeblink1Descr = valid_chars.'\{-}' + + " 1. [DESCRIPTION](URL) + " 1a) match [DESCRIPTION](URL) + let mkd_syntax.rxWeblink1 = mkd_syntax.rxWeblink1Prefix. + \ mkd_syntax.rxWeblink1Url . mkd_syntax.rxWeblink1Separator. + \ mkd_syntax.rxWeblink1Descr . mkd_syntax.rxWeblink1Suffix + " 1b) match URL within [DESCRIPTION](URL) + let mkd_syntax.rxWeblink1MatchUrl = mkd_syntax.rxWeblink1Prefix. + \ mkd_syntax.rxWeblink1Descr. mkd_syntax.rxWeblink1Separator. + \ '\zs' . mkd_syntax.rxWeblink1Url . '\ze' . mkd_syntax.rxWeblink1Suffix + " 1c) match DESCRIPTION within [DESCRIPTION](URL) + let mkd_syntax.rxWeblink1MatchDescr = mkd_syntax.rxWeblink1Prefix. + \ '\zs'.mkd_syntax.rxWeblink1Descr.'\ze'. mkd_syntax.rxWeblink1Separator. + \ mkd_syntax.rxWeblink1Url. mkd_syntax.rxWeblink1Suffix + + " TODO: image links too !! + let mkd_syntax.rxWeblink1Prefix1 = mkd_syntax.rxWeblink1Prefix + let mkd_syntax.rxWeblink1Suffix1 = mkd_syntax.rxWeblink1Separator. + \ mkd_syntax.rxWeblink1Url . mkd_syntax.rxWeblink1Suffix + + " *a) match ANY weblink + let mkd_syntax.rxWeblink = ''. + \ mkd_syntax.rxWeblink1.'\|'. + \ mkd_syntax.rxWeblink0 + " *b) match URL within ANY weblink + let mkd_syntax.rxWeblinkMatchUrl = ''. + \ mkd_syntax.rxWeblink1MatchUrl.'\|'. + \ mkd_syntax.rxWeblinkMatchUrl0 + " *c) match DESCRIPTION within ANY weblink + let mkd_syntax.rxWeblinkMatchDescr = ''. + \ mkd_syntax.rxWeblink1MatchDescr.'\|'. + \ mkd_syntax.rxWeblinkMatchDescr0 + + let mkd_syntax.rxAnyLink = mkd_syntax.rxWikiLink.'\|'. + \ g:vimwiki_global_vars.rxWikiIncl.'\|'.mkd_syntax.rxWeblink + + let mkd_syntax.rxMkdRef = '\['.g:vimwiki_global_vars.rxWikiLinkDescr.']:\%(\s\+\|\n\)'. + \ mkd_syntax.rxWeblink0 + let mkd_syntax.rxMkdRefMatchDescr = + \ '\[\zs'.g:vimwiki_global_vars.rxWikiLinkDescr.'\ze]:\%(\s\+\|\n\)'. mkd_syntax.rxWeblink0 + let mkd_syntax.rxMkdRefMatchUrl = + \ '\['.g:vimwiki_global_vars.rxWikiLinkDescr.']:\%(\s\+\|\n\)\zs'. + \ mkd_syntax.rxWeblink0.'\ze' +endfunction + + +function! vimwiki#vars#init() + call s:populate_global_variables() + call s:populate_wikilocal_options() +endfunction + + +function! vimwiki#vars#get_syntaxlocal(key, ...) + if a:0 + let syntax = a:1 + else + let syntax = vimwiki#vars#get_wikilocal('syntax') + endif + if !exists('g:vimwiki_syntax_variables') || !has_key(g:vimwiki_syntax_variables, syntax) + call vimwiki#vars#populate_syntax_vars(syntax) + endif + + return g:vimwiki_syntax_variables[syntax][a:key] +endfunction + + +" Get a variable for the buffer we are currently in or for the given buffer (number or name). +" Populate the variable, if it doesn't exist. +function! vimwiki#vars#get_bufferlocal(key, ...) + let buffer = a:0 ? a:1 : '%' + + let value = getbufvar(buffer, 'vimwiki_'.a:key, '/\/\') + if type(value) != 1 || value !=# '/\/\' + return value + elseif a:key ==# 'wiki_nr' + call setbufvar(buffer, 'vimwiki_wiki_nr', vimwiki#base#find_wiki(expand('%:p'))) + elseif a:key ==# 'subdir' + call setbufvar(buffer, 'vimwiki_subdir', vimwiki#base#current_subdir()) + elseif a:key ==# 'invsubdir' + let subdir = vimwiki#vars#get_bufferlocal('subdir') + call setbufvar(buffer, 'vimwiki_invsubdir', vimwiki#base#invsubdir(subdir)) + elseif a:key ==# 'existing_wikifiles' + call setbufvar(buffer, 'vimwiki_existing_wikifiles', + \ vimwiki#base#get_wikilinks(vimwiki#vars#get_bufferlocal('wiki_nr'), 1)) + elseif a:key ==# 'existing_wikidirs' + call setbufvar(buffer, 'vimwiki_existing_wikidirs', + \ vimwiki#base#get_wiki_directories(vimwiki#vars#get_bufferlocal('wiki_nr'))) + elseif a:key ==# 'prev_link' + call setbufvar(buffer, 'vimwiki_prev_link', []) + elseif a:key ==# 'markdown_refs' + call setbufvar(buffer, 'vimwiki_markdown_refs', vimwiki#markdown_base#scan_reflinks()) + else + echoerr 'Vimwiki Error: unknown buffer variable ' . string(a:key) + endif + + return getbufvar(buffer, 'vimwiki_'.a:key) +endfunction + + +function! vimwiki#vars#set_bufferlocal(key, value, ...) + let buffer = a:0 ? a:1 : '%' + call setbufvar(buffer, 'vimwiki_' . a:key, a:value) +endfunction + + +function! vimwiki#vars#get_global(key) + return g:vimwiki_global_vars[a:key] +endfunction + + +" the second argument can be a wiki number. When absent, the wiki of the currently active buffer is +" used +function! vimwiki#vars#get_wikilocal(key, ...) + if a:0 + return g:vimwiki_wikilocal_vars[a:1][a:key] + else + return g:vimwiki_wikilocal_vars[vimwiki#vars#get_bufferlocal('wiki_nr')][a:key] + endif +endfunction + + +function! vimwiki#vars#get_wikilocal_default(key) + return g:vimwiki_wikilocal_vars[-1][a:key] +endfunction + + +function! vimwiki#vars#set_wikilocal(key, value, wiki_nr) + if a:wiki_nr == len(g:vimwiki_wikilocal_vars) - 1 + call insert(g:vimwiki_wikilocal_vars, {}, -1) + endif + let g:vimwiki_wikilocal_vars[a:wiki_nr][a:key] = a:value +endfunction + + +function! vimwiki#vars#add_temporary_wiki(settings) + let new_temp_wiki_settings = copy(g:vimwiki_wikilocal_vars[-1]) + for [key, value] in items(a:settings) + let new_temp_wiki_settings[key] = value + endfor + call insert(g:vimwiki_wikilocal_vars, new_temp_wiki_settings, -1) + call s:normalize_wikilocal_settings() +endfunction + + +" number of registered wikis + temporary +function! vimwiki#vars#number_of_wikis() + return len(g:vimwiki_wikilocal_vars) - 1 +endfunction + diff --git a/.config/nvim/init.vim b/.config/nvim/init.vim @@ -13,7 +13,7 @@ " repeat - repeat things " vimling (ipa, deadkeys) - deadkeys " vimagit - git in vim -" v(org)im (written by me) - emulating org mode in vim +" vimwiki - wiki program (can view my wiki) "Leader let mapleader="," @@ -40,21 +40,25 @@ set relativenumber set number set hlsearch filetype plugin on +set noshowmode "Leader keys -noremap <leader>ve :vsplit ~/.config/nvim/init.vim<CR> +noremap <leader>vv :edit ~/.config/nvim/init.vim<CR> +noremap <leader>vz :vsplit ~/.config/nvim/init.vim<CR> +noremap <leader>vZ :split ~/.config/nvim/init.vim<CR> noremap <leader>vs :source ~/.config/nvim/init.vim<CR> map <leader><leader><leader> <leader>vs noremap <leader>g :Goyo \| set linebreak<CR> -noremap <leader>c :!sudo make all install clean \| set linebreak<CR> +noremap <leader>cd :chdir +noremap <leader>C :!sudo make all install clean<CR> noremap <leader>oc :!groff -T pdf % - > /tmp/grff \| zathura -<Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left> -noremap <Leader>sv :!sent % \| set linebreak<CR> +noremap <leader>sv :!sent % \| set linebreak<CR> noremap <leader>sc :setlocal spell! spelllang=en_us \| set linebreak<CR> noremap <leader>sf mm[s1z=`m<CR> -noremap <leader>ssf z=<CR> -noremap <leader>ff :r !find \| set linebreak<CR> -noremap <leader>fl :r !ls \| set linebreak<CR> +noremap <leader>ssf mm[sz=`m +noremap <leader>Ff :r !find \| set linebreak<CR> +noremap <leader>Fl :r !ls \| set linebreak<CR> noremap <leader>bd :bdelete \| set linebreak<CR> noremap <leader>bn :bn \| set linebreak<CR> noremap <leader>bp :bp \| set linebreak<CR> @@ -63,12 +67,15 @@ noremap <leader>mvd :w! /tmp/bmv-edit \| set linebreak<CR>:!sh /tmp/bmv-edit \| noremap <leader>ss :set syntax= inoremap <leader><leader>ss <Esc>:set syntax= noremap <leader>w :w \| set linebreak<CR> -noremap <leader>W :w !sudo tee %<CR> +noremap <leader>w! :w !sudo tee %<CR> +noremap <leader>wq :x!<CR> noremap <leader>" ea"<esc>bi"<esc> noremap <leader>u" ds" noremap <leader>' ea'<esc>bi'<esc> noremap <leader>u' ds' noremap <leader>sp o<esc>pi +noremap <leader>Ee :edit +noremap <leader>yv :reg<CR> noremap <leader>nn :set number! relativenumber!<CR> noremap <leader><leader>nn :setlocal number! relativenumber!<CR> @@ -99,16 +106,16 @@ noremap cw ciw noremap md ddp noremap mu ddkkp noremap <c-U> viwU -noremap <c-u> viwu +noremap <c-i> viwu "Insert mode inoremap <c-d> <esc>ddi inoremap <c-c> <esc>cci -inoremap <c-r> <esc>r -inoremap <c-R> <esc>R -inoremap <c-v> <esc>v -inoremap <c-p> <esc>pi -inoremap <c-P> <esc>Pi +inoremap <c-r> <esc>lr +inoremap <c-R> <esc>lR +inoremap <c-v> <esc>lv +inoremap <c-p> <esc>lpli +inoremap <c-P> <esc>lPli "Folds nnoremap <silent> <Space> @=(foldlevel('.')?'za':"\<Space>")<CR> @@ -127,7 +134,7 @@ inoremap <leader>li <esc>:call ToggleIPA()<CR>a "An erotic file-browser noremap <leader>eh :Sex \| set linebreak<CR> noremap <leader>ev :Vex \| set linebreak<CR> -noremap <leader>ee :Explore \| set linebreak<CR> +noremap <leader>ee :Explore noremap <leader>eo :browse oldfiles \| set linebreak<CR> noremap <leader>eb 100j let g:netrw_liststyle=3 @@ -161,13 +168,19 @@ source ~/.config/nvim/modules/theme.vim source ~/.config/nvim/modules/abbrs.vim source ~/.config/nvim/modules/statusline.vim source ~/.config/nvim/modules/splits.vim -source ~/.config/nvim/modules/buffs.vim source ~/.config/nvim/modules/netrw.vim source ~/.config/nvim/modules/term.vim source ~/.config/nvim/modules/tabs.vim +source ~/.config/nvim/modules/wiki.vim +source ~/.config/nvim/modules/edit.vim +source ~/.config/nvim/modules/window.vim +source ~/.config/nvim/modules/message.vim +source ~/.config/nvim/modules/openc.vim "Automatic commands augroup autocmd + "greet + autocmd BufRead *.greet set syntax=greet "netrw autocmd FileType,WinEnter,BufEnter netrw call Configurenetrw() diff --git a/.config/nvim/modules/abbrs.vim b/.config/nvim/modules/abbrs.vim @@ -2,3 +2,5 @@ iabbrev eemail hayden@haydenvh.com iabbrev <email> <hayden@haydenvh.com> iabbrev wweb haydenvh.com iabbrev ccopy Copyright (c) Hayden Hamilton <hayden@haydenvh.com> +iabbrev ssig -- Hayden +iabbrev nname Hayden Hamilton diff --git a/.config/nvim/modules/buffs.vim b/.config/nvim/modules/buffs.vim @@ -1,3 +0,0 @@ -hi TabLine cterm=none ctermfg=256 ctermbg=0 -hi TabLineSel cterm=bold ctermfg=252 ctermbg=1 -hi TabLineFill cterm=none ctermfg=none ctermbg=none diff --git a/.config/nvim/modules/edit.vim b/.config/nvim/modules/edit.vim @@ -0,0 +1,28 @@ +function! Sedrun(args) + write + let cmd="sed -i '" . a:args . "' %" + execute ":!" . cmd | redraw + silent! edit! +endfunction + +function! Grepwin(args, vert) + if a:vert == '1' + let split="vsplit" + else + let split="split" + endif + + write + let ftsave=&filetype + let tmpfile=fnameescape(tempname()) + let cmd="grep '" . a:args . "' % > " . tmpfile + execute ":!" . cmd | redraw + + silent! execute ":" . split . " " . tmpfile + + execute ":set filetype=" . ftsave +endfunction + +nnoremap <leader>S :call Sedrun("")<left><left> +nnoremap <leader>Gh :call Grepwin("", 0)<left><left><left><left><left> +nnoremap <leader>Gv :call Grepwin("", 1)<left><left><left><left><left> diff --git a/.config/nvim/modules/message.vim b/.config/nvim/modules/message.vim @@ -0,0 +1,116 @@ +set shortmess+=I + +augroup EnterMessage + autocmd VimEnter * if !argc() && (line2byte('$') == -1) && (v:progname =~? '^[-gmnq]\=vim\=x\=\%[\.exe]$') + \ | call VimEnterDisplay() + \ | endif +augroup END + +function! VimEnterDisplay() + edit ~/.config/nvim/startup.greet + set syntax=greet + call SpawnLauncher() +endfunction + +function! SpawnLauncher() + call Winmsg() + call LauncherRecent() + call Winset() +endfunction + +function! FzfLauncher() + call Winmsg() + " fzf + call Winset() +endfunction + +function! LauncherRecent() + rshada! + let olist=v:oldfiles + let i=0 + + redir! >/tmp/vim-recent | silent! echo ' Press "q" to open empty buffer, "Q" to quit, or any key below:' | silent! echo '' | silent! echo ' Recent files:' | redir END + redir! >/tmp/vim-recent.1 | silent! echo '' | silent! echo '' | silent! echo 'Config files:' | redir END + redir! >/tmp/vim-recent.2 | silent! echo '' | silent! echo '' | silent! echo 'Recent files (cwd):' | redir END + redir! >/tmp/vim-recentcmd.vim | silent! echo ':silent! unmap <buffer> q' | silent! echo 'nnoremap <buffer> q :q<CR>:new<CR>:only<CR>' | silent! echo ':silent! unmap <buffer>Q' | silent! echo ':nnoremap <buffer> Q :qa!<CR>' | silent! echo ':nnoremap <buffer> :q :qa!<CR>' | redir END + for string in olist + if i=='10' + break + endif + redir >>/tmp/vim-recent | silent! echo ' [' . i . '] ' . string | redir END + redir >>/tmp/vim-recentcmd.vim | silent! echo ':silent! unmap <buffer> ' . i | silent! echo ':nnoremap <buffer> ' . i . ' :q<CR>:edit ' . string '<CR>' | redir END + let i+=1 + endfor + let dir=getcwd() + let i=10 + for string in olist + if i=='20' + break + endif + if stridx(string, dir) != '-1' + redir >>/tmp/vim-recent.2 | silent! echo ' [' . i . '] ' . string | redir END + redir >>/tmp/vim-recentcmd.vim | silent! echo ':silent! unmap <buffer> ' . i | silent! echo ':nnoremap <buffer> ' . i . ' :q<CR>:edit ' . string '<CR>' | redir END + else + continue + endif + let i+=1 + endfor + call LauncherConfig() + call LauncherFileMerge() + edit /tmp/vim-recent + source /tmp/vim-recentcmd.vim + setlocal syntax=recent nomodifiable +endfunction + +function! LauncherFileMerge() + let w=&columns + execute ':silent !pr -mtw ' . w . ' /tmp/vim-recent /tmp/vim-recent.* > /tmp/vim-recent-concat' + execute ':silent !mv /tmp/vim-recent-concat /tmp/vim-recent' +endfunction + +function! LauncherConfig() + let configs=[ + \":edit ~/.config/nvim/init.vim", + \":Explore ~/.config/nvim/modules" + \] + + let i=1 + for config in configs + let a=Itoa(i) + redir! >/tmp/vim-config-dict | silent! echo config | redir END + let string=system("awk '{$1=\"\";print $0}' < /tmp/vim-config-dict | tr -d '\n\r'") + + redir >>/tmp/vim-recent.1 | silent! echo ' [' . a . '] ' . string | redir END + redir >>/tmp/vim-recentcmd.vim | silent! echo ':silent! unmap <buffer> ' . a | silent! echo ':nnoremap <buffer> ' . a . ' :q<CR>' . config . '<CR>' | redir END + let i+=1 + endfor + +endfunction + +function Itoa(i) + let i=a:i + let a='' + if i=='1' + let a='a' + elseif i=='2' + let a='b' + elseif i=='3' + let a='c' + elseif i=='4' + let a='d' + elseif i=='5' + let a='e' + elseif i=='6' + let a='f' + elseif i=='7' + let a='g' + elseif i=='8' + let a='h' + elseif i=='9' + let a='i' + elseif i=='10' + let a='j' + endif + + return a +endfunction diff --git a/.config/nvim/modules/openc.vim b/.config/nvim/modules/openc.vim @@ -0,0 +1,15 @@ +function! OpenC(arg) + let file='<cWORD>' + if a:arg == '0' + let split="vsplit" + elseif a:arg == '1' + let split="split" + else + let split="edit" + endif + execute ":" . split . " " . file +endfunction + +nnoremap <leader>Ew :call OpenC(2)<CR> +nnoremap <leader>EZ :call OpenC(1)<CR> +nnoremap <leader>Ez :call OpenC(0)<CR> diff --git a/.config/nvim/modules/splits.vim b/.config/nvim/modules/splits.vim @@ -9,18 +9,8 @@ noremap <C-l> <C-w>l noremap <C-c> <C-w>c noremap <A-j> <C-w>+ noremap <A-k> <C-w>- -noremap <A-h> <C-w>< -noremap <A-l> <C-w>> - -inoremap <C-h> <C-w>h -inoremap <C-j> <C-w>j -inoremap <C-k> <C-w>k -inoremap <C-l> <C-w>l -inoremap <C-c> <C-w>c -inoremap <A-j> <C-w>+ -inoremap <A-k> <C-w>- -inoremap <A-h> <C-w>< -inoremap <A-l> <C-w>> +noremap <A-h> <C-w>> +noremap <A-l> <C-w>< function! Netrwmap(filetype) if a:filetype == 'netrw' @@ -38,5 +28,5 @@ augroup Netrwstop augroup END set fillchars+=vert:\ -hi VertSplit ctermbg=0 ctermfg=0 -hi StatusLine ctermbg=0 ctermfg=0 +hi VertSplit ctermbg=1 ctermfg=1 +hi StatusLine ctermbg=1 ctermfg=1 diff --git a/.config/nvim/modules/statusline.vim b/.config/nvim/modules/statusline.vim @@ -1,7 +1,7 @@ hi Statusbar ctermbg=0 ctermfg=0 hi Modecol ctermbg=10 ctermfg=254 gui=bold -hi Basecol ctermbg=0 -hi Filecol ctermbg=2 ctermfg=7 gui=bold +hi Basecol ctermbg=1 +hi Filecol ctermbg=3 ctermfg=7 gui=bold hi Branchcol ctermbg=9 ctermfg=7 gui=bold hi Positioncol ctermbg=3 ctermfg=254 gui=bold hi Buffcol ctermbg=4 ctermfg=159 diff --git a/.config/nvim/modules/tabs.vim b/.config/nvim/modules/tabs.vim @@ -1,3 +1,7 @@ +hi TabLine cterm=none ctermfg=252 ctermbg=1 +hi TabLineSel cterm=bold ctermfg=252 ctermbg=0 +hi TabLineFill cterm=none ctermfg=none ctermbg=1 + nnoremap <leader>te :tabedit nnoremap <leader>tf :tabfind nnoremap <leader>tc :tabclose<CR> @@ -6,7 +10,10 @@ nnoremap <leader>tb :tab ball<CR> nnoremap <leader>th :tab help nnoremap <leader>tz :tab split<CR> nnoremap <leader>tZ :tab split<CR> -nnoremap <leader>tn :tabn<CR> +nnoremap <leader>tn :tabnew<CR> +nnoremap <leader>tN :tabNext<CR> nnoremap <leader>tp :tabp<CR> nnoremap <leader>tN :tablast<CR> nnoremap <leader>tP :tabfirst<CR> + +set showtabline=2 diff --git a/.config/nvim/modules/theme.vim b/.config/nvim/modules/theme.vim @@ -4,3 +4,10 @@ hi NvimInternalError ctermbg=3 ctermfg=3 hi Float ctermfg=13 cterm=bold hi LineNr ctermfg=11 hi CursorLineNr ctermfg=11 cterm=bold +hi SpellBad ctermbg=1 ctermfg=10 +hi SpellCap ctermbg=1 ctermfg=13 +hi SpellRare ctermbg=1 ctermfg=256 cterm=underline +hi SpellLocal ctermbg=1 ctermfg=255 cterm=bold + +hi MsgArea ctermbg=0 +hi MsgSeparator ctermbg=1 diff --git a/.config/nvim/modules/wiki.vim b/.config/nvim/modules/wiki.vim @@ -0,0 +1,12 @@ +augroup wikimaps + autocmd WinNew,WinEnter,BufNew,BufEnter *.wiki :call Wikimaps() +augroup END + +let g:vimwiki_listsyms='-~=X' + +function! Wikimaps() + nnoremap <buffer> <leader>Wt :VimwikiTable + nnoremap <buffer> <leader>W2h :Vimwiki2HTML + " To be continued +endfunction + diff --git a/.config/nvim/modules/window.vim b/.config/nvim/modules/window.vim @@ -0,0 +1,19 @@ +hi Float ctermbg=0 cterm=none ctermfg=256 + +function! Winmsg() + let width=&columns+4 + let height=20 + let top=&lines-height-1 + echo top + let left=-2 + let opts = {'relative': 'editor', 'row': top, 'col': left, 'width': width, 'height': height, 'style': 'minimal'} + let opts.row += 1 + let opts.height -= 2 + let opts.col += 2 + let opts.width -= 4 + call nvim_open_win(nvim_create_buf(v:false, v:true), v:true, opts) +endfunction + +function! Winset() + setlocal winhl=Normal:Float +endfunction diff --git a/.config/nvim/plugin/vimwiki.vim b/.config/nvim/plugin/vimwiki.vim @@ -0,0 +1,398 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki plugin file +" Home: https://github.com/vimwiki/vimwiki/ +" GetLatestVimScripts: 2226 1 :AutoInstall: vimwiki + + +if exists("g:loaded_vimwiki") || &cp + finish +endif +let g:loaded_vimwiki = 1 + +" Set to version number for release, otherwise -1 for dev-branch +let s:plugin_vers = "2.4.1" + +" Get the directory the script is installed in +let s:plugin_dir = expand('<sfile>:p:h:h') + +let s:old_cpo = &cpo +set cpo&vim + + +if exists('g:vimwiki_autowriteall') + let s:vimwiki_autowriteall_saved = g:vimwiki_autowriteall +else + let s:vimwiki_autowriteall_saved = 1 +endif + + +" this is called when the cursor leaves the buffer +function! s:setup_buffer_leave() + " don't do anything if it's not managed by Vimwiki (that is, when it's not in + " a registered wiki and not a temporary wiki) + if vimwiki#vars#get_bufferlocal('wiki_nr') == -1 + return + endif + + let &autowriteall = s:vimwiki_autowriteall_saved + + if !empty(vimwiki#vars#get_global('menu')) + exe 'nmenu disable '.vimwiki#vars#get_global('menu').'.Table' + endif +endfunction + + +" create a new temporary wiki for the current buffer +function! s:create_temporary_wiki() + let path = expand('%:p:h') + let ext = '.'.expand('%:e') + + let syntax_mapping = vimwiki#vars#get_global('ext2syntax') + if has_key(syntax_mapping, ext) + let syntax = syntax_mapping[ext] + else + let syntax = vimwiki#vars#get_wikilocal_default('syntax') + endif + + let new_temp_wiki_settings = {'path': path, + \ 'ext': ext, + \ 'syntax': syntax, + \ } + + call vimwiki#vars#add_temporary_wiki(new_temp_wiki_settings) + + " Update the wiki number of the current buffer, because it may have changed when adding this + " temporary wiki. + call vimwiki#vars#set_bufferlocal('wiki_nr', vimwiki#base#find_wiki(expand('%:p'))) +endfunction + + +" This function is called when Vim opens a new buffer with a known wiki +" extension. Both when the buffer has never been opened in this session and +" when it has. +function! s:setup_new_wiki_buffer() + let wiki_nr = vimwiki#vars#get_bufferlocal('wiki_nr') + if wiki_nr == -1 " it's not in a known wiki directory + if vimwiki#vars#get_global('global_ext') + call s:create_temporary_wiki() + else + " the user does not want a temporary wiki, so do nothing + return + endif + endif + + if vimwiki#vars#get_wikilocal('maxhi') + call vimwiki#vars#set_bufferlocal('existing_wikifiles', vimwiki#base#get_wikilinks(wiki_nr, 1)) + call vimwiki#vars#set_bufferlocal('existing_wikidirs', + \ vimwiki#base#get_wiki_directories(wiki_nr)) + endif + + " this makes that ftplugin/vimwiki.vim and afterwards syntax/vimwiki.vim are + " sourced + setfiletype vimwiki + +endfunction + + +" this is called when the cursor enters the buffer +function! s:setup_buffer_enter() + " don't do anything if it's not managed by Vimwiki (that is, when it's not in + " a registered wiki and not a temporary wiki) + if vimwiki#vars#get_bufferlocal('wiki_nr') == -1 + return + endif + + if &filetype != 'vimwiki' + setfiletype vimwiki + endif + + call s:set_global_options() + + call s:set_windowlocal_options() +endfunction + + +function! s:setup_cleared_syntax() + " highlight groups that get cleared + " on colorscheme change because they are not linked to Vim-predefined groups + hi def VimwikiBold term=bold cterm=bold gui=bold + hi def VimwikiItalic term=italic cterm=italic gui=italic + hi def VimwikiBoldItalic term=bold cterm=bold gui=bold,italic + hi def VimwikiUnderline gui=underline + if vimwiki#vars#get_global('hl_headers') == 1 + for i in range(1,6) + execute 'hi def VimwikiHeader'.i.' guibg=bg guifg=' + \ . vimwiki#vars#get_global('hcolor_guifg_'.&bg)[i-1] + \ .' gui=bold ctermfg='.vimwiki#vars#get_global('hcolor_ctermfg_'.&bg)[i-1] + \ .' term=bold cterm=bold' + endfor + endif +endfunction + + +function! s:vimwiki_get_known_extensions() + " Getting all extensions that different wikis could have + let extensions = {} + for idx in range(vimwiki#vars#number_of_wikis()) + let ext = vimwiki#vars#get_wikilocal('ext', idx) + let extensions[ext] = 1 + endfor + " append extensions from g:vimwiki_ext2syntax + for ext in keys(vimwiki#vars#get_global('ext2syntax')) + let extensions[ext] = 1 + endfor + return keys(extensions) +endfunction + + +" Set settings which are global for Vim, but should only be executed for +" Vimwiki buffers. So they must be set when the cursor enters a Vimwiki buffer +" and reset when the cursor leaves the buffer. +function! s:set_global_options() + let s:vimwiki_autowriteall_saved = &autowriteall + let &autowriteall = vimwiki#vars#get_global('autowriteall') + + if !empty(vimwiki#vars#get_global('menu')) + exe 'nmenu enable '.vimwiki#vars#get_global('menu').'.Table' + endif +endfunction + + +" Set settings which are local to a window. In a new tab they would be reset to +" Vim defaults. So we enforce our settings here when the cursor enters a +" Vimwiki buffer. +function! s:set_windowlocal_options() + if !&diff " if Vim is currently in diff mode, don't interfere with its folding + let foldmethod = vimwiki#vars#get_global('folding') + if foldmethod =~? '^expr.*' + setlocal foldmethod=expr + setlocal foldexpr=VimwikiFoldLevel(v:lnum) + setlocal foldtext=VimwikiFoldText() + elseif foldmethod =~? '^list.*' || foldmethod =~? '^lists.*' + setlocal foldmethod=expr + setlocal foldexpr=VimwikiFoldListLevel(v:lnum) + setlocal foldtext=VimwikiFoldText() + elseif foldmethod =~? '^syntax.*' + setlocal foldmethod=syntax + setlocal foldtext=VimwikiFoldText() + elseif foldmethod =~? '^custom.*' + " do nothing + else + setlocal foldmethod=manual + normal! zE + endif + endif + + if vimwiki#vars#get_global('conceallevel') && exists("+conceallevel") + let &conceallevel = vimwiki#vars#get_global('conceallevel') + endif + + if vimwiki#vars#get_global('auto_chdir') + exe 'lcd' vimwiki#vars#get_wikilocal('path') + endif +endfunction + + +function! s:get_version() + if s:plugin_vers != -1 + echo "Stable version: " . string(s:plugin_vers) + else + let l:plugin_rev = system("git --git-dir " . s:plugin_dir . "/.git rev-parse --short HEAD") + let l:plugin_branch = system("git --git-dir " . s:plugin_dir . "/.git rev-parse --abbrev-ref HEAD") + let l:plugin_date = system("git --git-dir " . s:plugin_dir . "/.git show -s --format=%ci") + if v:shell_error == 0 + echo "Branch: " . l:plugin_branch + echo "Revision: " . l:plugin_rev + echo "Date: " . l:plugin_date + else + echo "Unknown version" + endif + endif +endfunction + + + +" Initialization of Vimwiki starts here. Make sure everything below does not +" cause autoload/vimwiki/base.vim to be loaded + +call vimwiki#vars#init() + + +" Define callback functions which the user can redefine +if !exists("*VimwikiLinkHandler") + function VimwikiLinkHandler(url) + return 0 + endfunction +endif + +if !exists("*VimwikiLinkConverter") + function VimwikiLinkConverter(url, source, target) + " Return the empty string when unable to process link + return '' + endfunction +endif + +if !exists("*VimwikiWikiIncludeHandler") + function! VimwikiWikiIncludeHandler(value) + return '' + endfunction +endif + + + +" Define autocommands for all known wiki extensions + +let s:known_extensions = s:vimwiki_get_known_extensions() + +if index(s:known_extensions, '.wiki') > -1 + augroup filetypedetect + " clear FlexWiki's stuff + au! * *.wiki + augroup end +endif + +augroup vimwiki + autocmd! + autocmd ColorScheme * call s:setup_cleared_syntax() + for s:ext in s:known_extensions + exe 'autocmd BufNewFile,BufRead *'.s:ext.' call s:setup_new_wiki_buffer()' + exe 'autocmd BufEnter *'.s:ext.' call s:setup_buffer_enter()' + exe 'autocmd BufLeave *'.s:ext.' call s:setup_buffer_leave()' + " Format tables when exit from insert mode. Do not use textwidth to + " autowrap tables. + if vimwiki#vars#get_global('table_auto_fmt') + exe 'autocmd InsertLeave *'.s:ext.' call vimwiki#tbl#format(line("."))' + exe 'autocmd InsertEnter *'.s:ext.' call vimwiki#tbl#reset_tw(line("."))' + endif + if vimwiki#vars#get_global('folding') =~? ':quick$' + " from http://vim.wikia.com/wiki/Keep_folds_closed_while_inserting_text + " Don't screw up folds when inserting text that might affect them, until + " leaving insert mode. Foldmethod is local to the window. Protect against + " screwing up folding when switching between windows. + exe 'autocmd InsertEnter *'.s:ext.' if !exists("w:last_fdm") | let w:last_fdm=&foldmethod'. + \ ' | setlocal foldmethod=manual | endif' + exe 'autocmd InsertLeave,WinLeave *'.s:ext.' if exists("w:last_fdm") |'. + \ 'let &l:foldmethod=w:last_fdm | unlet w:last_fdm | endif' + endif + endfor +augroup END + + + +command! VimwikiUISelect call vimwiki#base#ui_select() +" why not using <count> instead of v:count1? +" See https://github.com/vimwiki-backup/vimwiki/issues/324 +command! -count=1 VimwikiIndex + \ call vimwiki#base#goto_index(v:count1) +command! -count=1 VimwikiTabIndex + \ call vimwiki#base#goto_index(v:count1, 1) + +command! -count=1 VimwikiDiaryIndex + \ call vimwiki#diary#goto_diary_index(v:count1) +command! -count=1 VimwikiMakeDiaryNote + \ call vimwiki#diary#make_note(v:count) +command! -count=1 VimwikiTabMakeDiaryNote + \ call vimwiki#diary#make_note(v:count, 1) +command! -count=1 VimwikiMakeYesterdayDiaryNote + \ call vimwiki#diary#make_note(v:count, 0, + \ vimwiki#diary#diary_date_link(localtime() - 60*60*24)) +command! -count=1 VimwikiMakeTomorrowDiaryNote + \ call vimwiki#diary#make_note(v:count, 0, + \ vimwiki#diary#diary_date_link(localtime() + 60*60*24)) + +command! VimwikiDiaryGenerateLinks + \ call vimwiki#diary#generate_diary_section() + +command! VimwikiShowVersion call s:get_version() + + + +let s:map_prefix = vimwiki#vars#get_global('map_prefix') + +if !hasmapto('<Plug>VimwikiIndex') + exe 'nmap <silent><unique> '.s:map_prefix.'w <Plug>VimwikiIndex' +endif +nnoremap <unique><script> <Plug>VimwikiIndex :VimwikiIndex<CR> + +if !hasmapto('<Plug>VimwikiTabIndex') + exe 'nmap <silent><unique> '.s:map_prefix.'t <Plug>VimwikiTabIndex' +endif +nnoremap <unique><script> <Plug>VimwikiTabIndex :VimwikiTabIndex<CR> + +if !hasmapto('<Plug>VimwikiUISelect') + exe 'nmap <silent><unique> '.s:map_prefix.'s <Plug>VimwikiUISelect' +endif +nnoremap <unique><script> <Plug>VimwikiUISelect :VimwikiUISelect<CR> + +if !hasmapto('<Plug>VimwikiDiaryIndex') + exe 'nmap <silent><unique> '.s:map_prefix.'i <Plug>VimwikiDiaryIndex' +endif +nnoremap <unique><script> <Plug>VimwikiDiaryIndex :VimwikiDiaryIndex<CR> + +if !hasmapto('<Plug>VimwikiDiaryGenerateLinks') + exe 'nmap <silent><unique> '.s:map_prefix.'<Leader>i <Plug>VimwikiDiaryGenerateLinks' +endif +nnoremap <unique><script> <Plug>VimwikiDiaryGenerateLinks :VimwikiDiaryGenerateLinks<CR> + +if !hasmapto('<Plug>VimwikiMakeDiaryNote') + exe 'nmap <silent><unique> '.s:map_prefix.'<Leader>w <Plug>VimwikiMakeDiaryNote' +endif +nnoremap <unique><script> <Plug>VimwikiMakeDiaryNote :VimwikiMakeDiaryNote<CR> + +if !hasmapto('<Plug>VimwikiTabMakeDiaryNote') + exe 'nmap <silent><unique> '.s:map_prefix.'<Leader>t <Plug>VimwikiTabMakeDiaryNote' +endif +nnoremap <unique><script> <Plug>VimwikiTabMakeDiaryNote + \ :VimwikiTabMakeDiaryNote<CR> + +if !hasmapto('<Plug>VimwikiMakeYesterdayDiaryNote') + exe 'nmap <silent><unique> '.s:map_prefix.'<Leader>y <Plug>VimwikiMakeYesterdayDiaryNote' +endif +nnoremap <unique><script> <Plug>VimwikiMakeYesterdayDiaryNote + \ :VimwikiMakeYesterdayDiaryNote<CR> + +if !hasmapto('<Plug>VimwikiMakeTomorrowDiaryNote') + exe 'nmap <silent><unique> '.s:map_prefix.'<Leader>m <Plug>VimwikiMakeTomorrowDiaryNote' +endif +nnoremap <unique><script> <Plug>VimwikiMakeTomorrowDiaryNote + \ :VimwikiMakeTomorrowDiaryNote<CR> + + + + +function! s:build_menu(topmenu) + for idx in range(vimwiki#vars#number_of_wikis()) + let norm_path = fnamemodify(vimwiki#vars#get_wikilocal('path', idx), ':h:t') + let norm_path = escape(norm_path, '\ \.') + execute 'menu '.a:topmenu.'.Open\ index.'.norm_path. + \ ' :call vimwiki#base#goto_index('.(idx+1).')<CR>' + execute 'menu '.a:topmenu.'.Open/Create\ diary\ note.'.norm_path. + \ ' :call vimwiki#diary#make_note('.(idx+1).')<CR>' + endfor +endfunction + +function! s:build_table_menu(topmenu) + exe 'menu '.a:topmenu.'.-Sep- :' + exe 'menu '.a:topmenu.'.Table.Create\ (enter\ cols\ rows) :VimwikiTable ' + exe 'nmenu '.a:topmenu.'.Table.Format<tab>gqq gqq' + exe 'nmenu '.a:topmenu.'.Table.Move\ column\ left<tab><A-Left> :VimwikiTableMoveColumnLeft<CR>' + exe 'nmenu '.a:topmenu. + \ '.Table.Move\ column\ right<tab><A-Right> :VimwikiTableMoveColumnRight<CR>' + exe 'nmenu disable '.a:topmenu.'.Table' +endfunction + + +if !empty(vimwiki#vars#get_global('menu')) + call s:build_menu(vimwiki#vars#get_global('menu')) + call s:build_table_menu(vimwiki#vars#get_global('menu')) +endif + + +" Hook for calendar.vim +if vimwiki#vars#get_global('use_calendar') + let g:calendar_action = 'vimwiki#diary#calendar_action' + let g:calendar_sign = 'vimwiki#diary#calendar_sign' +endif + + +let &cpo = s:old_cpo diff --git a/.config/nvim/startup.greet b/.config/nvim/startup.greet @@ -0,0 +1,24 @@ + + + + + + |‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾| + | _ _ _ _ | + | | |__ __ _ _ _ __| | ___ _ __ ( )___ __ _(_)_ __ ___ | + | | '_ \ / _` | | | |/ _` |/ _ \ '_ \|// __| \ \ / / | '_ ` _ \ | + | | | | | (_| | |_| | (_| | __/ | | | \__ \ \ V /| | | | | | | | + | |_| |_|\__,_|\__, |\__,_|\___|_| |_| |___/ (n)\_/ |_|_| |_| |_| | + | |___/ | + |____________________________________________________________________| + + Plugins collected by Hayden Hamilton + init.vim created by Hayden Hamilton + modules/ created by Hayden Hamilton + Find more stuff at http://haydenvh.com + + :edit ~/.config/nvim/init - Contains mappings and settings for neovim. + + :Explore ~/.config/nvim/modules - Contains my modules and additions. + + :help intro - introduction to the vim editor. diff --git a/.config/nvim/syntax/greet.vim b/.config/nvim/syntax/greet.vim @@ -0,0 +1,12 @@ +if exists("b:current_syntax") + finish +endif + +syn match gAscii '|.*|' +syn match gCommand ':[A-Za-z!]* [A-Za-z/~\.]*' +syn match gText '^\s*[A-Za-z].*' +hi gAscii cterm=none ctermbg=1 ctermfg=12 +hi gCommand cterm=none ctermbg=none ctermfg=13 +hi gText cterm=none ctermbg=none ctermfg=255 +setlocal fcs=eob:\ +set nonumber norelativenumber diff --git a/.config/nvim/syntax/recent.vim b/.config/nvim/syntax/recent.vim @@ -0,0 +1,10 @@ +if exists("b:current_syntax") + finish +endif + +syn match rNum '\[[0-9]*\]' +syn match rChar '\[[A-Za-z]*\]' +syn match Head '^\s*[A-Za-z0-9].*' +hi rNum cterm=none ctermfg=30 +hi rChar cterm=none ctermfg=28 +hi Head cterm=bold ctermfg=255 diff --git a/.config/nvim/syntax/vimwiki.vim b/.config/nvim/syntax/vimwiki.vim @@ -0,0 +1,487 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki syntax file +" Home: https://github.com/vimwiki/vimwiki/ + + +" Quit if syntax file is already loaded +if v:version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif + + +let s:current_syntax = vimwiki#vars#get_wikilocal('syntax') + + +call vimwiki#vars#populate_syntax_vars(s:current_syntax) + + +" LINKS: highlighting is complicated due to "nonexistent" links feature +function! s:add_target_syntax_ON(target, type) + let prefix0 = 'syntax match '.a:type.' `' + let suffix0 = '` display contains=@NoSpell,VimwikiLinkRest,'.a:type.'Char' + let prefix1 = 'syntax match '.a:type.'T `' + let suffix1 = '` display contained' + execute prefix0. a:target. suffix0 + execute prefix1. a:target. suffix1 +endfunction + + +function! s:add_target_syntax_OFF(target) + let prefix0 = 'syntax match VimwikiNoExistsLink `' + let suffix0 = '` display contains=@NoSpell,VimwikiLinkRest,VimwikiLinkChar' + let prefix1 = 'syntax match VimwikiNoExistsLinkT `' + let suffix1 = '` display contained' + execute prefix0. a:target. suffix0 + execute prefix1. a:target. suffix1 +endfunction + + +function! s:highlight_existing_links() + " Wikilink + " Conditional highlighting that depends on the existence of a wiki file or + " directory is only available for *schemeless* wiki links + " Links are set up upon BufEnter (see plugin/...) + let safe_links = '\%('.vimwiki#base#file_pattern( + \ vimwiki#vars#get_bufferlocal('existing_wikifiles')) . '\%(#[^|]*\)\?\|#[^|]*\)' + " Wikilink Dirs set up upon BufEnter (see plugin/...) + let safe_dirs = vimwiki#base#file_pattern(vimwiki#vars#get_bufferlocal('existing_wikidirs')) + + " match [[URL]] + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_global('WikiLinkTemplate1')), + \ safe_links, vimwiki#vars#get_global('rxWikiLinkDescr'), '') + call s:add_target_syntax_ON(target, 'VimwikiLink') + " match [[URL|DESCRIPTION]] + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_global('WikiLinkTemplate2')), + \ safe_links, vimwiki#vars#get_global('rxWikiLinkDescr'), '') + call s:add_target_syntax_ON(target, 'VimwikiLink') + + " match {{URL}} + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_global('WikiInclTemplate1')), + \ safe_links, vimwiki#vars#get_global('rxWikiInclArgs'), '') + call s:add_target_syntax_ON(target, 'VimwikiLink') + " match {{URL|...}} + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_global('WikiInclTemplate2')), + \ safe_links, vimwiki#vars#get_global('rxWikiInclArgs'), '') + call s:add_target_syntax_ON(target, 'VimwikiLink') + " match [[DIRURL]] + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_global('WikiLinkTemplate1')), + \ safe_dirs, vimwiki#vars#get_global('rxWikiLinkDescr'), '') + call s:add_target_syntax_ON(target, 'VimwikiLink') + " match [[DIRURL|DESCRIPTION]] + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_global('WikiLinkTemplate2')), + \ safe_dirs, vimwiki#vars#get_global('rxWikiLinkDescr'), '') + call s:add_target_syntax_ON(target, 'VimwikiLink') +endfunction + + +" use max highlighting - could be quite slow if there are too many wikifiles +if vimwiki#vars#get_wikilocal('maxhi') + " WikiLink + call s:add_target_syntax_OFF(vimwiki#vars#get_syntaxlocal('rxWikiLink')) + " WikiIncl + call s:add_target_syntax_OFF(vimwiki#vars#get_global('rxWikiIncl')) + + " Subsequently, links verified on vimwiki's path are highlighted as existing + call s:highlight_existing_links() +else + " Wikilink + call s:add_target_syntax_ON(vimwiki#vars#get_syntaxlocal('rxWikiLink'), 'VimwikiLink') + " WikiIncl + call s:add_target_syntax_ON(vimwiki#vars#get_global('rxWikiIncl'), 'VimwikiLink') +endif + + +" Weblink +call s:add_target_syntax_ON(vimwiki#vars#get_syntaxlocal('rxWeblink'), 'VimwikiLink') + + +" WikiLink +" All remaining schemes are highlighted automatically +let s:rxSchemes = '\%('. + \ vimwiki#vars#get_global('schemes') . '\|'. + \ vimwiki#vars#get_global('web_schemes1'). + \ '\):' + +" a) match [[nonwiki-scheme-URL]] +let s:target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_global('WikiLinkTemplate1')), + \ s:rxSchemes.vimwiki#vars#get_global('rxWikiLinkUrl'), + \ vimwiki#vars#get_global('rxWikiLinkDescr'), '') +call s:add_target_syntax_ON(s:target, 'VimwikiLink') +" b) match [[nonwiki-scheme-URL|DESCRIPTION]] +let s:target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_global('WikiLinkTemplate2')), + \ s:rxSchemes.vimwiki#vars#get_global('rxWikiLinkUrl'), + \ vimwiki#vars#get_global('rxWikiLinkDescr'), '') +call s:add_target_syntax_ON(s:target, 'VimwikiLink') + +" a) match {{nonwiki-scheme-URL}} +let s:target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_global('WikiInclTemplate1')), + \ s:rxSchemes.vimwiki#vars#get_global('rxWikiInclUrl'), + \ vimwiki#vars#get_global('rxWikiInclArgs'), '') +call s:add_target_syntax_ON(s:target, 'VimwikiLink') +" b) match {{nonwiki-scheme-URL}[{...}]} +let s:target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_global('WikiInclTemplate2')), + \ s:rxSchemes.vimwiki#vars#get_global('rxWikiInclUrl'), + \ vimwiki#vars#get_global('rxWikiInclArgs'), '') +call s:add_target_syntax_ON(s:target, 'VimwikiLink') + + + +" Header levels, 1-6 +for s:i in range(1,6) + execute 'syntax match VimwikiHeader'.s:i + \ . ' /'.vimwiki#vars#get_syntaxlocal('rxH'.s:i, s:current_syntax). + \ '/ contains=VimwikiTodo,VimwikiHeaderChar,VimwikiNoExistsLink,VimwikiCode,'. + \ 'VimwikiLink,@Spell' + execute 'syntax region VimwikiH'.s:i.'Folding start=/'. + \ vimwiki#vars#get_syntaxlocal('rxH'.s:i.'_Start', s:current_syntax).'/ end=/'. + \ vimwiki#vars#get_syntaxlocal('rxH'.s:i.'_End', s:current_syntax). + \ '/me=s-1 transparent fold' +endfor + + + +" possibly concealed chars +let s:conceal = exists("+conceallevel") ? ' conceal' : '' + +execute 'syn match VimwikiEqInChar contained /'. + \ vimwiki#vars#get_syntaxlocal('char_eqin').'/'.s:conceal +execute 'syn match VimwikiBoldChar contained /'. + \ vimwiki#vars#get_syntaxlocal('char_bold').'/'.s:conceal +execute 'syn match VimwikiItalicChar contained /'. + \ vimwiki#vars#get_syntaxlocal('char_italic').'/'.s:conceal +execute 'syn match VimwikiBoldItalicChar contained /'. + \ vimwiki#vars#get_syntaxlocal('char_bolditalic').'/'.s:conceal +execute 'syn match VimwikiItalicBoldChar contained /'. + \ vimwiki#vars#get_syntaxlocal('char_italicbold').'/'.s:conceal +execute 'syn match VimwikiCodeChar contained /'. + \ vimwiki#vars#get_syntaxlocal('char_code').'/'.s:conceal +execute 'syn match VimwikiDelTextChar contained /'. + \ vimwiki#vars#get_syntaxlocal('char_deltext').'/'.s:conceal +execute 'syn match VimwikiSuperScript contained /'. + \ vimwiki#vars#get_syntaxlocal('char_superscript').'/'.s:conceal +execute 'syn match VimwikiSubScript contained /'. + \ vimwiki#vars#get_syntaxlocal('char_subscript').'/'.s:conceal + + + + + +let s:options = ' contained transparent contains=NONE' + +" A shortener for long URLs: LinkRest (a middle part of the URL) is concealed +" VimwikiLinkRest group is left undefined if link shortening is not desired +if exists("+conceallevel") && vimwiki#vars#get_global('url_maxsave') > 0 + let s:options .= s:conceal + execute 'syn match VimwikiLinkRest `\%(///\=[^/ \t]\+/\)\zs\S\+\ze' + \.'\%([/#?]\w\|\S\{'.vimwiki#vars#get_global('url_maxsave').'}\)`'.' cchar=~'.s:options +endif + +" VimwikiLinkChar is for syntax markers (and also URL when a description +" is present) and may be concealed + +" conceal wikilinks +execute 'syn match VimwikiLinkChar /'.vimwiki#vars#get_global('rx_wikilink_prefix').'/'.s:options +execute 'syn match VimwikiLinkChar /'.vimwiki#vars#get_global('rx_wikilink_suffix').'/'.s:options +execute 'syn match VimwikiLinkChar /'.vimwiki#vars#get_global('rx_wikilink_prefix1').'/'.s:options +execute 'syn match VimwikiLinkChar /'.vimwiki#vars#get_global('rx_wikilink_suffix1').'/'.s:options + +" conceal wikiincls +execute 'syn match VimwikiLinkChar /'.vimwiki#vars#get_global('rxWikiInclPrefix').'/'.s:options +execute 'syn match VimwikiLinkChar /'.vimwiki#vars#get_global('rxWikiInclSuffix').'/'.s:options +execute 'syn match VimwikiLinkChar /'.vimwiki#vars#get_global('rxWikiInclPrefix1').'/'.s:options +execute 'syn match VimwikiLinkChar /'.vimwiki#vars#get_global('rxWikiInclSuffix1').'/'.s:options + + +" non concealed chars +execute 'syn match VimwikiHeaderChar contained /\%(^\s*'. + \ vimwiki#vars#get_syntaxlocal('rxH').'\+\)\|\%('.vimwiki#vars#get_syntaxlocal('rxH'). + \ '\+\s*$\)/' +execute 'syn match VimwikiEqInCharT contained /' + \ .vimwiki#vars#get_syntaxlocal('char_eqin').'/' +execute 'syn match VimwikiBoldCharT contained /' + \ .vimwiki#vars#get_syntaxlocal('char_bold').'/' +execute 'syn match VimwikiItalicCharT contained /' + \ .vimwiki#vars#get_syntaxlocal('char_italic').'/' +execute 'syn match VimwikiBoldItalicCharT contained /' + \ .vimwiki#vars#get_syntaxlocal('char_bolditalic').'/' +execute 'syn match VimwikiItalicBoldCharT contained /' + \ .vimwiki#vars#get_syntaxlocal('char_italicbold').'/' +execute 'syn match VimwikiCodeCharT contained /' + \ .vimwiki#vars#get_syntaxlocal('char_code').'/' +execute 'syn match VimwikiDelTextCharT contained /' + \ .vimwiki#vars#get_syntaxlocal('char_deltext').'/' +execute 'syn match VimwikiSuperScriptT contained /' + \ .vimwiki#vars#get_syntaxlocal('char_superscript').'/' +execute 'syn match VimwikiSubScriptT contained /' + \ .vimwiki#vars#get_syntaxlocal('char_subscript').'/' + + +execute 'syntax match VimwikiTodo /'. vimwiki#vars#get_global('rxTodo') .'/' + + + +" Tables +syntax match VimwikiTableRow /^\s*|.\+|\s*$/ + \ transparent contains=VimwikiCellSeparator, + \ VimwikiLinkT, + \ VimwikiNoExistsLinkT, + \ VimwikiTodo, + \ VimwikiBoldT, + \ VimwikiItalicT, + \ VimwikiBoldItalicT, + \ VimwikiItalicBoldT, + \ VimwikiDelTextT, + \ VimwikiSuperScriptT, + \ VimwikiSubScriptT, + \ VimwikiCodeT, + \ VimwikiEqInT, + \ @Spell +syntax match VimwikiCellSeparator + \ /\%(|\)\|\%(-\@<=+\-\@=\)\|\%([|+]\@<=-\+\)/ contained + + +" Lists +execute 'syntax match VimwikiList /'.vimwiki#vars#get_syntaxlocal('rxListItemWithoutCB').'/' +execute 'syntax match VimwikiList /'.vimwiki#vars#get_syntaxlocal('rxListDefine').'/' +execute 'syntax match VimwikiListTodo /'.vimwiki#vars#get_syntaxlocal('rxListItem').'/' + +if vimwiki#vars#get_global('hl_cb_checked') == 1 + execute 'syntax match VimwikiCheckBoxDone /'.vimwiki#vars#get_syntaxlocal('rxListItemWithoutCB') + \ . '\s*\[['.vimwiki#vars#get_syntaxlocal('listsyms_list')[-1] + \ . vimwiki#vars#get_global('listsym_rejected') + \ . ']\]\s.*$/ contains=VimwikiNoExistsLink,VimwikiLink,@Spell' +elseif vimwiki#vars#get_global('hl_cb_checked') == 2 + execute 'syntax match VimwikiCheckBoxDone /' + \ . vimwiki#vars#get_syntaxlocal('rxListItemAndChildren') + \ .'/ contains=VimwikiNoExistsLink,VimwikiLink,@Spell' +endif + + +execute 'syntax match VimwikiEqIn /'.vimwiki#vars#get_syntaxlocal('rxEqIn'). + \ '/ contains=VimwikiEqInChar' +execute 'syntax match VimwikiEqInT /'.vimwiki#vars#get_syntaxlocal('rxEqIn'). + \ '/ contained contains=VimwikiEqInCharT' + +execute 'syntax match VimwikiBold /'.vimwiki#vars#get_syntaxlocal('rxBold'). + \ '/ contains=VimwikiBoldChar,@Spell' +execute 'syntax match VimwikiBoldT /'.vimwiki#vars#get_syntaxlocal('rxBold'). + \ '/ contained contains=VimwikiBoldCharT,@Spell' + +execute 'syntax match VimwikiItalic /'.vimwiki#vars#get_syntaxlocal('rxItalic'). + \ '/ contains=VimwikiItalicChar,@Spell' +execute 'syntax match VimwikiItalicT /'.vimwiki#vars#get_syntaxlocal('rxItalic'). + \ '/ contained contains=VimwikiItalicCharT,@Spell' + +execute 'syntax match VimwikiBoldItalic /'.vimwiki#vars#get_syntaxlocal('rxBoldItalic'). + \ '/ contains=VimwikiBoldItalicChar,VimwikiItalicBoldChar,@Spell' +execute 'syntax match VimwikiBoldItalicT /'.vimwiki#vars#get_syntaxlocal('rxBoldItalic'). + \ '/ contained contains=VimwikiBoldItalicChatT,VimwikiItalicBoldCharT,@Spell' + +execute 'syntax match VimwikiItalicBold /'.vimwiki#vars#get_syntaxlocal('rxItalicBold'). + \ '/ contains=VimwikiBoldItalicChar,VimwikiItalicBoldChar,@Spell' +execute 'syntax match VimwikiItalicBoldT /'.vimwiki#vars#get_syntaxlocal('rxItalicBold'). + \ '/ contained contains=VimwikiBoldItalicCharT,VimsikiItalicBoldCharT,@Spell' + +execute 'syntax match VimwikiDelText /'.vimwiki#vars#get_syntaxlocal('rxDelText'). + \ '/ contains=VimwikiDelTextChar,@Spell' +execute 'syntax match VimwikiDelTextT /'.vimwiki#vars#get_syntaxlocal('rxDelText'). + \ '/ contained contains=VimwikiDelTextCharT,@Spell' + +execute 'syntax match VimwikiSuperScript /'.vimwiki#vars#get_syntaxlocal('rxSuperScript'). + \ '/ contains=VimwikiSuperScriptChar,@Spell' +execute 'syntax match VimwikiSuperScriptT /'.vimwiki#vars#get_syntaxlocal('rxSuperScript'). + \ '/ contained contains=VimwikiSuperScriptCharT,@Spell' + +execute 'syntax match VimwikiSubScript /'.vimwiki#vars#get_syntaxlocal('rxSubScript'). + \ '/ contains=VimwikiSubScriptChar,@Spell' +execute 'syntax match VimwikiSubScriptT /'.vimwiki#vars#get_syntaxlocal('rxSubScript'). + \ '/ contained contains=VimwikiSubScriptCharT,@Spell' + +execute 'syntax match VimwikiCode /'.vimwiki#vars#get_syntaxlocal('rxCode'). + \ '/ contains=VimwikiCodeChar' +execute 'syntax match VimwikiCodeT /'.vimwiki#vars#get_syntaxlocal('rxCode'). + \ '/ contained contains=VimwikiCodeCharT' + + +" <hr> horizontal rule +execute 'syntax match VimwikiHR /'.vimwiki#vars#get_syntaxlocal('rxHR').'/' + +execute 'syntax region VimwikiPre start=/'.vimwiki#vars#get_syntaxlocal('rxPreStart'). + \ '/ end=/'.vimwiki#vars#get_syntaxlocal('rxPreEnd').'/ contains=@Spell' + +execute 'syntax region VimwikiMath start=/'.vimwiki#vars#get_syntaxlocal('rxMathStart'). + \ '/ end=/'.vimwiki#vars#get_syntaxlocal('rxMathEnd').'/ contains=@Spell' + + +" placeholders +syntax match VimwikiPlaceholder /^\s*%nohtml\s*$/ +syntax match VimwikiPlaceholder + \ /^\s*%title\ze\%(\s.*\)\?$/ nextgroup=VimwikiPlaceholderParam skipwhite +syntax match VimwikiPlaceholder + \ /^\s*%date\ze\%(\s.*\)\?$/ nextgroup=VimwikiPlaceholderParam skipwhite +syntax match VimwikiPlaceholder + \ /^\s*%template\ze\%(\s.*\)\?$/ nextgroup=VimwikiPlaceholderParam skipwhite +syntax match VimwikiPlaceholderParam /.*/ contained + + +" html tags +if vimwiki#vars#get_global('valid_html_tags') != '' + let s:html_tags = join(split(vimwiki#vars#get_global('valid_html_tags'), '\s*,\s*'), '\|') + exe 'syntax match VimwikiHTMLtag #\c</\?\%('.s:html_tags.'\)\%(\s\{-1}\S\{-}\)\{-}\s*/\?>#' + execute 'syntax match VimwikiBold #\c<b>.\{-}</b># contains=VimwikiHTMLTag' + execute 'syntax match VimwikiItalic #\c<i>.\{-}</i># contains=VimwikiHTMLTag' + execute 'syntax match VimwikiUnderline #\c<u>.\{-}</u># contains=VimwikiHTMLTag' + + execute 'syntax match VimwikiComment /'.vimwiki#vars#get_syntaxlocal('rxComment'). + \ '/ contains=@Spell,VimwikiTodo' +endif + +" tags +execute 'syntax match VimwikiTag /'.vimwiki#vars#get_syntaxlocal('rxTags').'/' + + + +" header groups highlighting +if vimwiki#vars#get_global('hl_headers') == 0 + " Strangely in default colorscheme Title group is not set to bold for cterm... + if !exists("g:colors_name") + hi Title cterm=bold + endif + for s:i in range(1,6) + execute 'hi def link VimwikiHeader'.s:i.' Title' + endfor +else + for s:i in range(1,6) + execute 'hi def VimwikiHeader'.s:i.' guibg=bg guifg=' + \ .vimwiki#vars#get_global('hcolor_guifg_'.&bg)[s:i-1].' gui=bold ctermfg=' + \ .vimwiki#vars#get_global('hcolor_ctermfg_'.&bg)[s:i-1].' term=bold cterm=bold' + endfor +endif + + + +hi def link VimwikiMarkers Normal + +hi def link VimwikiEqIn Number +hi def link VimwikiEqInT VimwikiEqIn + +hi def VimwikiBold term=bold cterm=bold gui=bold +hi def link VimwikiBoldT VimwikiBold + +hi def VimwikiItalic term=italic cterm=italic gui=italic +hi def link VimwikiItalicT VimwikiItalic + +hi def VimwikiBoldItalic term=bold cterm=bold gui=bold,italic +hi def link VimwikiItalicBold VimwikiBoldItalic +hi def link VimwikiBoldItalicT VimwikiBoldItalic +hi def link VimwikiItalicBoldT VimwikiBoldItalic + +hi def VimwikiUnderline gui=underline + +hi def link VimwikiCode PreProc +hi def link VimwikiCodeT VimwikiCode + +hi def link VimwikiPre PreProc +hi def link VimwikiPreT VimwikiPre + +hi def link VimwikiMath Number +hi def link VimwikiMathT VimwikiMath + +hi def link VimwikiNoExistsLink SpellBad +hi def link VimwikiNoExistsLinkT VimwikiNoExistsLink + +hi def link VimwikiLink Underlined +hi def link VimwikiLinkT VimwikiLink + +hi def link VimwikiList Identifier +hi def link VimwikiListTodo VimwikiList +hi def link VimwikiCheckBoxDone Comment +hi def link VimwikiHR Identifier +hi def link VimwikiTag Keyword + +hi def link VimwikiDelText Constant +hi def link VimwikiDelTextT VimwikiDelText + +hi def link VimwikiSuperScript Number +hi def link VimwikiSuperScriptT VimwikiSuperScript + +hi def link VimwikiSubScript Number +hi def link VimwikiSubScriptT VimwikiSubScript + +hi def link VimwikiTodo Todo +hi def link VimwikiComment Comment + +hi def link VimwikiPlaceholder SpecialKey +hi def link VimwikiPlaceholderParam String +hi def link VimwikiHTMLtag SpecialKey + +hi def link VimwikiEqInChar VimwikiMarkers +hi def link VimwikiCellSeparator VimwikiMarkers +hi def link VimwikiBoldChar VimwikiMarkers +hi def link VimwikiItalicChar VimwikiMarkers +hi def link VimwikiBoldItalicChar VimwikiMarkers +hi def link VimwikiItalicBoldChar VimwikiMarkers +hi def link VimwikiDelTextChar VimwikiMarkers +hi def link VimwikiSuperScriptChar VimwikiMarkers +hi def link VimwikiSubScriptChar VimwikiMarkers +hi def link VimwikiCodeChar VimwikiMarkers +hi def link VimwikiHeaderChar VimwikiMarkers + +hi def link VimwikiEqInCharT VimwikiMarkers +hi def link VimwikiBoldCharT VimwikiMarkers +hi def link VimwikiItalicCharT VimwikiMarkers +hi def link VimwikiBoldItalicCharT VimwikiMarkers +hi def link VimwikiItalicBoldCharT VimwikiMarkers +hi def link VimwikiDelTextCharT VimwikiMarkers +hi def link VimwikiSuperScriptCharT VimwikiMarkers +hi def link VimwikiSubScriptCharT VimwikiMarkers +hi def link VimwikiCodeCharT VimwikiMarkers +hi def link VimwikiHeaderCharT VimwikiMarkers +hi def link VimwikiLinkCharT VimwikiLinkT +hi def link VimwikiNoExistsLinkCharT VimwikiNoExistsLinkT + + +" Load syntax-specific functionality +call vimwiki#u#reload_regexes_custom() + + +" FIXME it now does not make sense to pretend there is a single syntax "vimwiki" +let b:current_syntax="vimwiki" + + +" EMBEDDED syntax setup +let s:nested = vimwiki#vars#get_wikilocal('nested_syntaxes') +if vimwiki#vars#get_wikilocal('automatic_nested_syntaxes') + let s:nested = extend(s:nested, vimwiki#base#detect_nested_syntax(), "keep") +endif +if !empty(s:nested) + for [s:hl_syntax, s:vim_syntax] in items(s:nested) + call vimwiki#base#nested_syntax(s:vim_syntax, + \ vimwiki#vars#get_syntaxlocal('rxPreStart').'\%(.*[[:blank:][:punct:]]\)\?'. + \ s:hl_syntax.'\%([[:blank:][:punct:]].*\)\?', + \ vimwiki#vars#get_syntaxlocal('rxPreEnd'), 'VimwikiPre') + endfor +endif + + +" LaTeX +call vimwiki#base#nested_syntax('tex', + \ vimwiki#vars#get_syntaxlocal('rxMathStart').'\%(.*[[:blank:][:punct:]]\)\?'. + \ '\%([[:blank:][:punct:]].*\)\?', + \ vimwiki#vars#get_syntaxlocal('rxMathEnd'), 'VimwikiMath') + + +syntax spell toplevel + diff --git a/.config/nvim/syntax/vimwiki_default.vim b/.config/nvim/syntax/vimwiki_default.vim @@ -0,0 +1,110 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki syntax file +" Description: Defines default syntax +" Home: https://github.com/vimwiki/vimwiki/ + + +" s:default_syntax is kind of a reference to the dict in +" g:vimwiki_syntax_variables['default']. It is used here simply as an +" abbreviation for the latter. +let s:default_syntax = g:vimwiki_syntax_variables['default'] + + + +" text: $ equation_inline $ +let s:default_syntax.rxEqIn = '\$[^$`]\+\$' +let s:default_syntax.char_eqin = '\$' + +" text: *strong* +" let s:default_syntax.rxBold = '\*[^*]\+\*' +let s:default_syntax.rxBold = '\%(^\|\s\|[[:punct:]]\)\@<='. + \'\*'. + \'\%([^*`[:space:]][^*`]*[^*`[:space:]]\|[^*`[:space:]]\)'. + \'\*'. + \'\%([[:punct:]]\|\s\|$\)\@=' +let s:default_syntax.char_bold = '*' + +" text: _emphasis_ +" let s:default_syntax.rxItalic = '_[^_]\+_' +let s:default_syntax.rxItalic = '\%(^\|\s\|[[:punct:]]\)\@<='. + \'_'. + \'\%([^_`[:space:]][^_`]*[^_`[:space:]]\|[^_`[:space:]]\)'. + \'_'. + \'\%([[:punct:]]\|\s\|$\)\@=' +let s:default_syntax.char_italic = '_' + +" text: *_bold italic_* or _*italic bold*_ +let s:default_syntax.rxBoldItalic = '\%(^\|\s\|[[:punct:]]\)\@<='. + \'\*_'. + \'\%([^*_`[:space:]][^*_`]*[^*_`[:space:]]\|[^*_`[:space:]]\)'. + \'_\*'. + \'\%([[:punct:]]\|\s\|$\)\@=' +let s:default_syntax.char_bolditalic = '\*_' + +let s:default_syntax.rxItalicBold = '\%(^\|\s\|[[:punct:]]\)\@<='. + \'_\*'. + \'\%([^*_`[:space:]][^*_`]*[^*_`[:space:]]\|[^*_`[:space:]]\)'. + \'\*_'. + \'\%([[:punct:]]\|\s\|$\)\@=' +let s:default_syntax.char_italicbold = '_\*' + +" text: `code` +let s:default_syntax.rxCode = '`[^`]\+`' +let s:default_syntax.char_code = '`' + +" text: ~~deleted text~~ +let s:default_syntax.rxDelText = '\~\~[^~`]\+\~\~' +let s:default_syntax.char_deltext = '\~\~' + +" text: ^superscript^ +let s:default_syntax.rxSuperScript = '\^[^^`]\+\^' +let s:default_syntax.char_superscript = '^' + +" text: ,,subscript,, +let s:default_syntax.rxSubScript = ',,[^,`]\+,,' +let s:default_syntax.char_subscript = ',,' + +" generic headers +let s:default_syntax.rxH = '=' +let s:default_syntax.symH = 1 + + + +" <hr>, horizontal rule +let s:default_syntax.rxHR = '^-----*$' + +" Tables. Each line starts and ends with '|'; each cell is separated by '|' +let s:default_syntax.rxTableSep = '|' + +" Lists +let s:default_syntax.bullet_types = ['-', '*', '#'] +" 1 means the bullets can be repeatet to indicate the level, like * ** *** +" 0 means the bullets stand on their own and the level is indicated by the indentation +let s:default_syntax.recurring_bullets = 0 +let s:default_syntax.number_types = ['1)', '1.', 'i)', 'I)', 'a)', 'A)'] +"this should contain at least one element +"it is used for i_<C-L><C-J> among other things +let s:default_syntax.list_markers = ['-', '1.', '*', 'I)', 'a)'] +let s:default_syntax.rxListDefine = '::\(\s\|$\)' + +" Preformatted text +let s:default_syntax.rxPreStart = '{{{' +let s:default_syntax.rxPreEnd = '}}}' + +" Math block +let s:default_syntax.rxMathStart = '{{\$' +let s:default_syntax.rxMathEnd = '}}\$' + +let s:default_syntax.rxComment = '^\s*%%.*$' +let s:default_syntax.rxTags = '\%(^\|\s\)\@<=:\%([^:''[:space:]]\+:\)\+\%(\s\|$\)\@=' + +let s:default_syntax.header_search = '^\s*\(=\{1,6}\)\([^=].*[^=]\)\1\s*$' +let s:default_syntax.header_match = '^\s*\(=\{1,6}\)=\@!\s*__Header__\s*\1=\@!\s*$' +let s:default_syntax.bold_search = '\%(^\|\s\|[[:punct:]]\)\@<=\*\zs\%([^*`[:space:]][^*`]*'. + \ '[^*`[:space:]]\|[^*`[:space:]]\)\ze\*\%([[:punct:]]\|\s\|$\)\@=' +let s:default_syntax.bold_match = '\%(^\|\s\|[[:punct:]]\)\@<=\*__Text__\*'. + \ '\%([[:punct:]]\|\s\|$\)\@=' +let s:default_syntax.wikilink = '\[\[\zs[^\\\]|]\+\ze\%(|[^\\\]]\+\)\?\]\]' +let s:default_syntax.tag_search = '\(^\|\s\)\zs:\([^:''[:space:]]\+:\)\+\ze\(\s\|$\)' +let s:default_syntax.tag_match = '\(^\|\s\):\([^:''[:space:]]\+:\)*__Tag__:'. + \ '\([^:[:space:]]\+:\)*\(\s\|$\)' diff --git a/.config/nvim/syntax/vimwiki_markdown.vim b/.config/nvim/syntax/vimwiki_markdown.vim @@ -0,0 +1,104 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki syntax file +" Description: Defines markdown syntax +" Home: https://github.com/vimwiki/vimwiki/ + + +" see the comments in vimwiki_default.vim for some info about this file + + +let s:markdown_syntax = g:vimwiki_syntax_variables['markdown'] + +" text: $ equation_inline $ +let s:markdown_syntax.rxEqIn = '\$[^$`]\+\$' +let s:markdown_syntax.char_eqin = '\$' + +" text: *strong* +" let s:markdown_syntax.rxBold = '\*[^*]\+\*' +let s:markdown_syntax.rxBold = '\%(^\|\s\|[[:punct:]]\)\@<='. + \'\*'. + \'\%([^*`[:space:]][^*`]*[^*`[:space:]]\|[^*`[:space:]]\)'. + \'\*'. + \'\%([[:punct:]]\|\s\|$\)\@=' +let s:markdown_syntax.char_bold = '*' + +" text: _emphasis_ +" let s:markdown_syntax.rxItalic = '_[^_]\+_' +let s:markdown_syntax.rxItalic = '\%(^\|\s\|[[:punct:]]\)\@<='. + \'_'. + \'\%([^_`[:space:]][^_`]*[^_`[:space:]]\|[^_`[:space:]]\)'. + \'_'. + \'\%([[:punct:]]\|\s\|$\)\@=' +let s:markdown_syntax.char_italic = '_' + +" text: *_bold italic_* or _*italic bold*_ +let s:markdown_syntax.rxBoldItalic = '\%(^\|\s\|[[:punct:]]\)\@<='. + \'\*_'. + \'\%([^*_`[:space:]][^*_`]*[^*_`[:space:]]\|[^*_`[:space:]]\)'. + \'_\*'. + \'\%([[:punct:]]\|\s\|$\)\@=' +let s:markdown_syntax.char_bolditalic = '\*_' + +let s:markdown_syntax.rxItalicBold = '\%(^\|\s\|[[:punct:]]\)\@<='. + \'_\*'. + \'\%([^*_`[:space:]][^*_`]*[^*_`[:space:]]\|[^*_`[:space:]]\)'. + \'\*_'. + \'\%([[:punct:]]\|\s\|$\)\@=' +let s:markdown_syntax.char_italicbold = '_\*' + +" text: `code` +let s:markdown_syntax.rxCode = '`[^`]\+`' +let s:markdown_syntax.char_code = '`' + +" text: ~~deleted text~~ +let s:markdown_syntax.rxDelText = '\~\~[^~`]\+\~\~' +let s:markdown_syntax.char_deltext = '\~\~' + +" text: ^superscript^ +let s:markdown_syntax.rxSuperScript = '\^[^^`]\+\^' +let s:markdown_syntax.char_superscript = '^' + +" text: ,,subscript,, +let s:markdown_syntax.rxSubScript = ',,[^,`]\+,,' +let s:markdown_syntax.char_subscript = ',,' + +" generic headers +let s:markdown_syntax.rxH = '#' +let s:markdown_syntax.symH = 0 + + + +" <hr>, horizontal rule +let s:markdown_syntax.rxHR = '^-----*$' + +" Tables. Each line starts and ends with '|'; each cell is separated by '|' +let s:markdown_syntax.rxTableSep = '|' + +" Lists +let s:markdown_syntax.bullet_types = ['-', '*', '+'] +let s:markdown_syntax.recurring_bullets = 0 +let s:markdown_syntax.number_types = ['1.'] +let s:markdown_syntax.list_markers = ['-', '*', '+', '1.'] +let s:markdown_syntax.rxListDefine = '::\%(\s\|$\)' + +" Preformatted text +let s:markdown_syntax.rxPreStart = '```' +let s:markdown_syntax.rxPreEnd = '```' + +" Math block +let s:markdown_syntax.rxMathStart = '\$\$' +let s:markdown_syntax.rxMathEnd = '\$\$' + +let s:markdown_syntax.rxComment = '^\s*%%.*$\|<!--[^>]*-->' +let s:markdown_syntax.rxTags = '\%(^\|\s\)\@<=:\%([^:[:space:]]\+:\)\+\%(\s\|$\)\@=' + +let s:markdown_syntax.header_search = '^\s*\(#\{1,6}\)\([^#].*\)$' +let s:markdown_syntax.header_match = '^\s*\(#\{1,6}\)#\@!\s*__Header__\s*$' +let s:markdown_syntax.bold_search = '\%(^\|\s\|[[:punct:]]\)\@<=\*\zs'. + \ '\%([^*`[:space:]][^*`]*[^*`[:space:]]\|[^*`[:space:]]\)\ze\*\%([[:punct:]]\|\s\|$\)\@=' +let s:markdown_syntax.bold_match = '\%(^\|\s\|[[:punct:]]\)\@<=\*__Text__\*'. + \ '\%([[:punct:]]\|\s\|$\)\@=' +let s:markdown_syntax.wikilink = '\[\[\zs[^\\\]|]\+\ze\%(|[^\\\]]\+\)\?\]\]' +let s:markdown_syntax.tag_search = '\(^\|\s\)\zs:\([^:''[:space:]]\+:\)\+\ze\(\s\|$\)' +let s:markdown_syntax.tag_match = '\(^\|\s\):\([^:''[:space:]]\+:\)*__Tag__:'. + \ '\([^:[:space:]]\+:\)*\(\s\|$\)' diff --git a/.config/nvim/syntax/vimwiki_markdown_custom.vim b/.config/nvim/syntax/vimwiki_markdown_custom.vim @@ -0,0 +1,194 @@ + + + + + + +function! s:add_target_syntax_ON(target, type) + let prefix0 = 'syntax match '.a:type.' `' + let suffix0 = '` display contains=@NoSpell,VimwikiLinkRest,'.a:type.'Char' + let prefix1 = 'syntax match '.a:type.'T `' + let suffix1 = '` display contained' + execute prefix0. a:target. suffix0 + execute prefix1. a:target. suffix1 +endfunction + + +function! s:add_target_syntax_OFF(target, type) + let prefix0 = 'syntax match VimwikiNoExistsLink `' + let suffix0 = '` display contains=@NoSpell,VimwikiLinkRest,'.a:type.'Char' + let prefix1 = 'syntax match VimwikiNoExistsLinkT `' + let suffix1 = '` display contained' + execute prefix0. a:target. suffix0 + execute prefix1. a:target. suffix1 +endfunction + + +function! s:wrap_wikilink1_rx(target) + return vimwiki#vars#get_syntaxlocal('rxWikiLink1InvalidPrefix') . a:target. + \ vimwiki#vars#get_syntaxlocal('rxWikiLink1InvalidSuffix') +endfunction + + +function! s:existing_mkd_refs() + return keys(vimwiki#markdown_base#scan_reflinks()) +endfunction + + +function! s:highlight_existing_links() + " Wikilink1 + " Conditional highlighting that depends on the existence of a wiki file or + " directory is only available for *schemeless* wiki links + " Links are set up upon BufEnter (see plugin/...) + let safe_links = '\%('. + \ vimwiki#base#file_pattern(vimwiki#vars#get_bufferlocal('existing_wikifiles')) . + \ '\%(#[^|]*\)\?\|#[^|]*\)' + " Wikilink1 Dirs set up upon BufEnter (see plugin/...) + let safe_dirs = vimwiki#base#file_pattern(vimwiki#vars#get_bufferlocal('existing_wikidirs')) + " Ref links are cached + let safe_reflinks = vimwiki#base#file_pattern(s:existing_mkd_refs()) + + + " match [URL][] + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_syntaxlocal('WikiLink1Template1')), + \ safe_links, vimwiki#vars#get_syntaxlocal('rxWikiLink1Descr'), '') + call s:add_target_syntax_ON(s:wrap_wikilink1_rx(target), 'VimwikiWikiLink1') + " match [DESCRIPTION][URL] + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_syntaxlocal('WikiLink1Template2')), + \ safe_links, vimwiki#vars#get_syntaxlocal('rxWikiLink1Descr'), '') + call s:add_target_syntax_ON(s:wrap_wikilink1_rx(target), 'VimwikiWikiLink1') + + " match [DIRURL][] + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_syntaxlocal('WikiLink1Template1')), + \ safe_dirs, vimwiki#vars#get_syntaxlocal('rxWikiLink1Descr'), '') + call s:add_target_syntax_ON(s:wrap_wikilink1_rx(target), 'VimwikiWikiLink1') + " match [DESCRIPTION][DIRURL] + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_syntaxlocal('WikiLink1Template2')), + \ safe_dirs, vimwiki#vars#get_syntaxlocal('rxWikiLink1Descr'), '') + call s:add_target_syntax_ON(s:wrap_wikilink1_rx(target), 'VimwikiWikiLink1') + + " match [MKDREF][] + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_syntaxlocal('WikiLink1Template1')), + \ safe_reflinks, vimwiki#vars#get_syntaxlocal('rxWikiLink1Descr'), '') + call s:add_target_syntax_ON(s:wrap_wikilink1_rx(target), 'VimwikiWikiLink1') + " match [DESCRIPTION][MKDREF] + let target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_syntaxlocal('WikiLink1Template2')), + \ safe_reflinks, vimwiki#vars#get_syntaxlocal('rxWikiLink1Descr'), '') + call s:add_target_syntax_ON(s:wrap_wikilink1_rx(target), 'VimwikiWikiLink1') +endfunction + + +" use max highlighting - could be quite slow if there are too many wikifiles +if vimwiki#vars#get_wikilocal('maxhi') + " WikiLink + call s:add_target_syntax_OFF(vimwiki#vars#get_syntaxlocal('rxWikiLink1'), 'VimwikiWikiLink1') + + " Subsequently, links verified on vimwiki's path are highlighted as existing + call s:highlight_existing_links() +else + " Wikilink + call s:add_target_syntax_ON(vimwiki#vars#get_syntaxlocal('rxWikiLink1'), 'VimwikiWikiLink1') +endif + + +" Weblink +call s:add_target_syntax_ON(vimwiki#vars#get_syntaxlocal('rxWeblink1'), 'VimwikiWeblink1') + + +" WikiLink +" All remaining schemes are highlighted automatically +let s:rxSchemes = '\%('. + \ vimwiki#vars#get_global('schemes') . '\|'. + \ vimwiki#vars#get_global('web_schemes1'). + \ '\):' + +" a) match [nonwiki-scheme-URL] +let s:target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_syntaxlocal('WikiLink1Template1')), + \ s:rxSchemes . vimwiki#vars#get_syntaxlocal('rxWikiLink1Url'), + \ vimwiki#vars#get_syntaxlocal('rxWikiLink1Descr'), '') +call s:add_target_syntax_ON(s:wrap_wikilink1_rx(s:target), 'VimwikiWikiLink1') +" b) match [DESCRIPTION][nonwiki-scheme-URL] +let s:target = vimwiki#base#apply_template( + \ vimwiki#u#escape(vimwiki#vars#get_syntaxlocal('WikiLink1Template2')), + \ s:rxSchemes . vimwiki#vars#get_syntaxlocal('rxWikiLink1Url'), + \ vimwiki#vars#get_syntaxlocal('rxWikiLink1Descr'), '') +call s:add_target_syntax_ON(s:wrap_wikilink1_rx(s:target), 'VimwikiWikiLink1') + + + +" Header levels, 1-6 +for s:i in range(1,6) + execute 'syntax match VimwikiHeader'.s:i.' /'.vimwiki#vars#get_syntaxlocal('rxH'.s:i). + \ '/ contains=VimwikiTodo,VimwikiHeaderChar,VimwikiNoExistsLink,VimwikiCode,'. + \ 'VimwikiLink,VimwikiWeblink1,VimwikiWikiLink1,@Spell' +endfor + + + +" concealed chars +if exists("+conceallevel") + syntax conceal on +endif + +syntax spell toplevel + +" VimwikiWikiLink1Char is for syntax markers (and also URL when a description +" is present) and may be concealed +let s:options = ' contained transparent contains=NONE' +" conceal wikilink1 +execute 'syn match VimwikiWikiLink1Char /'. + \ vimwiki#vars#get_syntaxlocal('rx_wikilink_md_prefix').'/'.s:options +execute 'syn match VimwikiWikiLink1Char /'. + \ vimwiki#vars#get_syntaxlocal('rx_wikilink_md_suffix').'/'.s:options +execute 'syn match VimwikiWikiLink1Char /'. + \ vimwiki#vars#get_syntaxlocal('rxWikiLink1Prefix1').'/'.s:options +execute 'syn match VimwikiWikiLink1Char /'. + \ vimwiki#vars#get_syntaxlocal('rxWikiLink1Suffix1').'/'.s:options + +" conceal weblink1 +execute 'syn match VimwikiWeblink1Char "'. + \ vimwiki#vars#get_syntaxlocal('rxWeblink1Prefix1').'"'.s:options +execute 'syn match VimwikiWeblink1Char "'. + \ vimwiki#vars#get_syntaxlocal('rxWeblink1Suffix1').'"'.s:options + +if exists("+conceallevel") + syntax conceal off +endif + + + +" Tables +syntax match VimwikiTableRow /^\s*|.\+|\s*$/ + \ transparent contains=VimwikiCellSeparator, + \ VimwikiLinkT, + \ VimwikiWeblink1T, + \ VimwikiWikiLink1T, + \ VimwikiNoExistsLinkT, + \ VimwikiTodo, + \ VimwikiBoldT, + \ VimwikiItalicT, + \ VimwikiBoldItalicT, + \ VimwikiItalicBoldT, + \ VimwikiDelTextT, + \ VimwikiSuperScriptT, + \ VimwikiSubScriptT, + \ VimwikiCodeT, + \ VimwikiEqInT, + \ @Spell + + + +" syntax group highlighting +hi def link VimwikiWeblink1 VimwikiLink +hi def link VimwikiWeblink1T VimwikiLink + +hi def link VimwikiWikiLink1 VimwikiLink +hi def link VimwikiWikiLink1T VimwikiLink + diff --git a/.config/nvim/syntax/vimwiki_media.vim b/.config/nvim/syntax/vimwiki_media.vim @@ -0,0 +1,85 @@ +" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99 +" Vimwiki syntax file +" Description: Defines mediaWiki syntax +" Home: https://github.com/vimwiki/vimwiki/ + + +" see the comments in vimwiki_default.vim for some info about this file + + +let s:media_syntax = g:vimwiki_syntax_variables['media'] + +" text: $ equation_inline $ +let s:media_syntax.rxEqIn = '\$[^$`]\+\$' +let s:media_syntax.char_eqin = '\$' + +" text: '''strong''' +let s:media_syntax.rxBold = "'''[^']\\+'''" +let s:media_syntax.char_bold = "'''" + +" text: ''emphasis'' +let s:media_syntax.rxItalic = "''[^']\\+''" +let s:media_syntax.char_italic = "''" + +" text: '''''strong italic''''' +let s:media_syntax.rxBoldItalic = "'''''[^']\\+'''''" +let s:media_syntax.rxItalicBold = s:media_syntax.rxBoldItalic +let s:media_syntax.char_bolditalic = "'''''" +let s:media_syntax.char_italicbold = s:media_syntax.char_bolditalic + +" text: `code` +let s:media_syntax.rxCode = '`[^`]\+`' +let s:media_syntax.char_code = '`' + +" text: ~~deleted text~~ +let s:media_syntax.rxDelText = '\~\~[^~]\+\~\~' +let s:media_syntax.char_deltext = '\~\~' + +" text: ^superscript^ +let s:media_syntax.rxSuperScript = '\^[^^]\+\^' +let s:media_syntax.char_superscript = '^' + +" text: ,,subscript,, +let s:media_syntax.rxSubScript = ',,[^,]\+,,' +let s:media_syntax.char_subscript = ',,' + +" generic headers +let s:media_syntax.rxH = '=' +let s:media_syntax.symH = 1 + + + +" <hr>, horizontal rule +let s:media_syntax.rxHR = '^-----*$' + +" Tables. Each line starts and ends with '|'; each cell is separated by '|' +let s:media_syntax.rxTableSep = '|' + +" Lists +let s:media_syntax.bullet_types = ['*', '#'] +let s:media_syntax.recurring_bullets = 1 +let s:media_syntax.number_types = [] +let s:media_syntax.list_markers = ['*', '#'] +let s:media_syntax.rxListDefine = '^\%(;\|:\)\s' + +" Preformatted text +let s:media_syntax.rxPreStart = '<pre>' +let s:media_syntax.rxPreEnd = '<\/pre>' + +" Math block +let s:media_syntax.rxMathStart = '{{\$' +let s:media_syntax.rxMathEnd = '}}\$' + +let s:media_syntax.rxComment = '^\s*%%.*$' +let s:media_syntax.rxTags = '\%(^\|\s\)\@<=:\%([^:[:space:]]\+:\)\+\%(\s\|$\)\@=' + +let s:media_syntax.header_search = '^\s*\(=\{1,6}\)\([^=].*[^=]\)\1\s*$' +let s:media_syntax.header_match = '^\s*\(=\{1,6}\)=\@!\s*__Header__\s*\1=\@!\s*$' +let s:media_syntax.bold_search = "'''\\zs[^']\\+\\ze'''" +let s:media_syntax.bold_match = '''''''__Text__''''''' +" ^- this strange looking thing is equivalent to "'''__Text__'''" but since we later +" want to call escape() on this string, we must keep it in single quotes +let s:media_syntax.wikilink = '\[\[\zs[^\\\]|]\+\ze\%(|[^\\\]]\+\)\?\]\]' +let s:media_syntax.tag_search = '\(^\|\s\)\zs:\([^:''[:space:]]\+:\)\+\ze\(\s\|$\)' +let s:media_syntax.tag_match = '\(^\|\s\):\([^:''[:space:]]\+:\)*__Tag__:'. + \ '\([^:[:space:]]\+:\)*\(\s\|$\)' diff --git a/.config/zsh/functions b/.config/zsh/functions @@ -1,25 +1,27 @@ #!/bin/sh killprog(){ for prog in $(printf "$@") - do - pkill $prog - done + do + pkill $prog + done } 0x0(){ for file in $(printf "$@") - do - name=$(curl -n -F "file=@$file" http://0x0.st) - echo "$file has been hosted at $name" - done + do + name=$(curl -n -F "file=@$file" http://0x0.st) + echo "$file has been hosted at $name" + echo "$name" | xclip + done } ix(){ for file in $(printf "$@") - do - name=$(curl -n -F "f:1=<-" http://ix.io < $file) - echo "$file has been hosted at $name" - done + do + name=$(curl -n -F "f:1=<-" http://ix.io < $file) + echo "$file has been hosted at $name" + echo "$name" | xclip + done } pc(){ diff --git a/.scripts/bin/misc/drefresh b/.scripts/bin/misc/drefresh @@ -0,0 +1,4 @@ +#!/bin/sh + +hkill dunst +dunst &