pax_global_header 0000666 0000000 0000000 00000000064 14554351005 0014514 g ustar 00root root 0000000 0000000 52 comment=fde35bb87e45abe930eebef5ab99a16289e53789
vimwiki-2024.01.24/ 0000775 0000000 0000000 00000000000 14554351005 0013567 5 ustar 00root root 0000000 0000000 vimwiki-2024.01.24/.github/ 0000775 0000000 0000000 00000000000 14554351005 0015127 5 ustar 00root root 0000000 0000000 vimwiki-2024.01.24/.github/issue_template.md 0000664 0000000 0000000 00000000526 14554351005 0020477 0 ustar 00root root 0000000 0000000 Prior to submitting a new issue make sure to complete these steps:
- [ ] Include the VimWiki settings from your `.vimrc`
- [ ] Include the syntax you are using (default / Markdown / MediaWiki)
- [ ] Provide a detailed description of the problem including **steps to reproduce the issue**.
- [ ] Include the output of `:VimwikiShowVersion`.
vimwiki-2024.01.24/.github/pull_request_template.md 0000664 0000000 0000000 00000000767 14554351005 0022102 0 ustar 00root root 0000000 0000000 Steps for submitting a pull request:
- [ ] **ALL** pull requests should be made against the `dev` branch!
- [ ] Take a look at [CONTRIBUTING.MD](https://github.com/vimwiki/vimwiki/blob/dev/CONTRIBUTING.md)
- [ ] Reference any related issues.
- [ ] Provide a description of the proposed changes.
- [ ] PRs must pass Vint tests and add new Vader tests as applicable.
- [ ] Make sure to update the documentation in `doc/vimwiki.txt` if applicable,
including the Changelog and Contributors sections.
vimwiki-2024.01.24/.github/workflows/ 0000775 0000000 0000000 00000000000 14554351005 0017164 5 ustar 00root root 0000000 0000000 vimwiki-2024.01.24/.github/workflows/test-vader-action.yml 0000664 0000000 0000000 00000006111 14554351005 0023237 0 ustar 00root root 0000000 0000000 ---
# Copied from previous .travis.yml by tinmarino the 2023-03-09
# Commented out to avoid verbosity on github commit status
name: CI
# yamllint disable-line rule:truthy
on: [push, pull_request, workflow_dispatch]
jobs:
Typos:
# Copied from: https://github.com/junegunn/fzf/blob/master/
# -- .github/workflows/typos.yml
name: Typos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: crate-ci/typos@v1.13.16
with:
config: ./test/resources/typos_config.toml
Yamllint:
# Copied from: https://github.com/junegunn/fzf/blob/master/
# -- .github/workflows/typos.yml
name: Yamllint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: ibiqlik/action-yamllint@v3
with:
file_or_dir: .github/workflows/test-vader-action.yml
Vint:
# Copied from: https://github.com/LudvigHz/vint-action
# And local ./test/run_test.sh
name: Vint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: ludvighz/vint-action@v1
with:
path: .
args: --style-problem
- uses: ludvighz/vint-action@v1
with:
path: test/vimrc
args: --style-problem
Check:
name: Check ${{ matrix.opt }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
opt: [
# "vint",
"-n vim_7.3.429",
"-n vim_8.1.0519",
# TODO add me when test works on Vim, 9.0
# -- Currently I experienced some surprised due to defaults
# -- tinmarino 2023-03-10
# "-n v9.0.1396",
"-n nvim_0.3.8",
# Cannot quote as it is expanded from $OPT after quote removal
# So I decided to escape the *
"-n vim_7.4.1099 -f '[a-k]*.vader'",
"-n vim_7.4.1546 -f 'l*.vader'",
"-n vim_8.0.0027 -f '[m-z]*.vader'",
]
steps:
# This action is required to fetch the code to test
- uses: actions/checkout@v3
with:
fetch-depth: 0
# This action is crafting the docker image from the root Docker file
# or will use it is exists in cache
# It caches in GHA for GitHub Actions with 10 Gb
# See: https://github.com/moby/buildkit#github-actions-cache-experimental
# Examples at: https://github.com/docker/build-push-action/blob/
# e27bcee4eb9e7b4bc168418e3364c4482120393a/docs/advanced/cache.md
- uses: docker/setup-buildx-action@v2
- uses: docker/build-push-action@v2
with:
context: .
push: false
tags: vimwiki:latest
load: true
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Check
run: |
pushd test
if [[ "$OPT" == 'vint' ]]; then
bash run_tests.sh -v -t vint;
else
bash run_tests.sh -v -t vader $OPT;
fi
popd
env:
OPT: ${{ matrix.opt }}
vimwiki-2024.01.24/.gitignore 0000664 0000000 0000000 00000000505 14554351005 0015557 0 ustar 00root root 0000000 0000000 # Local stuff
# This section is devoted to this project
##############################
doc/tags
.tags
# Vim stuff
##############################
*.s[a-w][a-z]
*.un~
Session.vim
.netrwhist
*~
# OS generated files
##############################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
vimtest
vimwiki-2024.01.24/.travis.yml 0000664 0000000 0000000 00000003117 14554351005 0015702 0 ustar 00root root 0000000 0000000 # No language: we download vim and compile it oursselves
# WARNING: This file is OBSOLETE since travis CI is making us pay
# to get execution.
# See Github Actions at .github/workflows/test-vader-action.yml
language: generic
cache:
# Enable cache folder
bundler: true
directories:
- $HOME/docker_images
before_cache:
# Save tagged docker images. Info at https://github.com/travis-ci/travis-ci/issues/5358#issuecomment-248915326
- >
mkdir -p $HOME/docker_images && docker images -a --filter='dangling=false' --format '{{.Repository}}:{{.Tag}} {{.ID}}'
| xargs -n 2 -t sh -c 'test -e $HOME/docker_images/$1.tar.gz || docker save $0 | gzip -2 > $HOME/docker_images/$1.tar.gz'
before_install:
# Install docker
- n_image=$(ls -1 $HOME/docker_images/*.tar.gz | wc -l)
- if (( $n_image )); then ls $HOME/docker_images/*.tar.gz | xargs -I {file} sh -c "zcat {file} | docker load";
else docker build --tag vimwiki .;
fi
env:
# Define jobs <- vim version <- hard copied from Dockerfile
# First to be launched
- VIM_VERSION=vint
- VIM_VERSION=vim_7.3.429
- VIM_VERSION=nvim_0.3.8
- VIM_VERSION=vim_8.1.0519
# More
- VIM_VERSION=vim_7.4.1099 PATTERN='[a-k]*.vader'
- VIM_VERSION=vim_7.4.1546 PATTERN='l*.vader'
- VIM_VERSION=vim_8.0.0027 PATTERN='[m-z]*.vader'
script:
# Run All tests
- pushd test
- if [[ "$VIM_VERSION" == 'vint' ]]; then bash run_tests.sh -v -t vint;
elif [[ ! -z "$PATTERN" ]]; then bash run_tests.sh -v -t vader -n "$VIM_VERSION" -f "$PATTERN";
else bash run_tests.sh -v -t vader -n "$VIM_VERSION";
fi
- popd
# vim:sw=2:
vimwiki-2024.01.24/CONTRIBUTING.md 0000664 0000000 0000000 00000005237 14554351005 0016027 0 ustar 00root root 0000000 0000000 # Contributing to VimWiki
# Filing a bug
Before filing a bug or starting to write a patch, check the latest development
version from https://github.com/vimwiki/vimwiki/tree/dev to see if your problem
is already fixed.
Issues can be filed at https://github.com/vimwiki/vimwiki/issues/
# Git branching model
As of v2022.12.02, VimWiki has adopted a rolling release model, along with
[calendar versioning][calver]. A release should be
[prepared][#preparing-a-release] for every change or set of changes which merge
to `dev`.
[calver]: https://calver.org/
There are two permanent branches:
1. `dev`: This is the default branch, and where changes are released. Tasks
which are done in one or only a few commits go here directly. Always
keep this branch in a working state. If the task you work on requires
multiple commits, make sure intermediate commits don't make VimWiki
unusable.
2. `master`: This is a legacy branch, retained to avoid breaking existing
checkouts of the plugin. It should be kept in sync with `dev`.
Large changes which require multiple commits may be authored in feature
branches, and merged into `dev` when the work is done.
# Creating a pull request
If you want to provide a pull request on GitHub, start from the `dev` branch,
not from the `master` branch.
Version bureaucracy:
1. Pick a new version number according to the current date:
`YYYY.MM.DD` (if releasing a second version for the
current date, append a `_MICRO` version such as `_1`, `_2`, etc.
- Examples: `2022.12.22`, `2022.12.22_1`
2. Update the version number at the top of `plugin/vimwiki.vim`
3. Update the `!_TAG_PROGRAM_VERSION` expected in `test/tag.vader`
(this is a bit silly, will have to figure out how to get rid of it)
Update `doc/vimwiki.txt` with the following information:
1. Update the changelog to include, at the top of it, information on the new
feature the PR introduces or the bug it is fixing as well as the PR number
and related issue number if possible.
2. Add a help section to describe any new features or options.
3. If you are a first time contributor add your name to the list of
contributors.
# Preparing a release
This section is primarily for maintainers.
1. Set a tag with the version number in Git: `git tag -a v2022.12.02 -m 'Release v2022.12.02'`
2. `git push --tags`
3. In GitHub, go to _Releases_ -> _Draft a new release_ -> choose the tag,
convert the changelog from the doc to Markdown and post it there. Make
plans to build an automatic converter and immediately forget this plan.
4. If necessary, update `README.md` and the home page.
5. For major changes: Tell the world.
[semver]: https://semver.org/
vimwiki-2024.01.24/Dockerfile 0000664 0000000 0000000 00000001472 14554351005 0015565 0 ustar 00root root 0000000 0000000 FROM testbed/vim:latest
# Add packages
RUN apk --no-cache add bash
RUN apk --no-cache add git
RUN apk --no-cache add python3
RUN apk --no-cache add py3-pip
# Get vint for linting
RUN pip3 install vim-vint
# Get vader for unit tests
RUN git clone -n https://github.com/junegunn/vader.vim /vader
WORKDIR /vader
RUN git checkout de8a976f1eae2c2b680604205c3e8b5c8882493c
# Build vim and neovim versions we want to test
WORKDIR /
RUN install_vim -tag v7.3.429 -name vim_7.3.429 -build
RUN install_vim -tag v7.4.1099 -name vim_7.4.1099 -build
RUN install_vim -tag v7.4.1546 -name vim_7.4.1546 -build
RUN install_vim -tag v8.0.0027 -name vim_8.0.0027 -build
RUN install_vim -tag v8.1.0519 -name vim_8.1.0519 -build
RUN install_vim -tag v9.0.1396 -name v9.0.1396 -build
RUN install_vim -tag neovim:v0.3.8 -name nvim_0.3.8 -build
vimwiki-2024.01.24/LICENSE.md 0000664 0000000 0000000 00000002127 14554351005 0015175 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) 2008-2010 Maxim Kim
2013-2017 Daniel Schemala
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
vimwiki-2024.01.24/README-cn.md 0000664 0000000 0000000 00000013244 14554351005 0015450 0 ustar 00root root 0000000 0000000 VimWiki —— Vim 个人 Wiki 插件
==============================================================================
[English](README.md)

 *
介绍
------------------------------------------------------------------------------
Vimwiki 是 Vim 中的个人 Wiki —— 一组链接起来的、有独特语法高亮的文本文件。
通过 Vimwiki,你可以:
* 组织笔记和想法
* 管理待办事项
* 编写文档
* 坚持写日记
* 将这一切导出成 HTML 网页
马上开始!按下 `files
" Return:
diary file names
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) abort
" Return:
'.s:mid(a:value, 2).''
endfunction
function! s:tag_super(value) abort
return ''.s:mid(a:value, 1).''
endfunction
function! s:tag_sub(value) abort
return ''.s:mid(a:value, 2).''
endfunction
function! s:tag_code(value) abort
let l:retstr = ' 0.5)
\ ? 'black' : 'white'
let l:retstr .=
\ " style='background-color:" . l:str .
\ ';color:' . l:fg_color . ";'"
endif
let l:retstr .= '>'.s:safe_html_preformatted(l:str).''
return l:retstr
endfunction
function! s:incl_match_arg(nn_index) abort
" match n-th ARG within {{URL[|ARG1|ARG2|...]}}
" *c,d,e),...
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) abort
let src_str = ' href="'.s:escape_html_attribute(a:src).'"'
let descr = vimwiki#u#trim(a:descr)
let descr = (descr ==? '' ? a:src : descr)
let descr_str = (descr =~# vimwiki#vars#get_global('rxWikiIncl')
\ ? s:tag_wikiincl(descr)
\ : descr)
return ''.descr_str.''
endfunction
function! s:linkify_image(src, descr, verbatim_str) abort
let src_str = ' src="'.a:src.'"'
let descr_str = (a:descr !=? '' ? ' alt="'.a:descr.'"' : '')
let verbatim_str = (a:verbatim_str !=? '' ? ' '.a:verbatim_str : '')
return ''
endfunction
function! s:tag_weblink(value) abort
" Weblink Template -> descr
let str = a:value
let url = matchstr(str, vimwiki#vars#get_syntaxlocal('rxWeblinkMatchUrl'))
let descr = matchstr(str, vimwiki#vars#get_syntaxlocal('rxWeblinkMatchDescr'))
let line = s:linkify_link(url, descr)
return line
endfunction
function! s:tag_wikiincl(value) abort
" {{imgurl|arg1|arg2}} -> ???
" {{imgurl}} ->
" {{imgurl|descr|style="A"}} ->
" {{imgurl|descr|class="B"}} ->
let str = a:value
" custom transclusions
let line = VimwikiWikiIncludeHandler(str)
" otherwise, assume image transclusion
if line ==? ''
let url_0 = matchstr(str, vimwiki#vars#get_global('rxWikiInclMatchUrl'))
let descr = matchstr(str, s:incl_match_arg(1))
let verbatim_str = matchstr(str, s:incl_match_arg(2))
let link_infos = vimwiki#base#resolve_link(url_0)
if link_infos.scheme =~# '\mlocal\|wiki\d\+\|diary'
let url = vimwiki#path#relpath(fnamemodify(s:current_html_file, ':h'), link_infos.filename)
" strip the .html extension when we have wiki links, so that the user can
" simply write {{image.png}} to include an image from the wiki directory
if link_infos.scheme =~# '\mwiki\d\+\|diary'
let url = fnamemodify(url, ':r')
endif
else
let 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) abort
" [[url]] -> url
" [[url|descr]] -> descr
" [[url|{{...}}]] -> ...
" [[fileurl.ext|descr]] -> descr
" [[dirurl/|descr]] -> descr
" [[url#a1#a2]] -> url#a1#a2
" [[#a1#a2]] -> #a1#a2
let str = a:value
let url = matchstr(str, vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchUrl'))
let descr = matchstr(str, vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchDescr'))
let descr = vimwiki#u#trim(descr)
let descr = (descr !=? '' ? descr : url)
let line = VimwikiLinkConverter(url, s:current_wiki_file, s:current_html_file)
if line ==? ''
let link_infos = vimwiki#base#resolve_link(url, s:current_wiki_file)
if link_infos.scheme ==# 'file'
" external file links are always absolute
let html_link = link_infos.filename
elseif link_infos.scheme ==# 'local'
let html_link = vimwiki#path#relpath(fnamemodify(s:current_html_file, ':h'),
\ link_infos.filename)
elseif link_infos.scheme =~# '\mwiki\d\+\|diary'
" wiki links are always relative to the current file
let html_link = vimwiki#path#relpath(
\ fnamemodify(s:current_wiki_file, ':h'),
\ fnamemodify(link_infos.filename, ':r'))
if html_link !~? '\m/$'
let html_link .= '.html'
endif
else " other schemes, like http, are left untouched
let html_link = link_infos.filename
endif
if 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) abort
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) abort
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 = '
'
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, ...) abort
" 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').'\)\|'.
\ '\(\)\|'.
\ '\(
\)\|'.
\ '\(
')
else
call add(lines, '')
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, '')
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) abort
" 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_precode(line, quote) abort
" Process indented precode
let lines = []
let line = a:line
let quote = a:quote
let processed = 0
" Check if start
if line =~# '^\s\{4,}'
let line = substitute(line, '^\s*', '', '')
if !quote
" Check if must decrease level
let line = '' . line
let quote = 1
endif
let processed = 1
call add(lines, line)
" Check if end
elseif quote
call add(lines, '
')
let quote = 0
endif
return [processed, lines, quote]
endfunction
function! s:process_tag_arrow_quote(line, arrow_quote) abort
let lines = []
let arrow_quote = a:arrow_quote
let processed = 0
let line = a:line
" Check if must increase level
if line =~# '^' . repeat('\s*>', arrow_quote + 1)
" Increase arrow_quote
while line =~# '^' . repeat('\s*>', arrow_quote + 1)
call add(lines, '')
call add(lines, '')
let arrow_quote .= 1
endwhile
" Treat & Add line
let stripped_line = substitute(a:line, '^\%(\s*>\)\+', '', '')
if stripped_line =~# '^\s*$'
call add(lines, '
')
call add(lines, '')
endif
call add(lines, stripped_line)
let processed = 1
" Check if must decrease level
elseif arrow_quote > 0
while line !~# '^' . repeat('\s*>', arrow_quote - 1)
call add(lines, '
')
call add(lines, '
')
let arrow_quote -= 1
endwhile
endif
return [processed, lines, arrow_quote]
endfunction
function! s:process_tag_list(line, lists, lstLeadingSpaces) abort
function! s:add_checkbox(line, rx_list) abort
let st_tag = '')
let para = 1
endif
let processed = 1
if vimwiki#vars#get_wikilocal('text_ignore_newline')
call add(lines, a:line)
else
call add(lines, a:line.'
')
endif
elseif para && a:line =~# '^\s*$'
call add(lines, '
'
let type = split(split(split(html_lines[i], 'type=')[1], '>')[0], '\s\+')[0]
let attr = split(split(html_lines[i], '')[0]
let start = i + 1
let cur = start
while html_lines[cur] !~# '^<\/pre>'
let cur += 1
endwhile
let tmp = ('tmp'. split(system('mktemp -p . --suffix=.' . type, 'silent'), 'tmp')[-1])[:-2]
call system('echo ' . shellescape(join(html_lines[start : cur - 1], "\n")) . ' > ' . tmp)
call system(g:vimwiki_global_vars['listing_hl_command'] . ' ' . tmp . ' > ' . tmp . '.html')
let html_out = system('cat ' . tmp . '.html')
call system('rm ' . tmp . ' ' . tmp . '.html')
let i = cur
let html_lines = html_lines[0 : start - 1] + split(html_out, "\n") + html_lines[cur : ]
endif
let i += 1
endwhile
endif
call writefile(html_lines, path_html.htmlfile)
return path_html . htmlfile
endif
call vimwiki#u#error('Conversion to HTML is not supported for this syntax')
return ''
endfunction
function! vimwiki#html#Wiki2HTML(path_html, wikifile) abort
let result = s:convert_file(a:path_html, vimwiki#path#wikify_path(a:wikifile))
if result !=? ''
call s:create_default_CSS(a:path_html)
endif
return result
endfunction
function! vimwiki#html#WikiAll2HTML(path_html, force) abort
if !s:syntax_supported() && !s:use_custom_wiki2html()
call vimwiki#u#error('Conversion to HTML is not supported for this syntax')
return
endif
call vimwiki#u#echo('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)
if !vimwiki#vars#get_wikilocal('html_filename_parameterization')
call vimwiki#u#echo('Deleting non-wiki html files ...')
call s:delete_html_files(path_html)
endif
let setting_more = &more
call vimwiki#u#echo('Converting wiki to html files ...')
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 a:force || !s:is_html_uptodate(wikifile)
call vimwiki#u#echo('Processing '.wikifile)
call s:convert_file(path_html, wikifile)
else
call vimwiki#u#echo('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
call vimwiki#u#echo('Default style.css has been created')
endif
call vimwiki#u#echo('HTML exported to '.path_html)
call vimwiki#u#echo('Done!')
let &more = setting_more
endfunction
function! s:file_exists(fname) abort
return !empty(getftype(expand(a:fname)))
endfunction
function! s:binary_exists(fname) abort
return executable(expand(a:fname))
endfunction
function! s:get_wikifile_url(wikifile) abort
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) abort
execute 'r !echo file://'.s:get_wikifile_url(a:wikifile)
endfunction
function! vimwiki#html#CatUrl(wikifile) abort
execute '!echo file://'.s:get_wikifile_url(a:wikifile)
endfunction
function! s:rss_header() abort
let title = vimwiki#vars#get_wikilocal('diary_header')
let rss_url = vimwiki#vars#get_wikilocal('base_url') . vimwiki#vars#get_wikilocal('rss_name')
let link = vimwiki#vars#get_wikilocal('base_url')
\ . vimwiki#vars#get_wikilocal('diary_rel_path')
\ . vimwiki#vars#get_wikilocal('diary_index') . '.html'
let description = title
let pubdate = strftime('%a, %d %b %Y %T %z')
let header = [
\ '',
\ '',
\ '',
\ ' ' . title . ' ',
\ ' ' . link . '',
\ ' ' . description . ' ',
\ ' ' . pubdate . ' ',
\ ' '
\ ]
return header
endfunction
function! s:rss_footer() abort
let footer = [' ', ' ']
return footer
endfunction
function! s:rss_item(path, title) abort
let diary_rel_path = vimwiki#vars#get_wikilocal('diary_rel_path')
let full_path = vimwiki#vars#get_wikilocal('path')
\ . diary_rel_path . a:path . vimwiki#vars#get_wikilocal('ext')
let fname_base = fnamemodify(a:path, ':t:r')
let htmlfile = fname_base . '.html'
let converted = s:convert_file_to_lines(full_path, htmlfile)
if converted['nohtml'] == 1
return []
endif
let link = vimwiki#vars#get_wikilocal('base_url')
\ . diary_rel_path
\ . fname_base . '.html'
let pubdate = strftime('%a, %d %b %Y %T %z', getftime(full_path))
let item_pre = [' - ',
\ '
' . a:title . ' ',
\ ' ' . link . '',
\ ' ' . fname_base . ' ',
\ ' ',
\ ' ' . pubdate . ' ',
\ ' '
\]
return item_pre + converted['html'] + item_post
endfunction
function! s:generate_rss(path) abort
let rss_path = a:path . vimwiki#vars#get_wikilocal('rss_name')
let max_items = vimwiki#vars#get_wikilocal('rss_max_items')
let rss_lines = []
call extend(rss_lines, s:rss_header())
let captions = vimwiki#diary#diary_file_captions()
let i = 0
for diary in vimwiki#diary#diary_sort(keys(captions))
if i >= max_items
break
endif
let title = captions[diary]['top']
if title ==? ''
let title = diary
endif
call extend(rss_lines, s:rss_item(diary, title))
let i += 1
endfor
call extend(rss_lines, s:rss_footer())
call writefile(rss_lines, rss_path)
endfunction
function! vimwiki#html#diary_rss() abort
call vimwiki#u#echo('Saving RSS feed ...')
let path_html = expand(vimwiki#vars#get_wikilocal('path_html'))
call vimwiki#path#mkdir(path_html)
call s:generate_rss(path_html)
endfunction
vimwiki-2024.01.24/autoload/vimwiki/lst.vim 0000664 0000000 0000000 00000154307 14554351005 0020407 0 ustar 00root root 0000000 0000000 " Title: Vimwiki list functions
"
" Description:
" Everything concerning lists and checkboxes
"
" Also helpers for blockquotes as this file has intelligence and map (issue #1274)
" i
" n o
" n O
" Which also got exploited for blocquotes
"
" Home: https://github.com/vimwiki/vimwiki/
if exists('g:loaded_vimwiki_list_auto') || &compatible
finish
endif
let g:loaded_vimwiki_list_auto = 1
" ---------------------------------------------------------
" incrementation functions for the various kinds of numbers
" ---------------------------------------------------------
function! s:increment_1(value) abort
return eval(a:value) + 1
endfunction
function! s:increment_A(value) abort
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) abort
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) abort
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) abort
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) abort
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) abort
call s:substitute_rx_in_line(a:lnum, vimwiki#u#escape(a:old_string), a:new_string)
endfunction
function! s:first_char(string) abort
return matchstr(a:string, '^.')
endfunction
if exists('*strdisplaywidth')
function! s:string_length(str) abort
return strdisplaywidth(a:str)
endfunction
else
function! s:string_length(str) abort
return strlen(substitute(a:str, '.', 'x', 'g'))
endfunction
endif
function! vimwiki#lst#default_symbol() abort
return vimwiki#vars#get_syntaxlocal('list_markers')[0]
endfunction
function! vimwiki#lst#get_list_margin() abort
let list_margin = vimwiki#vars#get_wikilocal('list_margin')
if list_margin < 0
return &shiftwidth
else
return list_margin
endif
endfunction
function! s:text_begin(lnum) abort
" Returns: the column where the text of a line starts (possible list item
" markers and checkboxes are skipped)
return s:string_length(matchstr(getline(a:lnum), vimwiki#vars#get_wikilocal('rxListItem')))
endfunction
function! s:line_has_marker(lnum) abort
" 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)
" Concatenate regex list and blockquote item
let rx_list_or_blockquote =
\ '\%('
\ . vimwiki#vars#get_wikilocal('rxListItem')
\ . '\|'
\ . vimwiki#vars#get_wikilocal('rxBlockquoteItem')
\ . '\)'
" Search for marker
if getline(a:lnum) =~# rx_list_or_blockquote . '\s*$'
" Found without text
return 1
elseif getline(a:lnum) =~# rx_list_or_blockquote . '\s*\S'
" Found with text
return 2
else
" Not found
return 0
endif
endfunction
function! s:remove_including_children(item) abort
" Remove a list item and it's children (recursive)
let num_removed_lines = 1
let child = s:get_first_child(a:item)
while child.type != 0
let num_removed_lines += s:remove_including_children(child)
let child = s:get_first_child(a:item)
endwhile
exec a:item.lnum.'delete _'
return num_removed_lines
endfunction
function! s:is_done(item) abort
return a:item.type != 0 && a:item.cb !=# '' && s:get_rate(a:item) == 100
endfunction
" ---------------------------------------------------------
" get properties of a list item
" ---------------------------------------------------------
function! s:get_item(lnum) abort
" Return: 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 - the type of marker at current line
" - 0 for a regular line (default)
" - 1 for bulleted item
" - 2 for numbered item
" - 3 a blockquote item (see #1274 to add line-continuation trick to blockquotes)
" mrkr - the concrete marker, e.g. '**' or 'b)' (default '')
" cb - the char in the checkbox or '' if there is no checkbox
" Init default
let item = {'lnum': a:lnum}
let item.type = 0
let item.mrkr = ''
let item.cb = ''
" Clause: Check lnum argument is in buffer line range
if a:lnum == 0 || a:lnum > line('$')
return item
endif
" Clause: Search for blockquotes (#1274) and return it if found
let matches = matchlist(getline(a:lnum), vimwiki#vars#get_wikilocal('rxBlockquoteItem'))
if len(matches) >= 1 && matches[1] !=? ''
let item.type = 3
let item.mrkr = matches[1]
return item
endif
" List: Search for list on current line if no blockquotes
let matches = matchlist(getline(a:lnum), vimwiki#vars#get_wikilocal('rxListItem'))
" Clause: If not on a list line => do not work
if matches == [] ||
\ (matches[1] ==? '' && matches[2] ==? '') ||
\ (matches[1] !=? '' && matches[2] !=? '')
return item
endif
" Fill item
" The checkbox inner is the last match
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
" See you on an other stack
return item
endfunction
function! s:empty_item() abort
" Craft: empty item
return {'type': 0}
endfunction
function! s:get_level(lnum) abort
" Returns: level of the line
" 0 is the 'highest' level
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_wikilocal('rx_bullet_chars')))-1
if level < 0
let level = (indent(a:lnum) == 0) ? 0 : 9999
endif
endif
return level
endfunction
function! s:guess_kind_of_numbered_item(item) abort
" Returns: 1, a, i, A, I or ''
" If in doubt if alphanumeric character or romanian
" numeral, peek in the previous line
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) abort
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
function! s:is_closed(item) abort
" Returns: Whether or not the checkbox of a list item is [X] or [-]
let state = a:item.cb
return state ==# vimwiki#vars#get_wikilocal('listsyms_list')[-1]
\ || state ==# vimwiki#vars#get_global('listsym_rejected')
endfunction
" ---------------------------------------------------------
" functions for navigating between items
" ---------------------------------------------------------
function! s:get_next_list_item(item, ignore_kind) abort
" Returns: the list item after a:item or an empty item
" If a:ignore_kind is 1, the markers can differ
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
function! s:get_prev_list_item(item, ignore_kind) abort
" Returns: the list item before a:item or an empty item
" If a:ignore_kind is 1, the markers can differ
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) abort
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) abort
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) abort
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) abort
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
function! s:get_next_line(lnum, ...) abort
" 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
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 + 1
else
let next_line = a:lnum + 1
endif
let next_line = nextnonblank(next_line)
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
function! s:get_prev_line(lnum) abort
" 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
let cur_ln = a:lnum - 1
if getline(cur_ln) =~# vimwiki#vars#get_syntaxlocal('rxPreEnd')
while 1
if cur_ln == 0 || getline(cur_ln) =~# vimwiki#vars#get_syntaxlocal('rxPreStart')
break
endif
let cur_ln -= 1
endwhile
endif
let prev_line = prevnonblank(cur_ln)
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) abort
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
function! s:get_next_child_item(parent, child) abort
" 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
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) abort
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
function! s:get_a_neighbor_item(item) abort
" Returns: the item above or the item below or an empty 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) abort
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
function! s:get_corresponding_item(lnum) abort
" Returns: the item if there is one in a:lnum
" else the multiline item a:lnum belongs to
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
function! s:get_last_line_of_item_incl_children(item) abort
" Returns: the last line of a (possibly multiline) item, including all children
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
function! s:get_last_line_of_item(item) abort
" Returns: the last line of a (possibly multiline) item
" Note: there can be other list items between the first and last line
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
" ---------------------------------------------------------
function! s:adjust_numbered_list_below(item, recursive) abort
" Renumbers the current list from a:item on downwards
" Returns: the last item that was adjusted
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) abort
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
function! s:adjust_numbered_list(item, ignore_kind, recursive) abort
" 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
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
function! vimwiki#lst#adjust_numbered_list() abort
" Renumbers the list the cursor is in
" also update its parents checkbox state
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
function! vimwiki#lst#adjust_whole_buffer() abort
" Renumbers all lists of the buffer
" of course, this might take some seconds
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
" ---------------------------------------------------------
function! s:get_rate(item) abort
" Returns: the rate of checkboxed list item in percent
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_wikilocal('listsyms_list'))
return index(vimwiki#vars#get_wikilocal('listsyms_list'), state) * 100/(n-1)
endfunction
function! s:set_state(item, new_rate) abort
" Set state of the list item to [ ] or [o] or whatever
" Returns: 1 if the state changed, 0 otherwise
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
function! s:set_state_plus_children(item, new_rate, ...) abort
" 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.
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
if vimwiki#vars#get_wikilocal('listsyms_propagate') == 0
return
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_wikilocal('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
function! s:rate_to_state(rate) abort
" Returns: the appropriate symbol for a given percent rate
let listsyms_list = vimwiki#vars#get_wikilocal('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
function! s:update_state(item) abort
" Updates the symbol of a checkboxed item according to the symbols of its children
if a:item.type == 0 || a:item.cb ==? '' || vimwiki#vars#get_wikilocal('listsyms_propagate') == 0
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) abort
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
function! s:create_cb(item, start_rate) abort
" Creates checkbox in a list item.
" Returns: 1 if successful
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) abort
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
function! s:change_cb(from_line, to_line, new_rate) abort
" Change state of the checkboxes in the lines of the given range
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
function! s:toggle_create_cb(from_line, to_line, state1, state2, start_rate) abort
" 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.
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
function! vimwiki#lst#decrement_cb(from_line, to_line) abort
" Decrement checkbox between [ ] and [X]
" in the lines of the given range
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_wikilocal('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
function! vimwiki#lst#increment_cb(from_line, to_line) abort
" Increment checkbox between [ ] and [X]
" in the lines of the given range
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_wikilocal('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
function! vimwiki#lst#toggle_cb(from_line, to_line) abort
" Toggles checkbox between [ ] and [X] or creates one
" in the lines of the given range
return s:toggle_create_cb(a:from_line, a:to_line, 100, 0, 0)
endfunction
function! vimwiki#lst#toggle_rejected_cb(from_line, to_line) abort
" Toggles checkbox between [ ] and [-] or creates one
" in the lines of the given range
return s:toggle_create_cb(a:from_line, a:to_line, -1, 0, -1)
endfunction
function! vimwiki#lst#remove_cb(first_line, last_line) abort
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() abort
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
function! s:remove_done_in_list(item, recursive) abort
" Iterate over given todo list and remove all task that are done
" If recursive is true, child items will be checked too
" Clause non-null item type
if a:item.type == 0
return
endif
" Recurse self on list item
let first_item = s:get_first_item_in_list(a:item, 0)
let total_lines_removed = 0
let cur_item = first_item
while 1
let next_item = s:get_next_list_item(cur_item, 0)
if s:is_done(cur_item)
let lines_removed = s:remove_including_children(cur_item)
elseif a:recursive
let lines_removed = s:remove_done_in_list(s:get_first_child(cur_item), a:recursive)
else
let lines_removed = 0
endif
let total_lines_removed += lines_removed
if next_item.type == 0
break
else
let next_item.lnum -= lines_removed
let cur_item = next_item
endif
endwhile
" Update state of parent item (percentage of done)
call s:update_state(s:get_parent(first_item))
return total_lines_removed
endfunction
function! vimwiki#lst#remove_done_in_current_list(recursive) abort
" Iterate over the list that the cursor is positioned in
" and remove all lines of task that are done.
" If recursive is true, child items will be checked too
let item = s:get_corresponding_item(line('.'))
call s:remove_done_in_list(item, a:recursive)
endfunction
function! vimwiki#lst#remove_done_in_range(first_line, last_line) abort
" Remove selected lines if they contain a task that is done
let first_item = s:get_corresponding_item(a:first_line)
let last_item = s:get_corresponding_item(a:last_line)
" Clause non-null first and last type item
if first_item.type == 0 || last_item.type == 0
return
endif
" For each line, delete done tasks
let parent_items_of_lines = []
let cur_ln = first_item.lnum
let end_ln = last_item.lnum
while cur_ln > 0 && cur_ln <= end_ln
let cur_item = s:get_item(cur_ln)
if s:is_done(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
exe cur_ln.'delete _'
let cur_ln -= 1
let end_ln -= 1
endif
let cur_ln = s:get_next_line(cur_ln)
endwhile
" Update all parent state (percentage of done)
for parent_item in parent_items_of_lines
call s:update_state(parent_item)
endfor
endfunction
function! vimwiki#lst#remove_done(recursive, range, first_line, last_line) abort
" wrapper function to distinguish between function used with a range or not
" vim 8.0.1089 and newer and corresponding neovim versions allow to use to distinguish if
" the function has been called with a range. For older versions we use remove_done_in_range if
" first and last line are identical, which means there was either no range or the range was within
" one line.
if a:range ==# ''
let range = a:first_line != a:last_line
else
let range = a:range > 0
endif
if range
call vimwiki#lst#remove_done_in_range(a:first_line, a:last_line)
else
call vimwiki#lst#remove_done_in_current_list(a:recursive)
endif
endfunction
" ---------------------------------------------------------
" change the level of list items
" ---------------------------------------------------------
function! s:set_indent(lnum, new_indent) abort
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, by) abort
let removed_indent = 0
if vimwiki#vars#get_syntaxlocal('recurring_bullets') && a:item.type == 1 &&
\ index(vimwiki#vars#get_wikilocal('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), '')
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, a:by * new_indent)
endif
call s:indent_cycle_bullets(a:item, -a:by)
endfunction
function! s:increase_level(item, by) abort
let additional_indent = 0
if vimwiki#vars#get_syntaxlocal('recurring_bullets') && a:item.type == 1 &&
\ index(vimwiki#vars#get_wikilocal('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))
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, a:by * new_indent)
endif
call s:indent_cycle_bullets(a:item, a:by)
endfunction
function! s:indent_cycle_bullets(item, indent_by) abort
" Cycle through the bullet list markers set in
" `bullet_types` based on the indentation level
" TODO there is potential to merge this with the change_marker* funcs further
" up if we can make them operate on arbitrary lists of characters
" Clause: Check if should work
if !vimwiki#vars#get_syntaxlocal('cycle_bullets') || a:item.type != 1
return
endif
let bullets = vimwiki#vars#get_syntaxlocal('bullet_types')
let i = index(bullets, s:first_char(a:item.mrkr)) + a:indent_by
" Calculate the index in a way that wraps around the end of the list
" ... making it behave like a ring buffer
let new_mrkr = bullets[((i % len(bullets) + len(bullets)) % len(bullets))]
call vimwiki#lst#change_marker(a:item.lnum, a:item.lnum, new_mrkr, 'n')
endfunction
function! s:indent_line_by(lnum, indent_by) abort
" Add a:indent_by to the current indent
"a:indent_by can be negative
let item = s:get_item(a:lnum)
if a:indent_by > 0
call s:increase_level(item, a:indent_by)
elseif a:indent_by < 0
" double negate indent_by here
call s:decrease_level(item, -a:indent_by)
endif
endfunction
function! s:change_level(from_line, to_line, direction, plus_children) abort
" Change lvl of lines in selection
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
exe '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') ? 1 : -1
call s:indent_line_by(from_item.lnum, first_line_indented_by)
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) abort
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
function! s:indent_multiline(prev_item, lnum) abort
" Indent line a:lnum to be the continuation of a:prev_item
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
" ---------------------------------------------------------
function! s:get_idx_list_markers(item) abort
" Returns: the position of a marker in g:vimwiki_list_markers
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
function! s:get_next_mrkr(item) abort
" Changes the marker of the given item to the next in g:vimwiki_list_markers
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
function! s:get_prev_mrkr(item) abort
" Changes the marker of the given item to the previous in g:vimwiki_list_markers
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) abort
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) abort
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_wikilocal('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) abort
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
function! s:adjust_mrkr(item) abort
" Sets kind of the item depending on neighbor items and the parent 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_wikilocal('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) abort
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) abort
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) abort
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() abort
let fold_end = foldclosedend('.')
let lnum = (fold_end == -1) ? line('.') : fold_end
let cur_item = s:get_item(lnum)
let parent = s:get_corresponding_item(lnum)
"inserting and deleting the x is necessary
"because otherwise the indent is lost
exe 'normal!' "ox\"
if !vimwiki#u#is_codeblock(lnum)
if parent.type != 0
call s:clone_marker_from_to(parent.lnum, cur_item.lnum+1)
else
call s:indent_multiline(cur_item, cur_item.lnum+1)
endif
endif
startinsert!
endfunction
function! vimwiki#lst#kbd_O() abort
exe 'normal!' "Ox\"
let cur_ln = line('.')
if !vimwiki#u#is_codeblock(cur_ln)
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
endif
startinsert!
endfunction
function! s:cr_on_empty_list_item(lnum, behavior) abort
if a:behavior == 1
"just make a new list item
exe '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()
exe '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) abort
let lst = s:get_corresponding_item(a:lnum)
"inserting and deleting the x is necessary
"because otherwise the indent is lost
exe 'normal!' "gi\x\\"
if a:behavior == 2 || a:behavior == 3
if lst.type == 0 || vimwiki#u#is_codeblock(a:lnum)
" don't insert new bullet if not part of a list
return
else
call s:create_marker(a:lnum+1)
endif
endif
endfunction
function! s:cr_on_list_item(lnum, insert_new_marker, not_at_eol) abort
if a:insert_new_marker
"the ultimate feature of this script: make new marker on
exe '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
exe '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) abort
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
function! vimwiki#lst#toggle_list_item() abort
" Creates a list item in the current line or removes it
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) abort
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) abort
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
let c_indent = indent(a:lnum) / &shiftwidth
let n_indent = indent(a:lnum+1) / &shiftwidth
return 's' . (c_indent - n_indent)
endif
endif
return '='
endfunction
" vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99
vimwiki-2024.01.24/autoload/vimwiki/markdown_base.vim 0000664 0000000 0000000 00000007665 14554351005 0022425 0 ustar 00root root 0000000 0000000 " 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) abort
" 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() abort
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
function! vimwiki#markdown_base#open_reflink(link) abort
" try markdown reference links
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() abort
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)
if vimwiki#base#is_diary_file(expand('%:p'))
let sub = vimwiki#base#normalize_link_in_diary(lnk)
else
let sub = vimwiki#base#normalize_link_helper(lnk,
\ vimwiki#vars#get_global('rxWord'), '',
\ vimwiki#vars#get_syntaxlocal('Link1'))
endif
call vimwiki#base#replacestr_at_cursor('\V'.lnk, sub)
return
endif
endfunction
function! vimwiki#markdown_base#normalize_link() abort
" TODO mutualize with base
call s:normalize_link_syntax_n()
endfunction
vimwiki-2024.01.24/autoload/vimwiki/path.vim 0000664 0000000 0000000 00000014567 14554351005 0020544 0 ustar 00root root 0000000 0000000 " vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99
" Vimwiki autoload plugin file
" Description: Path manipulation functions
" Home: https://github.com/vimwiki/vimwiki/
function! s:unixify(path) abort
" Unixify Path:
return substitute(a:path, '\', '/', 'g')
endfunction
function! s:windowsify(path) abort
" Windowsify Path:
return substitute(a:path, '/', '\', 'g')
endfunction
" Define: os specific path conversion
if vimwiki#u#is_windows()
function! s:osxify(path) abort
return s:windowsify(a:path)
endfunction
else
function! s:osxify(path) abort
return s:unixify(a:path)
endfunction
endif
function! vimwiki#path#chomp_slash(str) abort
" Remove Delimiter: of last path (slash or backslash)
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) abort
return a:p1 ==? a:p2
endfunction
else
function! vimwiki#path#is_equal(p1, p2) abort
return a:p1 ==# a:p2
endfunction
endif
function! vimwiki#path#normalize(path) abort
" Collapse Sections: like /a/b/../c to /a/c and /a/b/./c to /a/b/c
let path = a:path
while 1
let intermediateResult = substitute(path, '/[^/]\+/\.\.', '', '')
let result = substitute(intermediateResult, '/\./', '/', '')
if result ==# path
break
endif
let path = result
endwhile
return result
endfunction
function! vimwiki#path#path_norm(path) abort
" Normalize Path: \ -> / && /// -> / && resolve(symlinks)
" return if scp
if a:path =~# '^scp:' | return a:path | endif
" convert backslash to slash
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)
endfunction
function! vimwiki#path#is_link_to_dir(link) abort
" 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) abort
" Get: absolute path <- path relative to current file
return vimwiki#path#normalize(expand('%:p:h').'/'.a:link)
endfunction
function! vimwiki#path#path_common_pfx(path1, path2) abort
" Returns: longest common path prefix of 2 given paths.
" Ex: '~/home/usrname/wiki', '~/home/usrname/wiki/shmiki' => '~/home/usrname/wiki'
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) abort
" Convert: path -> full resolved slashed 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() abort
" Return: Current file path relative
return vimwiki#path#wikify_path(expand('%:p'))
endfunction
function! vimwiki#path#relpath(dir, file) abort
" Return: the relative path from a:dir to a:file
" Check if dir here ('.') -> return file
if empty(a:dir) || a:dir =~# '^\.[/\\]\?$'
return a:file
endif
" Unixify && Expand in
let s_dir = s:unixify(expand(a:dir))
let s_file = s:unixify(expand(a:file))
" Split path
let dir = split(s_dir, '/')
let file = split(s_file, '/')
" Shorten loop till equality
while (len(dir) > 0 && len(file) > 0) && vimwiki#path#is_equal(dir[0], file[0])
call remove(dir, 0)
call remove(file, 0)
endwhile
" Return './' if nothing left
if empty(dir) && empty(file)
return s:osxify('./')
endif
" Build path segment
let segments = []
for segment in dir
let segments += ['..']
endfor
for segment in file
let segments += [segment]
endfor
" Join segments
let result_path = join(segments, '/')
if a:file =~# '\m/$'
let result_path .= '/'
endif
return result_path
endfunction
function! vimwiki#path#mkdir(path, ...) abort
" Mkdir:
" if the optional argument provided and nonzero,
" it will ask before creating a directory
" returns: 1 iff directory exists or successfully created
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, &encoding, 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) abort
" Check: if path is absolute
let res=0
" Match 'C:' or '/' or '~'
if vimwiki#u#is_windows()
let res += a:path =~? '\m^\a:'
else
let res += a:path =~# '\m^/\|\~/'
endif
" Do not prepend root_path to scp files
" See: https://vim.fandom.com/wiki/Editing_remote_files_via_scp_in_vim
let res += a:path =~# '\m^scp:'
return res
endfunction
function! s:get_wikifile_link(wikifile) abort
return vimwiki#base#subdir(vimwiki#vars#get_wikilocal('path'), a:wikifile).
\ fnamemodify(a:wikifile, ':t:r')
endfunction
function! vimwiki#path#PasteLink(wikifile) abort
call append(line('.'), '[[/'.s:get_wikifile_link(a:wikifile).']]')
endfunction
if vimwiki#u#is_windows()
" 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.
function! vimwiki#path#join_path(directory, file) abort
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) abort
let directory = substitute(a:directory, '\m/\+$', '', '')
let file = substitute(a:file, '\m^/\+', '', '')
return directory . '/' . file
endfunction
endif
vimwiki-2024.01.24/autoload/vimwiki/style.css 0000664 0000000 0000000 00000014576 14554351005 0020745 0 ustar 00root root 0000000 0000000 body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;;
margin: 2em 4em 2em 4em;
font-size: 120%;
line-height: 130%;
}
h1, h2, h3, h4, h5, h6 {
font-weight: bold;
line-height:100%;
margin-top: 1.5em;
margin-bottom: 0.5em;
}
h1 {font-size: 2em; color: #000000;}
h2 {font-size: 1.8em; color: #404040;}
h3 {font-size: 1.6em; color: #707070;}
h4 {font-size: 1.4em; color: #909090;}
h5 {font-size: 1.2em; color: #989898;}
h6 {font-size: 1em; 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;
}
dt { font-weight: bold; }
img { border: none; }
pre {
border-left: 5px solid #dcdcdc;
background-color: #f5f5f5;
padding-left: 1em;
font-family: Monaco, "Courier New", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace;
font-size: 0.8em;
border-radius: 6px;
}
p > a {
color: white;
text-decoration: none;
font-size: 0.7em;
padding: 3px 6px;
border-radius: 3px;
background-color: #1e90ff;
text-transform: uppercase;
font-weight: bold;
}
p > a:hover {
color: #dcdcdc;
background-color: #484848;
}
li > a {
color: #1e90ff;
font-weight: bold;
text-decoration: none;
}
li > a:hover { color: #ff4500; }
blockquote {
color: #686868;
font-size: 0.8em;
line-height: 120%;
padding: 0.8em;
border-left: 5px solid #dcdcdc;
}
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: #ff4500 ;
color: white;
font-size: 0.8em;
padding: 3px 6px;
border-radius: 3px;
}
.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;
}
vimwiki-2024.01.24/autoload/vimwiki/tags.vim 0000664 0000000 0000000 00000040576 14554351005 0020545 0 ustar 00root root 0000000 0000000 " vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99
" Vimwiki autoload plugin file
" Description: Tag manipulation functions
" Home: https://github.com/vimwiki/vimwiki/
"
" 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|) and
" https://ctags.sourceforge.net/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".
let s:TAGS_METADATA_FILE_NAME = '.vimwiki_tags'
function! vimwiki#tags#update_tags(full_rebuild, all_files) abort
" Update tags metadata.
" Param: a:full_rebuild == 1: re-scan entire wiki
" Param: a:full_rebuild == 0: only re-scan current page
" a:all_files == '': only if the file is newer than .tags
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
function! s:safesubstitute(text, search, replace, mode) abort
" Substitute regexp but do not interpret replace
" TODO mutualize with same function in base
let escaped = escape(a:replace, '\&')
return substitute(a:text, a:search, escaped, a:mode)
endfunction
function! s:scan_tags(lines, page_name) abort
" Scan the list of text lines (argument) and produces tags metadata as a list of tag entries.
" Code wireframe to scan for headers -- borrowed from
" vimwiki#base#get_anchors(), with minor modifications.
let entries = []
" Get syntax wide regex
let rxheader = vimwiki#vars#get_syntaxlocal('header_search')
let tag_search_rx = vimwiki#vars#get_syntaxlocal('tag_search')
let tag_format = vimwiki#vars#get_syntaxlocal('tag_format')
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]
" ignore verbatim blocks
if vimwiki#u#is_codeblock(line_nr)
continue
endif
" process headers
let h_match = matchlist(line, rxheader)
if !empty(h_match) " got a header
let header_line_nr = line_nr
let header = vimwiki#base#normalize_anchor(h_match[2])
let current_header_description = 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
" See: issue #1316 to allow tags in header
" continue " tags are not allowed in headers
endif
" Scan line for tags. There can be many of them.
let str = line
" Get all matches
let tag_groups = []
call substitute(str, tag_search_rx, '\=add(tag_groups, submatch(0))', 'g')
if tag_groups == []
continue
endif
for tag_group in tag_groups
for tag in split(tag_group, tag_format.sep)
" 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
let entry.description = entry.link
elseif line_nr <= (header_line_nr + PROXIMITY_LINES_NR)
" Tag appeared right below a header
let entry.link = a:page_name . '#' . current_complete_anchor
let entry.description = current_header_description
else
" Tag stands on its own
let entry.link = a:page_name . '#' . tag
let entry.description = entry.link
endif
call add(entries, entry)
endfor
endfor
endfor " loop over lines
return entries
endfunction
function! vimwiki#tags#metadata_file_path() abort
" Return: tags metadata file path
return fnamemodify(vimwiki#path#join_path(vimwiki#vars#get_wikilocal('path'),
\ s:TAGS_METADATA_FILE_NAME), ':p')
endfunction
function! s:load_tags_metadata() abort
" Load tags metadata from file, returns a dictionary
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_.*$'
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) != 3
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]
let entry.description = vw_fields[2]
if has_key(metadata, pagename)
call add(metadata[pagename], entry)
else
let metadata[pagename] = [entry]
endif
endfor
return metadata
endfunction
function! s:remove_page_from_tags(metadata, page_name) abort
" Remove all entries for given page from metadata in-place. Returns updated
" metadata (just in case).
if has_key(a:metadata, a:page_name)
call remove(a:metadata, a:page_name)
return a:metadata
else
return a:metadata
endif
endfunction
function! s:merge_tags(metadata, pagename, file_metadata) abort
" Merge metadata of one file into a:metadata
let metadata = a:metadata
let metadata[a:pagename] = a:file_metadata
return metadata
endfunction
function! s:tags_entry_cmp(i1, i2) abort
" Compare 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
" precedes the same tags on the same page at line 9. (Because string "14" is
" alphabetically 'less than' string "9".)
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
function! s:write_tags_metadata(metadata) abort
" Save metadata object into a file. Throws exceptions in case of problems.
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 . "\t" . entry.description
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')
let tag_comments = [
\ "!_TAG_PROGRAM_VERSION\t" . g:vimwiki_version,
\ "!_TAG_PROGRAM_URL\thttps://github.com/vimwiki/vimwiki",
\ "!_TAG_PROGRAM_NAME\tVimwiki Tags",
\ "!_TAG_PROGRAM_AUTHOR\tVimwiki",
\ "!_TAG_OUTPUT_MODE\tvimwiki-tags",
\ "!_TAG_FILE_SORTED\t1",
\ "!_TAG_FILE_FORMAT\t2",
\ ]
for c in tag_comments
call insert(tags, c)
endfor
call writefile(tags, metadata_path)
endfunction
function! vimwiki#tags#get_tags() abort
" Return: list of unique tags found in the .tags file
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
function! vimwiki#tags#generate_tags(create, ...) abort
" Generate tags in current buffer
" 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.
let header_level = vimwiki#vars#get_global('tags_header_level')
let tags_header_text = vimwiki#vars#get_global('tags_header')
" If tag headers should only be updated, search for already present tag headers
if !a:create
let headers = vimwiki#base#collect_headers()
let specific_tags = []
let inside_tag_headers = 0
for header in headers
" If we ran out of the headers containing the tags, stop
if inside_tag_headers && header[1] <= header_level
break
endif
" All headers in the tag headers section correspond to tag names. Collect all of them in a list.
if inside_tag_headers
call add(specific_tags, header[2])
endif
" If we found the start of the tag headers section, remember that the following headers are now inside of it
if header[1] == header_level && header[2] ==# tags_header_text
let inside_tag_headers = 1
endif
endfor
else
let specific_tags = a:000
endif
" use a dictionary function for closure like capability
" copy all local variables into dict (add a: if arguments are needed)
let GeneratorTags = copy(l:)
function! GeneratorTags.f() abort
let need_all_tags = empty(self.specific_tags)
let metadata = s:load_tags_metadata()
" make a dictionary { tag_name: [tag_links, ...] }
let tags_entries = {}
for tagname in self.specific_tags
let tags_entries[tagname] = []
endfor
for entries in values(metadata)
for entry in entries
if has_key(tags_entries, entry.tagname)
call add(tags_entries[entry.tagname], [entry.link, entry.description])
else
if need_all_tags
let tags_entries[entry.tagname] = [[entry.link, entry.description]]
endif
endif
endfor
unlet entry " needed for older vims with sticky type checking since name is reused
endfor
let tagnames = need_all_tags ? sort(keys(tags_entries)) : self.specific_tags
let lines = []
let bullet = repeat(' ', vimwiki#lst#get_list_margin()).vimwiki#lst#default_symbol().' '
let current_dir = vimwiki#base#current_subdir()
for tagname in tagnames
if len(lines) > 0
call add(lines, '')
endif
let tag_tpl = printf('rxH%d_Template', self.header_level + 1)
call add(lines, s:safesubstitute(vimwiki#vars#get_syntaxlocal(tag_tpl), '__Header__', tagname, ''))
if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown'
for _ in range(vimwiki#vars#get_global('markdown_header_style'))
call add(lines, '')
endfor
endif
for [taglink, tagdescription] in sort(tags_entries[tagname])
let taglink = vimwiki#path#relpath(current_dir, taglink)
if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown'
let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink3Template')
let link_infos = vimwiki#base#resolve_link(taglink)
if empty(link_infos.anchor)
let link_tpl = vimwiki#vars#get_syntaxlocal('Link1')
let entry = s:safesubstitute(link_tpl, '__LinkUrl__', taglink, '')
let entry = s:safesubstitute(entry, '__LinkDescription__', tagdescription, '')
let file_extension = vimwiki#vars#get_wikilocal('ext', vimwiki#vars#get_bufferlocal('wiki_nr'))
let entry = s:safesubstitute(entry, '__FileExtension__', file_extension , '')
else
let link_caption = split(tagdescription, '#', 0)[-1]
let link_text = split(taglink, '#', 1)[0]
let entry = s:safesubstitute(link_tpl, '__LinkUrl__', link_text, '')
let entry = s:safesubstitute(entry, '__LinkAnchor__', link_infos.anchor, '')
let entry = s:safesubstitute(entry, '__LinkDescription__', link_caption, '')
let file_extension = vimwiki#vars#get_wikilocal('ext', vimwiki#vars#get_bufferlocal('wiki_nr'))
let entry = s:safesubstitute(entry, '__FileExtension__', file_extension , '')
endif
call add(lines, bullet . entry)
else
let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate1')
let file_extension = vimwiki#vars#get_wikilocal('ext', vimwiki#vars#get_bufferlocal('wiki_nr'))
let link_tpl = s:safesubstitute(link_tpl, '__FileExtension__', file_extension , '')
call add(lines, bullet . substitute(link_tpl, '__LinkUrl__', taglink, ''))
endif
endfor
endfor
return lines
endfunction
let tag_match = printf('rxH%d', header_level + 1)
let links_rx = '^\%('.vimwiki#vars#get_syntaxlocal(tag_match).'\)\|'.
\ '\%(^\s*$\)\|^\s*\%('.vimwiki#vars#get_syntaxlocal('rxListBullet').'\)'
call vimwiki#base#update_listing_in_buffer(
\ GeneratorTags,
\ tags_header_text,
\ links_rx,
\ line('$')+1,
\ header_level,
\ a:create)
endfunction
function! vimwiki#tags#complete_tags(ArgLead, CmdLine, CursorPos) abort
" Complete tags
" 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
function! vimwiki#tags#search_tags(tag_pattern) abort
" See #1316 and rxTags in vars.vim
let tf = vimwiki#vars#get_syntaxlocal('tag_format')
" Craft regex
let rx_this_tag = '/'
let rx_this_tag .= tf.pre . '\@<=' . tf.pre_mark
let rx_this_tag .= '\%(' . tf.in . tf.sep . '\)*'
let rx_this_tag .= a:tag_pattern
let rx_this_tag .= '\%(' . tf.sep . tf.in . '\)*'
let rx_this_tag .= tf.post_mark . tf.post . '\@='
let rx_this_tag .= '/'
" Search in current wiki folder
return vimwiki#base#search(rx_this_tag)
endfunction
vimwiki-2024.01.24/autoload/vimwiki/tbl.vim 0000664 0000000 0000000 00000047671 14554351005 0020373 0 ustar 00root root 0000000 0000000 " 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/
" Clause: Load only once
if exists('g:loaded_vimwiki_tbl_auto') || &compatible
finish
endif
let g:loaded_vimwiki_tbl_auto = 1
function! s:s_sep() abort
" Return string column separator
return vimwiki#vars#get_syntaxlocal('rxTableSep')
endfunction
function! s:r_sep() abort
" Return regex column separator
" Not prefixed with \
let res = '\(^\|[^\\]\)\@<='
let res .= vimwiki#vars#get_syntaxlocal('rxTableSep')
return res
endfunction
function! s:wide_len(str) abort
" 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\"
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() abort
return '\s*'.s:r_sep().'\s*'
endfunction
function! s:sep_splitter() abort
return '-'.s:r_sep().'-'
endfunction
function! s:is_table(line) abort
" Check if param:line is in a table
return s:is_separator(a:line) ||
\ (a:line !~# s:r_sep().s:r_sep() && a:line =~# '^\s*'.s:r_sep().'.\+'.s:r_sep().'\s*$')
endfunction
function! s:is_separator(line) abort
" Check if param:line is a separator (ex: | --- | --- |)
return a:line =~# '^\s*'.s:r_sep().'\(:\=--\+:\='.s:r_sep().'\)\+\s*$'
endfunction
function! s:is_separator_tail(line) abort
return a:line =~# '^\{-1}\%(\s*\|-*\)\%('.s:r_sep().'-\+\)\+'.s:r_sep().'\s*$'
endfunction
function! s:is_last_column(lnum, cnum) abort
let line = strpart(getline(a:lnum), a:cnum - 1)
return line =~# s:r_sep().'\s*$' && line !~# s:r_sep().'.*'.s:r_sep().'\s*$'
endfunction
function! s:is_first_column(lnum, cnum) abort
let line = strpart(getline(a:lnum), 0, a:cnum - 1)
return line =~# '^\s*$' ||
\ (line =~# '^\s*'.s:r_sep() && line !~# '^\s*'.s:r_sep().'.*'.s:r_sep())
endfunction
function! s:count_separators_up(lnum) abort
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) abort
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) abort
" Create an empty row of a:cols columns
let row = s:s_sep()
let cell = ' '.s:s_sep()
for c in range(a:cols)
let row .= cell
endfor
return row
endfunction
function! s:create_row_sep(cols) abort
" Create an empty separator row of a:cols columns
let row = s:s_sep()
let cell = '---'.s:s_sep()
for c in range(a:cols)
let row .= cell
endfor
return row
endfunction
function! vimwiki#tbl#get_cells(line, ...) abort
let result = []
let state = 'NONE'
let cell_start = 0
let quote_start = 0
" Split byte string into list of character to properly handle multibyte chars
let chars = split(a:line, '\zs')
let len = len(chars) - 1
" 'Simple' FSM
while state !=# 'CELL'
if quote_start != 0 && state !=# 'CELL'
let state = 'CELL'
endif
for idx in range(quote_start, len)
let ch = chars[idx]
if state ==# 'NONE'
if ch ==# s:s_sep() && (idx < 1 || chars[idx-1] !=# '\')
let cell_start = idx + 1
let state = 'CELL'
endif
elseif state ==# 'CELL'
if ch ==# '[' || ch ==# '{'
let state = 'BEFORE_QUOTE_START'
let quote_start = idx
elseif ch ==# s:s_sep() && (idx < 1 || chars[idx-1] !=# '\')
let cell = join(chars[cell_start : idx-1], '')
if a:0 && a:1
let cell = substitute(cell, '^ \(.*\) $', '\1', '')
else
let cell = vimwiki#u#trim(cell)
endif
call add(result, cell)
let cell_start = idx + 1
endif
elseif state ==# 'BEFORE_QUOTE_START'
if ch ==# '[' || ch ==# '{'
let state = 'QUOTE'
let quote_start = idx
else
let state = 'CELL'
endif
elseif state ==# 'QUOTE'
if ch ==# ']' || ch ==# '}'
let state = 'BEFORE_QUOTE_END'
endif
elseif state ==# 'BEFORE_QUOTE_END'
if ch ==# ']' || ch ==# '}'
let state = 'CELL'
endif
endif
endfor
if state ==# 'NONE'
break
endif
endwhile
return result
endfunction
function! s:col_count(lnum) abort
return len(vimwiki#tbl#get_cells(getline(a:lnum)))
endfunction
function! s:get_indent(lnum, depth) abort
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
if a:depth > 0 && lnum < a:lnum - a:depth
break
endif
endwhile
return indent
endfunction
function! s:get_rows(lnum, ...) abort
let rows = []
if !s:is_table(getline(a:lnum))
return rows
endif
let lnum = a:lnum - 1
let depth = a:0 > 0 ? a:1 : 0
let ldepth = 0
while lnum >= 1 && (depth == 0 || ldepth < depth)
let line = getline(lnum)
if s:is_table(line)
call insert(rows, [lnum, line])
else
break
endif
let lnum -= 1
let ldepth += 1
endwhile
let lnum = a:lnum
while lnum <= line('$')
let line = getline(lnum)
if s:is_table(line)
call add(rows, [lnum, line])
else
break
endif
if depth > 0
break
endif
let lnum += 1
endwhile
return rows
endfunction
function! s:get_cell_aligns(lnum, ...) abort
let aligns = {}
let depth = a:0 > 0 ? a:1 : 0
for [lnum, row] in s:get_rows(a:lnum, depth)
if s:is_separator(row)
let cells = vimwiki#tbl#get_cells(row)
for idx in range(len(cells))
let cell = cells[idx]
if cell =~# '^--\+:'
let aligns[idx] = 'right'
elseif cell =~# '^:--\+:'
let aligns[idx] = 'center'
else
let aligns[idx] = 'left'
endif
endfor
else
let cells = vimwiki#tbl#get_cells(row)
for idx in range(len(cells))
if !has_key(aligns, idx)
let aligns[idx] = 'left'
endif
endfor
endif
endfor
return aligns
endfunction
function! s:get_cell_aligns_fast(rows) abort
let aligns = {}
let clen = 0
for [lnum, row] in a:rows
if s:is_separator(row)
return s:get_cell_aligns(lnum, 1)
endif
let cells = vimwiki#tbl#get_cells(row, 1)
let clen = len(cells)
for idx in range(clen)
let cell = cells[idx]
if !has_key(aligns, idx)
let cs = matchlist(cell, '^\(\s*\)[^[:space:]].\{-}\(\s*\)$')
if !empty(cs)
let lstart = len(cs[1])
let lend = len(cs[2])
if lstart > 0 && lend > 0
let aligns[idx] = 'center'
elseif lend > 0
let aligns[idx] = 'left'
elseif lstart > 0
let aligns[idx] = 'right'
endif
endif
endif
endfor
endfor
for idx in range(clen)
if !has_key(aligns, idx)
return {}
endif
endfor
return aligns
endfunction
function! s:get_cell_max_lens(lnum, ...) abort
let max_lens = {}
let rows = a:0 > 2 ? a:3 : s:get_rows(a:lnum)
for [lnum, row] in rows
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, depth) abort
let rows = []
let aligns = {}
let startlnum = 0
let cells = []
let max_lens = {}
let check_all = 1
if a:depth > 0
let rows = s:get_rows(a:lnum, a:depth)
let startlnum = len(rows) > 0 ? rows[0][0] : 0
let lrows = len(rows)
if lrows == a:depth + 1
let line = rows[-1][1]
if !s:is_separator(line)
let lcells = vimwiki#tbl#get_cells(line)
let lclen = len(lcells)
let lmax_lens = repeat([0], lclen)
let laligns = repeat(['left'], lclen)
let rows[-1][1] = s:fmt_row(lcells, lmax_lens, laligns, 0, 0)
endif
let i = 1
for [lnum, row] in rows
call add(cells, vimwiki#tbl#get_cells(row, i != lrows - 1))
let i += 1
endfor
let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows)
" user option not to expand last call
if vimwiki#vars#get_global('table_reduce_last_col')
let last_index = keys(max_lens)[-1]
let max_lens[last_index] = 1
endif
let fst_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, rows[0:0])
let check_all = max_lens != fst_lens
let aligns = s:get_cell_aligns_fast(rows[0:-2])
let rows[-1][1] = line
endif
endif
if check_all
" all the table must be re-formatted
let rows = s:get_rows(a:lnum)
let startlnum = len(rows) > 0 ? rows[0][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, rows)
" user option not to expand last call
if vimwiki#vars#get_global('table_reduce_last_col')
let last_index = keys(max_lens)[-1]
let max_lens[last_index] = 1
endif
endif
if empty(aligns)
let aligns = s:get_cell_aligns(a:lnum)
endif
let result = []
for [lnum, row] in rows
if s:is_separator(row)
let new_row = s:fmt_sep(max_lens, aligns, a:col1, a:col2)
else
let new_row = s:fmt_row(cells[lnum - startlnum], max_lens, aligns, a:col1, a:col2)
endif
call add(result, [lnum, new_row])
endfor
return result
endfunction
function! s:cur_column() abort
" Number of the current column. Starts from 0.
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:r_sep(), 0)
let col = -1
while mpos < curs_pos && mpos != -1
let mpos = match(line, s:r_sep(), mpos+1)
if mpos != -1
let col += 1
endif
endwhile
return col
endfunction
function! s:fmt_cell(cell, max_len, align) abort
let cell = ' '.a:cell.' '
let diff = a:max_len - s:wide_len(a:cell)
if diff == 0 && empty(a:cell)
let diff = 1
endif
if a:align ==# 'left'
let cell .= repeat(' ', diff)
elseif a:align ==# 'right'
let cell = repeat(' ',diff).cell
else
let cell = repeat(' ',diff/2).cell.repeat(' ',diff-diff/2)
endif
return cell
endfunction
function! s:fmt_row(cells, max_lens, aligns, col1, col2) abort
let new_line = s:s_sep()
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], a:aligns[idx]).s:s_sep()
endfor
let idx = len(a:cells)
while idx < len(a:max_lens)
let new_line .= s:fmt_cell('', a:max_lens[idx], a:aligns[idx]).s:s_sep()
let idx += 1
endwhile
return new_line
endfunction
function! s:fmt_cell_sep(max_len, align) abort
let cell = ''
if a:max_len == 0
let cell .= '-'
else
let cell .= repeat('-', a:max_len)
endif
if a:align ==# 'right'
return cell.'-:'
elseif a:align ==# 'left'
return cell.'--'
else
return ':'.cell.':'
endif
endfunction
function! s:fmt_sep(max_lens, aligns, col1, col2) abort
let new_line = s:s_sep()
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], a:aligns[idx]).s:s_sep()
endfor
return new_line
endfunction
function! s:kbd_create_new_row(cols, goto_first) abort
let cmd = "\o".s:create_empty_row(a:cols)
let cmd .= "\:call vimwiki#tbl#format(line('.'), 2)\"
let cmd .= "\0"
if a:goto_first
let cmd .= ":call search('\\(".s:r_sep()."\\)\\zs', 'c', line('.'))\"
else
let cmd .= (col('.')-1).'l'
let cmd .= ":call search('\\(".s:r_sep()."\\)\\zs', 'bc', line('.'))\"
endif
let cmd .= 'a'
return cmd
endfunction
function! s:kbd_goto_next_row() abort
let cmd = "\j"
let cmd .= ":call search('.\\(".s:r_sep()."\\)', 'c', line('.'))\"
let cmd .= ":call search('\\(".s:r_sep()."\\)\\zs', 'bc', line('.'))\"
let cmd .= 'a'
return cmd
endfunction
function! s:kbd_goto_prev_row() abort
let cmd = "\k"
let cmd .= ":call search('.\\(".s:r_sep()."\\)', 'c', line('.'))\"
let cmd .= ":call search('\\(".s:r_sep()."\\)\\zs', 'bc', line('.'))\"
let cmd .= 'a'
return cmd
endfunction
function! vimwiki#tbl#goto_next_col() abort
" Used in s:kbd_goto_next_col
let curcol = virtcol('.')
let lnum = line('.')
let depth = 2
let newcol = s:get_indent(lnum, depth)
let rows = s:get_rows(lnum, depth)
let startlnum = len(rows) > 0 ? rows[0][0] : 0
let cells = []
for [lnum, row] in rows
call add(cells, vimwiki#tbl#get_cells(row, 1))
endfor
let max_lens = s:get_cell_max_lens(lnum, cells, startlnum, rows)
for cell_len in values(max_lens)
if newcol >= curcol-1
break
endif
let newcol += cell_len + 3 " +3 == 2 spaces + 1 separator |...
endfor
let newcol += 2 " +2 == 1 separator + 1 space | 0 ? rows[0][0] : 0
let cells = []
for [lnum, row] in rows
call add(cells, vimwiki#tbl#get_cells(row, 1))
endfor
let max_lens = s:get_cell_max_lens(lnum, cells, startlnum, rows)
let prev_cell_len = 0
for cell_len in values(max_lens)
let delta = cell_len + 3 " +3 == 2 spaces + 1 separator |...
if newcol + delta > curcol-1
let newcol -= (prev_cell_len + 3) " +3 == 2 spaces + 1 separator |...
break
elseif newcol + delta == curcol-1
break
endif
let prev_cell_len = cell_len
let newcol += delta
endfor
let newcol += 2 " +2 == 1 separator + 1 space |"
" let cmd .= "a"
return cmd
endfunction
function! vimwiki#tbl#kbd_cr() abort
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() abort
let lnum = line('.')
if !s:is_table(getline(lnum))
return "\"
endif
let last = s:is_last_column(lnum, col('.'))
let is_sep = s:is_separator_tail(getline(lnum))
"vimwiki#u#debug("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() abort
let lnum = line('.')
if !s:is_table(getline(lnum))
return "\"
endif
let first = s:is_first_column(lnum, col('.'))
let is_sep = s:is_separator_tail(getline(lnum))
"vimwiki#u#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, ...) abort
" Clause in
if !vimwiki#u#ft_is_vw()
return
endif
let line = getline(a:lnum)
if !s:is_table(line)
return
endif
" Backup textwidth
let textwidth = &textwidth
let depth = a:0 == 1 ? a:1 : 0
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, depth)
if &expandtab
let indentstring = repeat(' ', indent)
else
execute "let indentstring = repeat('\', indent / &tabstop) . repeat(' ', indent % &tabstop)"
endif
" getting N = depth last rows is enough for having been formatted tables
for [lnum, row] in s:get_aligned_rows(a:lnum, col1, col2, depth)
let row = indentstring.row
if getline(lnum) != row
call setline(lnum, row)
endif
endfor
" Restore user textwidth
let &textwidth = textwidth
endfunction
function! vimwiki#tbl#create(...) abort
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, ...) abort
if s:is_table(getline('.'))
call call('vimwiki#tbl#format', [line('.')] + a:000)
else
exe 'normal! '.a:cmd
endif
endfunction
function! vimwiki#tbl#move_column_left() abort
" TODO: move_column_left and move_column_right are good candidates to be refactored.
" Clause in
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
return
endif
call vimwiki#tbl#format(line('.'), cur_col-1, cur_col)
call cursor(line('.'), 1)
let sep = '\('.s:r_sep().'\).\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
endfunction
function! vimwiki#tbl#move_column_right() abort
" Clause in
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
return
endif
" Format table && Put cursor on first col
call vimwiki#tbl#format(line('.'), cur_col, cur_col+1)
call cursor(line('.'), 1)
" Change add one to all col
let sep = '\('.s:r_sep().'\).\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
endfunction
function! vimwiki#tbl#get_rows(lnum) abort
return s:get_rows(a:lnum)
endfunction
function! vimwiki#tbl#is_table(line) abort
return s:is_table(a:line)
endfunction
function! vimwiki#tbl#is_separator(line) abort
return s:is_separator(a:line)
endfunction
function! vimwiki#tbl#cell_splitter() abort
return s:cell_splitter()
endfunction
function! vimwiki#tbl#sep_splitter() abort
return s:sep_splitter()
endfunction
vimwiki-2024.01.24/autoload/vimwiki/u.vim 0000664 0000000 0000000 00000041047 14554351005 0020045 0 ustar 00root root 0000000 0000000 " vim:tabstop=2:shiftwidth=2:expandtab:textwidth=99
" Vimwiki autoload plugin file
" Description: Utility functions
" Home: https://github.com/vimwiki/vimwiki/
function! vimwiki#u#echo(msg, ...) abort
" Echo: msg
" :param: (1) highlighting group
" :param: (2) echo suffix (ex: 'n', 'm')
" :param: (3) message prefix, default Vimwiki
let hl_group = a:0 > 0 ? a:1 : ''
let echo_suffix = a:0 > 1 ? a:2 : ''
let msg_prefix = a:0 > 2 ? a:3 : 'Vimwiki: '
" Start highlighting
if hl_group !=# ''
exe 'echohl ' . hl_group
endif
" Escape
let msg = substitute(a:msg, "'", "''", 'g')
" Print
exe 'echo'.echo_suffix . " '" . msg_prefix . msg . "'"
" Stop highlighting
if hl_group !=# ''
echohl None
endif
endfunction
function! vimwiki#u#debug(msg) abort
" Debug: msg
" let b:vimwiki_debug to trigger
if !exists('b:vimwiki_debug') || b:vimwiki_debug == 0
return
endif
echomsg 'DEBUG: ' . a:msg
endfunction
function! vimwiki#u#warn(msg) abort
" Warn: msg
call vimwiki#u#echo('Warning: ' . a:msg, 'WarningMsg', '')
endfunction
function! vimwiki#u#error(msg) abort
" Error: msg
call vimwiki#u#echo('Error: ' . a:msg, 'Error', 'msg')
endfunction
function! vimwiki#u#deprecate(old, new) abort
" Warn: deprecated feature: old -> new
call vimwiki#u#warn('Deprecated: ' . a:old . ' is deprecated and '
\ . 'will be removed in future versions. Use ' . a:new . ' instead.')
endfunction
function! vimwiki#u#get_selection(...) abort
" Get visual selection text content, optionally replace its content
" :param: Text to replace selection
" Copied from DarkWiiPlayer at stackoverflow
" https://stackoverflow.com/a/47051271/2544873
" Get selection extremity position,
" Discriminate selection mode
if mode() ==? 'v'
let [line_start, column_start] = getpos('v')[1:2]
let [line_end, column_end] = getpos('.')[1:2]
else
let [line_start, column_start] = getpos("'<")[1:2]
let [line_end, column_end] = getpos("'>")[1:2]
end
" Guard
if (line2byte(line_start)+column_start) > (line2byte(line_end)+column_end)
let [line_start, column_start, line_end, column_end] =
\ [line_end, column_end, line_start, column_start]
end
let lines = getline(line_start, line_end)
if len(lines) == 0
return ''
endif
" If want to modify selection
if a:0 > 0
" Grab new content
let line_link = a:1
" Grab the content of line around the link: pre and post
let start_link = max([column_start - 2, 0])
let line_pre = ''
if start_link > 0
let line_pre .= lines[0][ : start_link]
endif
let line_post = lines[0][column_end - (&selection ==# 'inclusive' ? 0 : 1) : ]
" Set the only single selected line
call setline(line_start, line_pre . line_link . line_post)
endif
" Get selection extremity position, take into account selection option
let lines[-1] = lines[-1][: column_end - (&selection ==# 'inclusive' ? 1 : 2)]
let lines[0] = lines[0][column_start - 1:]
return join(lines, "\n")
endfunction
function! vimwiki#u#count_exe(cmd) abort
" Execute: string v:count times
" Called: prefixable mapping
for i in range( max([1, v:count]) )
exe a:cmd
endfor
endfunction
function! vimwiki#u#sort_len(list) abort
function! s:len_compare(s1, s2) abort
let i1 = len(a:s1)
let i2 = len(a:s2)
return i1 == i2 ? 0 : i1 > i2 ? 1 : -1
endfunction
return sort(a:list, 's:len_compare')
endfunction
function! vimwiki#u#trim(string, ...) abort
" Trim spaces: leading and trailing
" :param: string in
" :param: (1) optional list of character to trim
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
function! vimwiki#u#cursor(lnum, cnum) abort
" Builtin cursor doesn't work right with unicode characters.
exe a:lnum
exe 'normal! 0'.a:cnum.'|'
endfunction
function! vimwiki#u#os_name() abort
" Returns: OS name, human readable
if vimwiki#u#is_windows()
return 'Windows'
elseif vimwiki#u#is_macos()
return 'Mac'
else
return 'Linux'
endif
endfunction
function! vimwiki#u#is_windows() abort
" Check if OS is windows
return has('win32') || has('win64') || has('win95') || has('win16')
endfunction
function! vimwiki#u#is_macos() abort
" Check if OS is mac
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) abort
let first_sym = matchstr(a:line, '\S')
return len(matchstr(a:line, first_sym.'\+'))
endfunction
function! vimwiki#u#escape(string) abort
" Escape string for literal magic regex match
return escape(a:string, '~.*[]\^$')
endfunction
function! vimwiki#u#reload_regexes() abort
" Load concrete Wiki syntax: sets regexes and templates for headers and links
execute 'runtime! syntax/vimwiki_'.vimwiki#vars#get_wikilocal('syntax').'.vim'
endfunction
function! vimwiki#u#reload_regexes_custom() abort
" Load syntax-specific functionality
execute 'runtime! syntax/vimwiki_'.vimwiki#vars#get_wikilocal('syntax').'_custom.vim'
endfunction
function! vimwiki#u#sw() abort
" Backward compatible version of the built-in function shiftwidth()
if exists('*shiftwidth')
return shiftwidth()
else
return &shiftwidth
endif
endfunc
function! vimwiki#u#map_key(mode, key, plug, ...) abort
" a:mode single character indicating the mode as defined by :h maparg
" a:key the key sequence to map
" a:plug the plug command the key sequence should be mapped to
" a:1 optional argument with the following functionality:
" if a:1==1 then the hasmapto() check is skipped.
" this can be used to map different keys to the same definition
" if a:1==2 then the mapping is not specific i.e. it is global
if a:0 && a:1 == 2
" global mappings
if !hasmapto(a:plug, a:mode) && maparg(a:key, a:mode) ==# ''
exe a:mode . 'map ' . a:key . ' ' . a:plug
endif
elseif a:0 && a:1 == 1
" vimwiki buffer mappings, repeat mapping to the same definition
exe a:mode . 'map ' . a:key . ' ' . a:plug
else
" vimwiki buffer mappings
if !hasmapto(a:plug, a:mode)
exe a:mode . 'map ' . a:key . ' ' . a:plug
endif
endif
endfunction
function! vimwiki#u#is_codeblock(lnum) abort
" Returns: 1 if line is a code block or math block
"
" The last two conditions are needed for this to correctly
" detect nested syntaxes within code blocks
let syn_g = synIDattr(synID(a:lnum,1,1),'name')
if syn_g =~# 'Vimwiki\(Pre.*\|IndentedCodeBlock\|Math.*\)'
\ || (syn_g !~# 'Vimwiki.*' && syn_g !=? '')
return 1
else
return 0
endif
endfunction
function! vimwiki#u#ft_set() abort
" Sets the filetype to vimwiki
" If g:vimwiki_filetypes variable is set
" the filetype will be vimwiki.. etc.
let ftypelist = vimwiki#vars#get_global('filetypes')
let ftype = 'vimwiki'
for ftypeadd in ftypelist
let ftype = ftype . '.' . ftypeadd
endfor
let &filetype = ftype
endfunction
function! vimwiki#u#ft_is_vw() abort
" Returns: 1 if filetype is vimwiki, 0 else
" If multiple fileytpes are in use 1 is returned only if the
" first ft is vimwiki which should always be the case unless
" the user manually changes it to something else
" Clause: is filetype defined
if &filetype ==# '' | return 0 | endif
if split(&filetype, '\.')[0] ==? 'vimwiki'
return 1
else
return 0
endif
endfunction
function! vimwiki#u#get_syntax_dic(...) abort
" Helper: Getter
" :param: syntax to retrieve, default to current
let syntax = a:0 ? a:1 : vimwiki#vars#get_wikilocal('syntax')
return g:vimwiki_syntaxlocal_vars[syntax]
endfunction
function! vimwiki#u#get_punctuation_regex() abort
" Helper: to mutualize
" Called: normalize and unnormalize anchor
" From: https://gist.github.com/asabaylus/3071099#gistcomment-2563127
" Faster
" Unused now
if v:version <= 703
" Retrocompatibility: Get invalid range for vim 7.03
return '[^0-9a-zA-Z_ \-]'
else
return '[^0-9a-zA-Z\u4e00-\u9fff_ \-]'
endif
endfunction
function! vimwiki#u#get_punctuation_string() abort
" Faster
" See: https://github.github.com/gfm/#ascii-punctuation-character
" res = '!"#$%&''()*+,-./:;<=>?@\[\\\]^`{}|~'
" But I removed the * as it is treated as a special case
return '!"#$%&''()+,-./:;<=>?@\[\\\]^`{}|~'
endfunction
function! vimwiki#u#hi_expand_regex(lst) abort
" Helper: Expand regex from reduced typeface delimiters
" :param: list> with reduced regex
" 1: Left delimiter (regex)
" 2: Right delimiter (regex)
" 3: Possible characters to ignore (regex: default '$^' => never match)
" 4: Can multiply delimiter (boolean: default 0 => do not repeat)
" Return: list with extended regex delimiters (not inside a word)
" -- [['\*_', '_\*']] -> [['\*_\S\@=', '\S\@<=_\*\%(\s\|$\)\@=']]
" Note: For purposes of this definition, the beginning and the end of the line count as Unicode whitespace.
" See: https://github.github.com/gfm/#left-flanking-delimiter-run
let res = []
let punctuation = vimwiki#u#get_punctuation_string()
" Iterate on (left delimiter, right delimiter pair)
for a_delimiter in a:lst
let r_left_del = a_delimiter[0]
let r_right_del = a_delimiter[1]
let r_repeat_del = len(a_delimiter) >= 3 ? a_delimiter[2] : '$^'
let b_can_mult = len(a_delimiter) >= 4 ? a_delimiter[3] : 0
" Craft the repeatable middle
let r_mult = b_can_mult ? '\+' : ''
let r_left_repeat = '\%(\%(' . r_left_del . '\)' . r_mult . '\)'
let r_right_repeat = '\%(\%(' . r_right_del . '\)' . r_mult . '\)'
let r_unescaped_repeat = '\%(\\\|\\\@: opening tag example ''
" :param: tag_post : closing tag example ' '
" :param: syntax_group example: VimwikiBold
" :param: contains coma separated and prefixed, default VimwikiHTMLTag
" :param: (1) is contained
" :param: (2) more param ex:oneline
" Discriminate parameters
let opt_is_contained = a:0 > 0 && a:1 > 0 ? 'contained ' : ''
let opt_more = a:0 > 1 ? ' ' . a:2 : ''
let opt_contains = ''
if a:contains !=# ''
let opt_contains = 'contains=' . a:contains . ' '
endif
" Craft command
" \ 'skip="\\' . a:tag_pre . '" ' .
let cmd = 'syn region ' . a:syntax_group . ' matchgroup=VimwikiDelimiter ' .
\ opt_is_contained .
\ 'start="' . a:tag_pre . '" ' .
\ 'end="' . a:tag_post . '" ' .
\ 'keepend ' .
\ opt_contains .
\ b:vimwiki_syntax_concealends .
\ opt_more
exe cmd
endfunction
function! vimwiki#u#hi_typeface(dic) abort
" Highight typeface: see $VIMRUNTIME/syntax/html.vim
" -- Basically allow nesting with multiple definition contained
" :param: dic must contain: bold, italic and underline, even if underline is often void,
" -- see here for underline not defined: https://stackoverflow.com/questions/3003476
" Italic must go before, otherwise single * takes precedence over ** and ** is considered as
" -- a void italic.
" Note:
" The last syntax defined take precedence so that user can change at runtime (:h :syn-define)
" Some cases are contained by default:
" -- ex: VimwikiCodeBoldUnderline is not defined in colorschemes -> VimwikiCode
" -- see: #709 asking for concealing quotes in bold, so it must be highlighted differently
" -- -- for the user to understand what is concealed around
" VimwikiCheckBoxDone and VimwikiDelText are as their are even when nested in bold or italic
" -- This is because it would add a lot of code (as n**2) at startup and is not often used
" -- Here n=3 (bold, italic, underline)
" Bold > Italic > Underline
let nested = vimwiki#u#get_syntax_dic().nested
" Bold Italic
if has_key(a:dic, 'bold_italic')
for bi in a:dic['bold_italic']
call vimwiki#u#hi_tag(bi[0], bi[1], 'VimwikiBoldItalic', nested . ',VimwikiBoldItalicUnderline')
endfor
endif
" Italic
for i in a:dic['italic']
" -- Italic 1
call vimwiki#u#hi_tag(i[0], i[1], 'VimwikiItalic ', nested .',VimwikiItalicBold,VimwikiItalicUnderline')
" -- Bold 2
call vimwiki#u#hi_tag(i[0], i[1], 'VimwikiBoldItalic', nested . ',VimwikiBoldItalicUnderline', 1)
" -- Bold 3
call vimwiki#u#hi_tag(i[0], i[1], 'VimwikiBoldUnderlineItalic', nested, 2)
" -- Underline 2
call vimwiki#u#hi_tag(i[0], i[1], 'VimwikiUnderlineItalic', nested . ',VimwikiUnderlineItalicBold', 1)
" -- Underline 3
call vimwiki#u#hi_tag(i[0], i[1], 'VimwikiUnderlineBoldItalic', nested, 2)
endfor
" Bold
for b in a:dic['bold']
" -- Bold 1
call vimwiki#u#hi_tag(b[0],b[1], 'VimwikiBold', nested . ',VimwikiBoldUnderline,VimwikiBoldItalic')
" -- Italic 2
call vimwiki#u#hi_tag(b[0], b[1], 'VimwikiItalicBold', nested . ',VimwikiItalicBoldUnderline', 1)
" -- Italic 3
call vimwiki#u#hi_tag(b[0], b[1], 'VimwikiItalicUnderlineBold', nested, 2)
" -- Underline 2
call vimwiki#u#hi_tag(b[0], b[1], 'VimwikiUnderlineBold', nested . ',VimwikiUnderlineBoldItalic', 1)
" -- Underline 3
call vimwiki#u#hi_tag(b[0], b[1], 'VimwikiUnderlineItalicBold', nested, 2)
endfor
" Underline
for u in a:dic['underline']
" -- Underline 1
call vimwiki#u#hi_tag(u[0], u[1], 'VimwikiUnderline', nested . ',VimwikiUnderlineBold,VimwikiUnderlineItalic')
" -- Italic 2
call vimwiki#u#hi_tag(u[0], u[1], 'VimwikiItalicUnderline', nested . ',VimwikiItalicUnderlineBold', 1)
" -- Italic 3
call vimwiki#u#hi_tag(u[0], u[1], 'VimwikiBoldItalicUnderline', nested, 2)
" -- Underline 2
call vimwiki#u#hi_tag(u[0], u[1], 'VimwikiBoldUnderline', nested . ',VimwikiBoldUnderlineItalic', 1)
" -- Underline 3
call vimwiki#u#hi_tag(u[0], u[1], 'VimwikiItalicBoldUnderline', nested, 2)
endfor
" Strikethrough
" Note: VimwikiBoldDelText Not Implemented (see above)
for u in a:dic['del']
call vimwiki#u#hi_tag(u[0], u[1], 'VimwikiDelText', nested)
endfor
"" Code do not contain anything but can be contained very nested
for u in a:dic['code']
call vimwiki#u#hi_tag(u[0], u[1], 'VimwikiCode', '')
endfor
" Superscript
for u in a:dic['sup']
call vimwiki#u#hi_tag(u[0], u[1], 'VimwikiSuperScript', nested, 0, 'oneline')
endfor
" Subscript
for u in a:dic['sub']
call vimwiki#u#hi_tag(u[0], u[1], 'VimwikiSubScript', nested, 0, 'oneline')
endfor
" Prevent var_with_underscore to trigger italic text
" -- See $VIMRUNTIME/syntax/markdown.vim
" But leave
" -- See https://github.github.com/gfm/#example-364
syn match VimwikiError "\w\@<=_\w\@="
endfunction
vimwiki-2024.01.24/autoload/vimwiki/vars.vim 0000664 0000000 0000000 00000217377 14554351005 0020567 0 ustar 00root root 0000000 0000000 " Title: Vimwiki variable definition and manipulation functions
"
" 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_syntaxlocal_vars 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!
" ------------------------------------------------------------------------------------------------
" Script variable
let s:margin_set_by_user = 0
function! vimwiki#vars#init() abort
" Init global and local variables
" Init && Populate: global variable container
let g:vimwiki_global_vars = {}
call s:populate_global_variables()
" Init && Populate: local variable container
let g:vimwiki_wikilocal_vars = []
call s:populate_wikilocal_options()
endfunction
function! s:check_users_value(key, users_value, value_infos, comes_from_global_variable) abort
" Helper: Check user setting
" warn user with message if not good type
" Param: 1: key : variable name
" Param: 2: vimwiki_key : user value
" Param: 3: value_infod : type and default value
" Param: 4: coming from a 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)
let help_text = a:comes_from_global_variable ?
\ 'g:vimwiki_' :
\ 'vimwiki-option-'
if has_key(a:value_infos, 'type') && type(a:users_value) != a:value_infos.type
call vimwiki#u#error(printf('The provided value of the option %s is a %s, ' .
\ 'but expected is a %s. See '':h '.help_text.'%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
call vimwiki#u#error(printf('The provided value ''%i'' of the option %s is'
\ . ' too small. The minimum value is %i. See '':h '.help_text.'%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
call vimwiki#u#error(printf('The provided value ''%i'' of the option %s is'
\ . ' too large. The maximum value is %i. See '':h '.help_text.'%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
call vimwiki#u#error(printf('The provided value ''%s'' of the option %s is'
\ . ' invalid. Allowed values are %s. See '':h '.help_text.'%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
call vimwiki#u#error(printf('The provided value ''%s'' of the option %s must'
\ . ' contain exactly %i character(s) but has %i. See '':h '.help_text.'_%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
call vimwiki#u#error(printf('The provided value ''%s'' of the option %s must'
\ . ' have at least %d character(s) but has %d. See '':h '.help_text.'%s''.', a:users_value,
\ setting_origin, a:value_infos.min_length, strwidth(a:users_value), a:key))
endif
endfunction
function! s:update_key(output_dic, key, old, new) abort
" Helper: Treat special variables
" Set list margin
if a:key ==# 'list_margin'
let s:margin_set_by_user = 1
let a:output_dic[a:key] = a:new
return
" Extend Tag format
elseif a:key ==# 'tag_format'
let a:output_dic[a:key] = {}
call extend(a:output_dic[a:key], a:old)
call extend(a:output_dic[a:key], a:new)
return
else
let a:output_dic[a:key] = a:new
return
endif
endfunction
" ----------------------------------------------------------
" 1. Global {{{1
" ----------------------------------------------------------
function! s:get_default_global() abort
" Get default wikilocal values
" Please: keep alphabetical sort
return {
\ 'CJK_length': {'type': type(0), 'default': 0, 'min': 0, 'max': 1},
\ 'auto_chdir': {'type': type(0), 'default': 0, 'min': 0, 'max': 1},
\ 'auto_header': {'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},
\ 'conceal_onechar_markers': {'type': type(0), 'default': 1, 'min': 0, 'max': 1},
\ 'conceal_pre': {'type': type(0), 'default': 0, 'min': 0, 'max': 1},
\ 'create_link': {'type': type(0), 'default': 1, 'min':0, 'max': 1},
\ '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': ''},
\ 'emoji_enable': {'type': type(0), 'default': 3, 'min':0, 'max': 3},
\ 'ext2syntax': {'type': type({}), 'default': {'.md': 'markdown', '.mkdn': 'markdown',
\ '.mdwn': 'markdown', '.mdown': 'markdown', '.markdown': 'markdown', '.mw': 'media'}},
\ 'folding': {'type': type(''), 'default': '', 'possible_values': ['', 'expr', 'syntax',
\ 'list', 'custom', ':quick', 'expr:quick', 'syntax:quick', 'list:quick',
\ 'custom:quick']},
\ 'filetypes': {'type': type([]), 'default': []},
\ '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': ''},
\ 'key_mappings': {'type': type({}), 'default':
\ {
\ 'all_maps': 1, 'global': 1, 'headers': 1, 'text_objs': 1,
\ 'table_format': 1, 'table_mappings': 1, 'lists': 1, 'lists_return': 1,
\ 'links': 1, 'html': 1, 'mouse': 0,
\ }},
\ 'links_header': {'type': type(''), 'default': 'Generated Links', 'min_length': 1},
\ 'links_header_level': {'type': type(0), 'default': 1, 'min': 1, 'max': 6},
\ 'listing_hl': {'type': type(0), 'default': 0, 'min': 0, 'max': 1},
\ 'listing_hl_command': {'type': type(''), 'default': 'pygmentize -f html'},
\ 'listsyms': {'type': type(''), 'default': ' .oOX', 'min_length': 2},
\ 'listsym_rejected': {'type': type(''), 'default': '-', 'length': 1},
\ 'map_prefix': {'type': type(''), 'default': 'w'},
\ 'markdown_header_style': {'type': type(0), 'default': 1, 'min':0, 'max': 2},
\ 'menu': {'type': type(''), 'default': 'Vimwiki'},
\ 'schemes_web': {'type': type([]), 'default':
\ [
\ 'http', 'https', 'file', 'ftp', 'gopher', 'telnet', 'nntp', 'ldap',
\ 'rsync', 'imap', 'pop', 'irc', 'ircs', 'cvs', 'svn', 'svn+ssh',
\ 'git', 'ssh', 'fish', 'sftp', 'thunderlink', 'message'
\ ]},
\ 'schemes_any': {'type': type([]), 'default': ['mailto', 'matrix', 'news', 'xmpp', 'sip', 'sips', 'doi', 'urn', 'tel', 'data']},
\ 'table_auto_fmt': {'type': type(0), 'default': 1, 'min': 0, 'max': 1},
\ 'table_reduce_last_col': {'type': type(0), 'default': 0, 'min': 0, 'max': 1},
\ 'table_mappings': {'type': type(0), 'default': 1, 'min': 0, 'max': 1},
\ 'tags_header': {'type': type(''), 'default': 'Generated Tags', 'min_length': 1},
\ 'tags_header_level': {'type': type(0), 'default': 1, 'min': 1, 'max': 5},
\ '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': ''},
\ }
endfunction
function! s:populate_global_variables() abort
" Populate: global variable <- user & default
" Called: s:vimwiki#vars#init
call s:read_global_settings_from_user()
call s:normalize_global_settings()
call s:internal_global_settings()
endfunction
function! s:internal_global_settings() abort
" Declare: normalized settings -> more usefull variables to use internally
" non-configurable global variables:
" Scheme regexes must be defined even if syntax file is not loaded yet cause users should be
" able to ww without opening any vimwiki file first
" Know internal schemes
let g:vimwiki_global_vars.schemes_web =
\ join(vimwiki#vars#get_global('schemes_web'), '\|')
let g:vimwiki_global_vars.schemes_any =
\ join(vimwiki#vars#get_global('schemes_any'), '\|')
let g:vimwiki_global_vars.schemes_local =
\ join(['wiki\d\+', 'diary', 'local'], '\|')
" Concatenate known schemes => regex
let g:vimwiki_global_vars.rxSchemes = '\%('.
\ g:vimwiki_global_vars.schemes_local . '\|'.
\ g:vimwiki_global_vars.schemes_web . '\|'.
\ g:vimwiki_global_vars.schemes_any .
\ '\)'
" 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.schemes_web . '\):'.
\ '\%(//\)'.
\ '\)'.
\ '\|'.
\ '\%('. g:vimwiki_global_vars.schemes_any .'\):'.
\ '\)'
let g:vimwiki_global_vars.rxWeblinkUrl = rxWebProtocols . '\S\{-1,}'. '\%(([^ \t()]*)\)\='
let wikilink_prefix = '[['
let wikilink_suffix = ']]'
let wikilink_separator = '|'
let g:vimwiki_global_vars.rx_wikilink_prefix = vimwiki#u#escape(wikilink_prefix)
let g:vimwiki_global_vars.rx_wikilink_suffix = vimwiki#u#escape(wikilink_suffix)
let g:vimwiki_global_vars.rx_wikilink_separator = vimwiki#u#escape(wikilink_separator)
" templates for the creation of wiki links
" [[URL]]
let g:vimwiki_global_vars.WikiLinkTemplate1 = wikilink_prefix . '__LinkUrl__'. wikilink_suffix
" [[URL|DESCRIPTION]]
let g:vimwiki_global_vars.WikiLinkTemplate2 = wikilink_prefix . '__LinkUrl__'. wikilink_separator
\ . '__LinkDescription__' . wikilink_suffix
let valid_chars = '[^\\\]]'
let g:vimwiki_global_vars.rxWikiLinkUrl = valid_chars.'\{-}'
let g:vimwiki_global_vars.rxWikiLinkDescr = valid_chars.'\{-}'
" this regexp defines what can form a link when the user presses in the
" buffer (and not on a link) to create a link
" basically, it's Ascii alphanumeric characters plus #|./@-_~ plus all
" non-Ascii characters, except that . is not accepted as the last character
" TODO look behind for . reduces the second part of the regex that is the same with '.' added
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
" 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:extend_global(output_dic, default_dic) abort
" Extend global dictionary <- default <- user
" Note: user_dic is unused here because it comes from g:vimwiki_* vars
" Copy the user's settings from variables of the form g:vimwiki_