diff --git a/.gitignore b/.gitignore index 3d791bc..3929660 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ # This section is devoted to this project ############################## doc/tags +.tags # Vim stuff ############################## @@ -20,3 +21,4 @@ Session.vim .Trashes ehthumbs.db Thumbs.db +vimtest diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cc519c7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,27 @@ +# No language: we download vim and compile it oursselves +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 + +script: + # Run All tests + - pushd test + - bash run_tests.sh + - popd diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1685084..8d3e53b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,5 @@ +# Contributing to Vimwiki + # Filing a bug Before filing a bug or starting to write a patch, check the latest development version from @@ -15,7 +17,14 @@ Make sure to update `doc/vimwiki.txt` with the following information: 1. Update the changelog to include information on the new feature the PR introduces or the bug it is fixing. 2. Add a help section to describe any new features or options. -2. If you are a first time contributor add your name to the list of contributors. +3. If you are a first time contributor add your name to the list of contributors. + +**Testing:** Vimwiki uses [vader](https://github.com/junegunn/vader.vim) for unit tests and +[vint](https://github.com/Kuniwak/vint) for linting. Any new PRs must add new tests and pass all +linter checks. See the [test README](test/README.md) for more info. + +- In addition to the included tests, there are more example wikis that can be used for testing + [here](https://github.com/vimwiki/testwikis). # More info and advice for (aspiring) core developers @@ -30,17 +39,17 @@ Make sure to update `doc/vimwiki.txt` with the following information: ## Git branching model -- there are two branches with eternal lifetime: - - `dev`: This is where the main development happens. Tasks which are done in one or only a few - commits go here directly. Always try to keep this branch in a working state, that is, if the - task you work on requires multiple commits, make sure intermediate commits don't make Vimwiki - unusable (or at least push these commits at one go). - - `master`: This branch is for released states only. Whenever a reasonable set of changes has - piled up in the `dev` branch, a [release is done](#Preparing a release). After a release, - `dev` has been merged into `master` and `master` got exactly one additional commit in which - the version number in `plugin/vimwiki.vim` is updated. Apart from these commits and the merge - commit from `dev`, nothing happens on `master`. Never should `master` merge into `dev`. When - the users ask, we should recommend this branch for them to use. +- There are two branches with eternal lifetime: + 1. `dev`: This is where the main development happens. Tasks which are done in one or only a few + commits go here directly. Always try to keep this branch in a working state, that is, if the + task you work on requires multiple commits, make sure intermediate commits don't make + Vimwiki unusable (or at least push these commits at one go). + 2. `master`: This branch is for released states only. Whenever a reasonable set of changes has + piled up in the `dev` branch, a [release is done](#preparing-a-release). After a release, + `dev` has been merged into `master` and `master` got exactly one additional commit in which + the version number in `plugin/vimwiki.vim` is updated. Apart from these commits and the + merge commit from `dev`, nothing happens on `master`. Never should `master` merge into + `dev`. When the users ask, we should recommend this branch for them to use. - Larger changes which require multiple commits are done in feature branches. They are based on `dev` and merge into `dev` when the work is done. @@ -55,9 +64,9 @@ Make sure to update `doc/vimwiki.txt` with the following information: 7. Update the version number at the top of plugin/vimwiki.vim. 8. Set a tag with the version number in Git: `git tag vX.Y` 9. `git push --tags` -10. In GitHub, go to _Releases_ -> _Draft a new release_ -> choose the tag, convert the changelog from the - doc to markdown and post it there. Make plans to build an automatic converter and immediately - forget this plan. +10. In GitHub, go to _Releases_ -> _Draft a new release_ -> choose the tag, convert the changelog + from the doc to markdown and post it there. Make plans to build an automatic converter and + immediately forget this plan. 11. Tell the world. -%% vim:tw=99 + diff --git a/DesignNotes.md b/DesignNotes.md new file mode 100644 index 0000000..5e7f957 --- /dev/null +++ b/DesignNotes.md @@ -0,0 +1,186 @@ +# Design Notes + +This file is meant to document design decisions and algorithms inside vimwiki +which are too large for code comments, and not necessarily interesting to +users. Please create a new section to document each behavior. + +## Formatting tables + +In vimwiki, formatting tables occurs dynamically, when navigating between cells +and adding new rows in a table in the Insert mode, or statically, when pressing +`gqq` or `gqw` (which are mappings for commands `VimwikiTableAlignQ` and +`VimwikiTableAlignW` respectively) in the Normal mode. It also triggers when +leaving Insert mode, provided variable `g:vimwiki_table_auto_fmt` is set. In +this section, the original and the newer optimized algorithms of table +formatting will be described and compared. + +### The older table formatting algorithm and why this is not optimal + +Let's consider a simple example. Open a new file, say _tmp.wiki_, and create a +new table with command `VimwikiTable`. This should create a blank table. + +``` +| | | | | | +|---|---|---|---|---| +| | | | | | +``` + +Let's put the cursor in the first header column of the table, enter the Insert +mode and type a name, say _Col1_. Then press _Tab_: the cursor will move to the +second column of the header and the table will get aligned (in the context of +the table formatting story, words _aligned_ and _formatted_ are considered as +synonyms). Now the table looks as in the following snippet. + +``` +| Col1 | | | | | +|------|---|---|---|---| +| | | | | | +``` + +Then, when moving cursor to the first data row (i.e. to the third line of the +table below the separator line) and typing anything here and there while +navigating using _Tab_ or _Enter_ (pressing this creates a new row below the +current row), the table shall keep formatting. Below is a result of such a +random edit. + +``` +| Col1 | | | | | +|------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| | | | | New data | +``` + +The lowest row gets aligned when leaving the Insert mode. Let's copy _Data1_ +(using `viwy` or another keystroke) and paste it (using `p`) in the second data +row of the first column. Now the table looks mis-aligned (as we did not enter +the Insert mode). + +``` +| Col1 | | | | | +|------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| Data1 | | | | New data | +``` + +This is not a big problem though, because we can put the cursor at _any_ place +in the table and press `gqq`: the table will get aligned. + +``` +| Col1 | | | | | +|-------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| Data1 | | | | New data | +``` + +Now let's make real problems! Move the cursor to the lowest row and copy it +with `yy`. Then 500-fold paste it with `500p`. Now the table very long. Move +the cursor to the lowest row (by pressing `G`), enter the Insert mode, and try +a new random editing session by typing anything in cells with _Tab_ and _Enter_ +navigation interleaves. The editing got painfully slow, did not? + +The reason of the slowing down is the older table formatting algorithm. Every +time _Tab_ or _Enter_ get pressed down, all rows in the table get visited to +calculate a new alignment. Moreover, by design it may happen even more than +once per one press! + +```vim +function! s:kbd_create_new_row(cols, goto_first) + let cmd = "\o".s:create_empty_row(a:cols) + let cmd .= "\:call vimwiki#tbl#format(line('.'))\" + let cmd .= "\0" + if a:goto_first + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'c', line('.'))\" + else + let cmd .= (col('.')-1)."l" + let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\" + endif + let cmd .= "a" + + return cmd +endfunction +``` + +Function `s:kbd_create_new_row()` is called when _Tab_ or _Enter_ get pressed. +Formatting of the whole table happens in function `vimwiki#tbl#format()`. But +remember that leaving the Insert mode triggers re-formatting of a table when +variable `g:vimwiki_table_auto_fmt` is set. This means that formatting of the +whole table is called on all those multiple interleaves between the Insert and +the Normal mode in `s:kbd_create_new_row` (notice `\`, `o`, etc.). + +### The newer table formating algorithm + +The newer algorithm was introduced to struggle against performance issues when +formatting large tables. + +Let's take the table from the previous example in an intermediate state. + +``` +| Col1 | | | | | +|------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| Data1 | | | | New data | +``` + +Then move the cursor to the first data row, copy it with `yy`, go down to the +mis-aligned line, and press `5p`. Now we have a slightly bigger mis-aligned +table. + +``` +| Col1 | | | | | +|------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| Data1 | | | | New data | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +``` + +Go down to the lowest, the 7th, data row and press `gq1`. Nothing happened. +Let's go to the second or the third data row and press `gq1` once again. Now +the table gets aligned. Let's undo formatting with `u`, go to the fourth row, +and press `gq1`. Now the table should look like in the following snippet. + +``` +| Col1 | | | | | +|------|-------|---|-------|----------| +| | Data1 | | Data2 | | +| Data1 | | | | New data | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +| | Data1 | | Data2 | | +``` + +What a peculiar command! Does using it make any sense? Not much, honestly. +Except it shows how the newer optimized table formatting algorithm works in the +Insert mode. + +Indeed, the newer table formatting algorithm introduces a _viewport_ on a table. +Now, when pressing _Tab_ or _Enter_ in the Insert mode, only a small part of +rows are checked for possible formatting: two rows above the current line and +the current line itself (the latter gets preliminary shrunk with function +`s:fmt_row()`). If all three lines in the viewport are of the same length, then +nothing happens (case 1 in the example). If the second or the shrunk current +line is longer then the topmost line in the viewport, then the algorithm falls +back to the older formatting algorithm and the whole table gets aligned +(case 2). If the topmost line in the viewport is longer than the second +and the shrunk current line, then the two lowest lines get aligned according to +the topmost line (case 3). + +Performance of the newer formatting algorithm should not depend on the height +of the table. The newer algorithm should also be consistent with respect to +user editing experience. Indeed, as soon as a table should normally be edited +row by row from the top to the bottom, dynamic formatting should be both fast +(watching only three rows in a table, re-formatting only when the shrunk +current row gets longer than any of the two rows above) and eager (a table +should look formatted on every press on _Tab_ and _Enter_). However, the newer +algorithm differs from the older algorithm when starting editing a mis-aligned +table in an area where mis-aligned rows do not get into the viewport: in this +case the newer algorithm will format the table partly (in the rows of the +viewport) until one of the being edited cells grows in length to a value big +enough to trigger the older algorithm and the whole table gets aligned. When +partial formatting is not desirable, the whole table can be formatted by +pressing `gqq` in the Normal mode. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b6ffdd0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM testbed/vim:17 + +# add packages +RUN apk --no-cache add bash=~5.0 +RUN apk --no-cache add git=~2.22 +RUN apk --no-cache add python3=~3.7 + +# get vint for linting +RUN pip3 install vim-vint==0.3.21 + +# 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 +# TODO uncomment nvim tag +WORKDIR / +RUN install_vim -tag v7.3.429 -name vim_7.3.429 -build \ + -tag v7.4.1099 -name vim_7.4.1099 -build \ + -tag v7.4.1546 -name vim_7.4.1546 -build \ + -tag v8.0.0027 -name vim_8.0.0027 -build \ + -tag v8.1.0519 -name vim_8.1.0519 -build \ diff --git a/README.md b/README.md index 6edd731..d53526c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -# VimWiki: A Personal Wiki For Vim +![VimWiki: A Personal Wiki For Vim](doc/splash.png) [中文](README-cn.md) - [Intro](#intro) +- [Screenshots](#screenshots) - [Installation](#installation) - [Prerequisites](#prerequisites) - [VIM Packages](#installation-using-vim-packages-since-vim-741528) @@ -19,31 +20,36 @@ - [Wiki](https://github.com/vimwiki/vimwiki/wiki) - [License](#license) -## Intro +---- + +## Introduction VimWiki is a personal wiki for Vim -- a number of linked text files that have -their own syntax highlighting. +their own syntax highlighting. See the [VimWiki Wiki](https://vimwiki.github.io/vimwikiwiki/) +for an example website built with VimWiki! -With VimWiki you can: +For the latest features and fixes checkout the [dev branch](https://github.com/vimwiki/vimwiki/tree/dev). +If you are interested in contributing see [this section](#helping-vimwiki). - * Organize notes and ideas - * Manage to-do lists - * Write documentation - * Maintain a diary - * Export everything to HTML +With VimWiki, you can: -To do a quick start press `ww` (this is usually `\ww`) to go to your -index wiki file. By default it is located in `~/vimwiki/index.wiki`. +- Organize notes and ideas +- Manage to-do lists +- Write documentation +- Maintain a diary +- Export everything to HTML + +To do a quick start, press `ww` (default is `\ww`) to go to your index +wiki file. By default, it is located in `~/vimwiki/index.wiki`. See `:h vimwiki_list` +for registering a different path/wiki. Feed it with the following example: -``` - +```text = My knowledge base = * Tasks -- things to be done _yesterday_!!! * Project Gutenberg -- good books are power. * Scratchpad -- various temporary stuff. - ``` Place your cursor on `Tasks` and press Enter to create a link. Once pressed, @@ -52,16 +58,14 @@ open it. Edit the file, save it, and then press Backspace to jump back to your index. A VimWiki link can be constructed from more than one word. Just visually -select the words to be linked and press Enter. Try it with `Project Gutenberg`. +select the words to be linked and press Enter. Try it, with `Project Gutenberg`. The result should look something like: -``` - +```text = My knowledge base = * [[Tasks]] -- things to be done _yesterday_!!! * [[Project Gutenberg]] -- good books are power. * Scratchpad -- various temporary stuff. - ``` ## Screenshots @@ -73,20 +77,20 @@ The result should look something like: ## Installation +VimWiki has been tested on **Vim >= 7.3**. It will likely work on older +versions but will not be officially supported. + ### Prerequisites Make sure you have these settings in your vimrc file: ```vim - set nocompatible filetype plugin on syntax on - ``` -Without them VimWiki will not work properly. - +Without them, VimWiki will not work properly. #### Installation using [Vim packages](http://vimhelp.appspot.com/repeat.txt.html#packages) (since Vim 7.4.1528) @@ -94,9 +98,17 @@ Without them VimWiki will not work properly. git clone https://github.com/vimwiki/vimwiki.git ~/.vim/pack/plugins/start/vimwiki +# to generate documentation i.e. ':h vimwiki' +vim -c 'helptags ~/.vim/pack/plugins/start/vimwiki/doc' -c quit + ``` -#### Installation using [Pathogen](http://www.vim.org/scripts/script.php?script_id=2332) +Notes: + +- See `:h helptags` for issues with installing the documentation. +- For general information on vim packages see `:h packages`. + +#### Installation using [Pathogen](https://github.com/tpope/vim-pathogen) ```sh @@ -121,7 +133,7 @@ Then run `:PlugInstall`. #### Installation using [Vundle](https://github.com/VundleVim/Vundle.vim) -Add `Plugin 'vimwiki/vimwiki'` to your vimrc file and run +Add `Plugin 'vimwiki/vimwiki'` to your vimrc file and run: ```sh @@ -129,16 +141,17 @@ vim +PluginInstall +qall ``` -Or download the [zip -archive](https://github.com/vimwiki/vimwiki/archive/master.zip) and extract it -in `~/.vim/bundle/` +#### Manual Install + +Download the [zip archive](https://github.com/vimwiki/vimwiki/archive/master.zip) +and extract it in `~/.vim/bundle/` Then launch Vim, run `:Helptags` and then `:help vimwiki` to verify it was installed. ## Basic Markup -``` +```text = Header1 = == Header2 == === Header3 === @@ -151,9 +164,9 @@ _italic_ -- italic text [[wiki link|description]] -- wiki link with description ``` -### Lists: +### Lists -``` +```text * bullet list item 1 - bullet list item 2 - bullet list item 3 @@ -174,36 +187,49 @@ For other syntax elements, see `:h vimwiki-syntax` ## Key bindings -Normal mode: +### Normal mode - * `ww` -- Open default wiki index file. - * `wt` -- Open default wiki index file in a new tab. - * `ws` -- Select and open wiki index file. - * `wd` -- Delete wiki file you are in. - * `wr` -- Rename wiki file you are in. - * `` -- Follow/Create wiki link - * `` -- Split and follow/create wiki link - * `` -- Vertical split and follow/create wiki link - * `` -- Go back to parent(previous) wiki link - * `` -- Find next wiki link - * `` -- Find previous wiki link +**Note:** your terminal may prevent capturing some of the default bindings +listed below. See `:h vimwiki-local-mappings` for suggestions for alternative +bindings if you encounter a problem. -For more keys, see `:h vimwiki-mappings` +#### Basic key bindings + +- `ww` -- Open default wiki index file. +- `wt` -- Open default wiki index file in a new tab. +- `ws` -- Select and open wiki index file. +- `wd` -- Delete wiki file you are in. +- `wr` -- Rename wiki file you are in. +- `` -- Follow/Create wiki link. +- `` -- Split and follow/create wiki link. +- `` -- Vertical split and follow/create wiki link. +- `` -- Go back to parent(previous) wiki link. +- `` -- Find next wiki link. +- `` -- Find previous wiki link. + +#### Advanced key bindings + +Refer to the complete documentation at `:h vimwiki-mappings` to see many +more bindings. ## Commands - * `:Vimwiki2HTML` -- Convert current wiki link to HTML - * `:VimwikiAll2HTML` -- Convert all your wiki links to HTML - * `:help vimwiki-commands` -- list all commands - * `:help vimwiki` -- General vimwiki help docs +- `:Vimwiki2HTML` -- Convert current wiki link to HTML. +- `:VimwikiAll2HTML` -- Convert all your wiki links to HTML. +- `:help vimwiki-commands` -- List all commands. +- `:help vimwiki` -- General vimwiki help docs. ## Changing Wiki Syntax VimWiki currently ships with 3 syntaxes: VimWiki (default), Markdown -(markdown), and MediaWiki (media) +(markdown), and MediaWiki (media). + +**NOTE:** Only the default syntax ships with a built-in HTML converter. For +Markdown or MediaWiki see `:h vimwiki-option-custom_wiki2html`. Some examples +and 3rd party tools are available [here](https://vimwiki.github.io/vimwikiwiki/Related%20Tools.html#Related%20Tools-External%20Tools). If you would prefer to use either Markdown or MediaWiki syntaxes, set the -following option in your .vimrc: +following option in your `.vimrc`: ```vim @@ -214,15 +240,22 @@ let g:vimwiki_list = [{'path': '~/vimwiki/', ## Getting help -**Have a question?** -Visit the IRC channel [`#vimwiki`](https://webchat.freenode.net/?channels=#vimwiki) on Freenode ([webchat](https://webchat.freenode.net/?channels=#vimwiki), also synced to Matrix/Riot: `#vimwiki:matrix.org`) or post to the [mailing list](https://groups.google.com/forum/#!forum/vimwiki). +[GitHub issues](https://github.com/vimwiki/vimwiki/issues) are the primary +method for raising bug reports or feature requests. + +Additional resources include the IRC channel [#vimwiki](https://webchat.freenode.net/?channels=#vimwiki) on Freenode +([webchat](https://webchat.freenode.net/?channels=#vimwiki), also synced to Matrix/Riot: `#freenode_#vimwiki:matrix.org` and [Telegram](https://t.me/joinchat/JqBaKBfWs04qNVrp5oWcMg)) +or post to the [mailing list](https://groups.google.com/forum/#!forum/vimwiki). ## Helping VimWiki VimWiki has a lot of users but only very few recurring developers or people helping the community. Your help is therefore appreciated. Everyone can help! -See [#625](https://github.com/vimwiki/vimwiki/issues/625) for information on -how you can help. +See [#625](https://github.com/vimwiki/vimwiki/issues/625) for information on how you can help. + +Also, take a look at [CONTRIBUTING.md](https://github.com/vimwiki/vimwiki/blob/master/CONTRIBUTING.md). + +---- ## License diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim index 7986609..4a13da8 100644 --- a/autoload/vimwiki/base.vim +++ b/autoload/vimwiki/base.vim @@ -3,20 +3,23 @@ " Desc: Basic functionality " Home: https://github.com/vimwiki/vimwiki/ -if exists("g:loaded_vimwiki_auto") || &cp +if exists('g:loaded_vimwiki_auto') || &compatible finish endif let g:loaded_vimwiki_auto = 1 -function! s:safesubstitute(text, search, replace, mode) +let g:vimwiki_max_scan_for_caption = 5 + + +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! s:vimwiki_get_known_syntaxes() +function! s:vimwiki_get_known_syntaxes() abort " Getting all syntaxes that different wikis could have let syntaxes = {} let syntaxes['default'] = 1 @@ -32,7 +35,7 @@ function! s:vimwiki_get_known_syntaxes() endfunction -function! vimwiki#base#file_pattern(files) +function! vimwiki#base#file_pattern(files) abort " Get search regex from glob() " string. Aim to support *all* special characters, forcing the user to choose " names that are compatible with any external restrictions that they @@ -44,7 +47,7 @@ endfunction "FIXME TODO slow and faulty -function! vimwiki#base#subdir(path, filename) +function! vimwiki#base#subdir(path, filename) abort let path = a:path " ensure that we are not fooled by a symbolic link "FIXME if we are not "fooled", we end up in a completely different wiki? @@ -68,12 +71,12 @@ function! vimwiki#base#subdir(path, filename) endfunction -function! vimwiki#base#current_subdir() +function! vimwiki#base#current_subdir() abort return vimwiki#base#subdir(vimwiki#vars#get_wikilocal('path'), expand('%:p')) endfunction -function! vimwiki#base#invsubdir(subdir) +function! vimwiki#base#invsubdir(subdir) abort return substitute(a:subdir, '[^/\.]\+/', '../', 'g') endfunction @@ -81,7 +84,7 @@ endfunction " Returns: the number of the wiki a file belongs to or -1 if it doesn't belong " to any registered wiki. " The path can be the full path or just the directory of the file -function! vimwiki#base#find_wiki(path) +function! vimwiki#base#find_wiki(path) abort let bestmatch = -1 let bestlen = 0 let path = vimwiki#path#path_norm(vimwiki#path#chomp_slash(a:path)) @@ -101,11 +104,17 @@ function! vimwiki#base#find_wiki(path) endfunction +" helper: check if a link is a well formed wiki link +function! s:is_wiki_link(link_infos) abort + return a:link_infos.scheme =~# '\mwiki\d\+' || a:link_infos.scheme ==# 'diary' +endfunction + + " THE central function of Vimwiki. Extract infos about the target from a link. " If the second parameter is present, which should be an absolute file path, it " is assumed that the link appears in that file. Without it, the current file " is used. -function! vimwiki#base#resolve_link(link_text, ...) +function! vimwiki#base#resolve_link(link_text, ...) abort if a:0 let source_wiki = vimwiki#base#find_wiki(a:1) let source_file = a:1 @@ -114,8 +123,9 @@ function! vimwiki#base#resolve_link(link_text, ...) let source_file = vimwiki#path#current_wiki_file() endif - let link_text = a:link_text - + " get rid of '\' in escaped characters in []() style markdown links + " other style links don't allow '\' + let link_text = substitute(a:link_text, '\(\\\)\(\W\)\@=', '', 'g') let link_infos = { \ 'index': -1, @@ -124,12 +134,13 @@ function! vimwiki#base#resolve_link(link_text, ...) \ 'anchor': '', \ } - if link_text == '' + if link_text ==? '' return link_infos endif let scheme = matchstr(link_text, '^\zs'.vimwiki#vars#get_global('rxSchemes').'\ze:') - if scheme == '' + if scheme ==? '' + " interwiki link scheme is default let link_infos.scheme = 'wiki'.source_wiki else let link_infos.scheme = scheme @@ -142,16 +153,16 @@ function! vimwiki#base#resolve_link(link_text, ...) let link_text = matchstr(link_text, '^'.vimwiki#vars#get_global('rxSchemes').':\zs.*\ze') endif - let is_wiki_link = link_infos.scheme =~# '\mwiki\d\+' || link_infos.scheme ==# 'diary' + let is_wiki_link = s:is_wiki_link(link_infos) " extract anchor if is_wiki_link let split_lnk = split(link_text, '#', 1) let link_text = split_lnk[0] - if len(split_lnk) > 1 && split_lnk[-1] != '' + if len(split_lnk) > 1 && split_lnk[-1] !=? '' let link_infos.anchor = join(split_lnk[1:], '#') endif - if link_text == '' " because the link was of the form '#anchor' + if link_text ==? '' " because the link was of the form '#anchor' let expected_ext = vimwiki#u#escape(vimwiki#vars#get_wikilocal('ext')).'$' if source_file =~# expected_ext " Source file has expected extension. Remove it, it will be added later on @@ -163,8 +174,8 @@ function! vimwiki#base#resolve_link(link_text, ...) endif " check if absolute or relative path - if is_wiki_link && link_text[0] == '/' - if link_text != '/' + if is_wiki_link && link_text[0] ==# '/' + if link_text !=# '/' let link_text = link_text[1:] endif let is_relative = 0 @@ -178,11 +189,35 @@ function! vimwiki#base#resolve_link(link_text, ...) " extract the other items depending on the scheme if link_infos.scheme =~# '\mwiki\d\+' - let link_infos.index = eval(matchstr(link_infos.scheme, '\D\+\zs\d\+\ze')) - if link_infos.index < 0 || link_infos.index >= vimwiki#vars#number_of_wikis() - let link_infos.index = -1 - let link_infos.filename = '' - return link_infos + + " interwiki link named wiki 'wn.name:link' format + let wnmatch = matchlist(link_text, '\m^wn\.\([a-zA-Z0-9\-_ ]\+\):\(.*\)') + if len(wnmatch) >= 2 && wnmatch[1] !=? '' && wnmatch[2] !=? '' + let wname = wnmatch[1] + for idx in range(vimwiki#vars#number_of_wikis()) + if vimwiki#vars#get_wikilocal('name', idx) ==# wname + " name matches! + let link_infos.index = idx + let link_text = wnmatch[2] + break + endif + endfor + if link_text !=# wnmatch[2] + " error: invalid wiki name + let link_infos.index = -2 + let link_infos.filename = '' + " use scheme field to return invalid wiki name + let link_infos.scheme = wname + return link_infos + endif + else + " interwiki link numbered wiki format + let link_infos.index = eval(matchstr(link_infos.scheme, '\D\+\zs\d\+\ze')) + if link_infos.index < 0 || link_infos.index >= vimwiki#vars#number_of_wikis() + let link_infos.index = -1 + let link_infos.filename = '' + return link_infos + endif endif if !is_relative || link_infos.index != source_wiki @@ -192,12 +227,15 @@ function! vimwiki#base#resolve_link(link_text, ...) let link_infos.filename = root_dir . link_text if vimwiki#path#is_link_to_dir(link_text) - if vimwiki#vars#get_global('dir_link') != '' + if vimwiki#vars#get_global('dir_link') !=? '' let link_infos.filename .= vimwiki#vars#get_global('dir_link') . \ vimwiki#vars#get_wikilocal('ext', link_infos.index) endif else - let link_infos.filename .= vimwiki#vars#get_wikilocal('ext', link_infos.index) + let ext = fnamemodify(link_text, ':e') + if ext ==? '' " append ext iff one not already present + let link_infos.filename .= vimwiki#vars#get_wikilocal('ext', link_infos.index) + endif endif elseif link_infos.scheme ==# 'diary' @@ -223,12 +261,12 @@ function! vimwiki#base#resolve_link(link_text, ...) endfunction -function! vimwiki#base#system_open_link(url) +function! vimwiki#base#system_open_link(url) abort " handlers - function! s:win32_handler(url) + function! s:win32_handler(url) abort "Disable shellslash for cmd and command.com, but enable for all other shells "See Issue #560 - if (&shell =~? "cmd") || (&shell =~? "command.com") + if (&shell =~? 'cmd') || (&shell =~? 'command.com') if exists('+shellslash') let old_ssl = &shellslash @@ -254,10 +292,10 @@ function! vimwiki#base#system_open_link(url) endif endfunction - function! s:macunix_handler(url) + function! s:macunix_handler(url) abort call system('open ' . shellescape(a:url).' &') endfunction - function! s:linux_handler(url) + function! s:linux_handler(url) abort call system('xdg-open ' . shellescape(a:url).' &') endfunction try @@ -276,7 +314,7 @@ function! vimwiki#base#system_open_link(url) endfunction -function! vimwiki#base#open_link(cmd, link, ...) +function! vimwiki#base#open_link(cmd, link, ...) abort let link_infos = {} if a:0 let link_infos = vimwiki#base#resolve_link(a:link, a:1) @@ -284,26 +322,26 @@ function! vimwiki#base#open_link(cmd, link, ...) let link_infos = vimwiki#base#resolve_link(a:link) endif - if link_infos.filename == '' + if link_infos.filename ==? '' if link_infos.index == -1 echomsg 'Vimwiki Error: No registered wiki ''' . link_infos.scheme . '''.' + elseif link_infos.index == -2 + " scheme field stores wiki name for this error case + echom 'Vimwiki Error: No wiki found with name "' . link_infos.scheme . '"' else echomsg 'Vimwiki Error: Unable to resolve link!' endif return endif - let is_wiki_link = link_infos.scheme =~# '\mwiki\d\+' || link_infos.scheme =~# 'diary' - - let update_prev_link = is_wiki_link && - \ !vimwiki#path#is_equal(link_infos.filename, vimwiki#path#current_wiki_file()) + let is_wiki_link = s:is_wiki_link(link_infos) let vimwiki_prev_link = [] " update previous link for wiki pages - if update_prev_link + if is_wiki_link if a:0 let vimwiki_prev_link = [a:1, []] - elseif &ft ==# 'vimwiki' + elseif vimwiki#u#ft_is_vw() let vimwiki_prev_link = [vimwiki#path#current_wiki_file(), getpos('.')] endif endif @@ -311,69 +349,111 @@ function! vimwiki#base#open_link(cmd, link, ...) " open/edit if is_wiki_link call vimwiki#base#edit_file(a:cmd, link_infos.filename, link_infos.anchor, - \ vimwiki_prev_link, update_prev_link) + \ vimwiki_prev_link, is_wiki_link) else call vimwiki#base#system_open_link(link_infos.filename) endif endfunction -function! vimwiki#base#get_globlinks_escaped() abort +function! vimwiki#base#get_globlinks_escaped(...) abort + let s_arg_lead = a:0 > 0 ? a:1 : '' " only get links from the current dir " change to the directory of the current file let orig_pwd = getcwd() lcd! %:h " all path are relative to the current file's location - let globlinks = glob('*'.vimwiki#vars#get_wikilocal('ext'), 1)."\n" + let globlinks = glob('**/*'.vimwiki#vars#get_wikilocal('ext'), 1)."\n" " remove extensions let globlinks = substitute(globlinks, '\'.vimwiki#vars#get_wikilocal('ext').'\ze\n', '', 'g') " restore the original working directory exe 'lcd! '.orig_pwd " convert to a List let lst = split(globlinks, '\n') + " Filter files whose path matches the user's argument leader + " " use smart case matching + let r_arg = substitute(s_arg_lead, '\u', '[\0\l\0]', 'g') + call filter(lst, '-1 != match(v:val, r_arg)') " Apply fnameescape() to each item call map(lst, 'fnameescape(v:val)') - " Convert back to newline-separated list - let globlinks = join(lst, "\n") - " return all escaped links as a single newline-separated string - return globlinks + " Return list (for customlist completion) + return lst endfunction -function! vimwiki#base#generate_links() - let lines = [] +" Optional pattern argument +function! vimwiki#base#generate_links(create, ...) abort + " Get pattern if present + " Globlal to script to be passed to closure + if a:0 + let s:pattern = a:1 + else + let s:pattern = '' + endif - let links = vimwiki#base#get_wikilinks(vimwiki#vars#get_bufferlocal('wiki_nr'), 0) - call sort(links) + " Define link generator closure + let GeneratorLinks = copy(l:) + function! GeneratorLinks.f() abort + let lines = [] - let bullet = repeat(' ', vimwiki#lst#get_list_margin()) . vimwiki#lst#default_symbol().' ' - for link in links - let abs_filepath = vimwiki#path#abs_path_of_link(link) - if !s:is_diary_file(abs_filepath) - call add(lines, bullet. - \ s:safesubstitute(vimwiki#vars#get_global('WikiLinkTemplate1'), - \ '__LinkUrl__', link, '')) - endif - endfor + let links = vimwiki#base#get_wikilinks(vimwiki#vars#get_bufferlocal('wiki_nr'), 0, s:pattern) + call sort(links) - let links_rx = '\m^\s*'.vimwiki#u#escape(vimwiki#lst#default_symbol()).' ' + let bullet = repeat(' ', vimwiki#lst#get_list_margin()) . vimwiki#lst#default_symbol().' ' + let l:diary_file_paths = vimwiki#diary#get_diary_files() - call vimwiki#base#update_listing_in_buffer(lines, 'Generated Links', links_rx, line('$')+1, 1) + for link in links + let link_infos = vimwiki#base#resolve_link(link) + if !vimwiki#base#is_diary_file(link_infos.filename, copy(l:diary_file_paths)) + if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown' + let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink1Template') + else + let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate1') + endif + + let link_caption = vimwiki#base#read_caption(link_infos.filename) + if link_caption ==? '' " default to link if caption not found + let link_caption = link + endif + + let entry = s:safesubstitute(link_tpl, '__LinkUrl__', link, '') + let entry = s:safesubstitute(entry, '__LinkDescription__', link_caption, '') + call add(lines, bullet. entry) + endif + endfor + + return lines + endfunction + + let links_rx = '\%(^\s*$\)\|\%('.vimwiki#vars#get_syntaxlocal('rxListBullet').'\)' + + call vimwiki#base#update_listing_in_buffer( + \ GeneratorLinks, + \ vimwiki#vars#get_global('links_header'), + \ links_rx, + \ line('$')+1, + \ vimwiki#vars#get_global('links_header_level'), + \ a:create) endfunction -function! vimwiki#base#goto(...) - let key = a:1 +function! vimwiki#base#goto(...) abort + let key = a:0 > 0 ? a:1 : input('Enter name: ') let anchor = a:0 > 1 ? a:2 : '' + " Save current file pos + let vimwiki_prev_link = [vimwiki#path#current_wiki_file(), getpos('.')] + call vimwiki#base#edit_file(':e', \ vimwiki#vars#get_wikilocal('path') . key . vimwiki#vars#get_wikilocal('ext'), - \ anchor) + \ anchor, + \ vimwiki_prev_link, + \ vimwiki#u#ft_is_vw()) endfunction -function! vimwiki#base#backlinks() - let current_filename = expand("%:p") +function! vimwiki#base#backlinks() abort + let current_filename = expand('%:p') let locations = [] for idx in range(vimwiki#vars#number_of_wikis()) let syntax = vimwiki#vars#get_wikilocal('syntax', idx) @@ -381,6 +461,11 @@ function! vimwiki#base#backlinks() for source_file in wikifiles let links = s:get_links(source_file, idx) for [target_file, _, lnum, col] in links + if vimwiki#u#is_windows() + " TODO this is a temporary fix - see issue #478 + let target_file = substitute(target_file, '/', '\', 'g') + let current_filename = substitute(current_filename, '/', '\', 'g') + endif " don't include links from the current file to itself if vimwiki#path#is_equal(target_file, current_filename) && \ !vimwiki#path#is_equal(target_file, source_file) @@ -402,7 +487,8 @@ endfunction " Returns: a list containing all files of the given wiki as absolute file path. " If the given wiki number is negative, the diary of the current wiki is used " If the second argument is not zero, only directories are found -function! vimwiki#base#find_files(wiki_nr, directories_only) +" If third argument: pattern to search for +function! vimwiki#base#find_files(wiki_nr, directories_only, ...) abort let wiki_nr = a:wiki_nr if wiki_nr >= 0 let root_directory = vimwiki#vars#get_wikilocal('path', wiki_nr) @@ -416,15 +502,26 @@ function! vimwiki#base#find_files(wiki_nr, directories_only) else let ext = vimwiki#vars#get_wikilocal('ext', wiki_nr) endif + " If pattern is given, use it " if current wiki is temporary -- was added by an arbitrary wiki file then do " not search wiki files in subdirectories. Or it would hang the system if " wiki file was created in $HOME or C:/ dirs. - if vimwiki#vars#get_wikilocal('is_temporary_wiki', wiki_nr) + if a:0 && a:1 !=# '' + let pattern = a:1 + elseif vimwiki#vars#get_wikilocal('is_temporary_wiki', wiki_nr) let pattern = '*'.ext else let pattern = '**/*'.ext endif - return split(globpath(root_directory, pattern), '\n') + let files = split(globpath(root_directory, pattern), '\n') + + " filter excluded files before returning + for pattern in vimwiki#vars#get_wikilocal('exclude_files') + let efiles = split(globpath(root_directory, pattern), '\n') + let files = filter(files, 'index(efiles, v:val) == -1') + endfor + + return files endfunction @@ -432,8 +529,9 @@ endfunction " files in the given wiki. " If the given wiki number is negative, the diary of the current wiki is used. " If also_absolute_links is nonzero, also return links of the form /file -function! vimwiki#base#get_wikilinks(wiki_nr, also_absolute_links) - let files = vimwiki#base#find_files(a:wiki_nr, 0) +" If pattern is not '', only filepaths matching pattern will be considered +function! vimwiki#base#get_wikilinks(wiki_nr, also_absolute_links, pattern) abort + let files = vimwiki#base#find_files(a:wiki_nr, 0, a:pattern) if a:wiki_nr == vimwiki#vars#get_bufferlocal('wiki_nr') let cwd = vimwiki#path#wikify_path(expand('%:p:h')) elseif a:wiki_nr < 0 @@ -444,6 +542,10 @@ function! vimwiki#base#get_wikilinks(wiki_nr, also_absolute_links) let result = [] for wikifile in files let wikifile = fnamemodify(wikifile, ':r') " strip extension + if vimwiki#u#is_windows() + " TODO temporary fix see #478 + let wikifile = substitute(wikifile , '/', '\', 'g') + endif let wikifile = vimwiki#path#relpath(cwd, wikifile) call add(result, wikifile) endfor @@ -455,6 +557,10 @@ function! vimwiki#base#get_wikilinks(wiki_nr, also_absolute_links) let cwd = vimwiki#vars#get_wikilocal('path') . vimwiki#vars#get_wikilocal('diary_rel_path') endif let wikifile = fnamemodify(wikifile, ':r') " strip extension + if vimwiki#u#is_windows() + " TODO temporary fix see #478 + let wikifile = substitute(wikifile , '/', '\', 'g') + endif let wikifile = '/'.vimwiki#path#relpath(cwd, wikifile) call add(result, wikifile) endfor @@ -464,7 +570,7 @@ endfunction " Returns: a list containing the links to all directories from the current file -function! vimwiki#base#get_wiki_directories(wiki_nr) +function! vimwiki#base#get_wiki_directories(wiki_nr) abort let dirs = vimwiki#base#find_files(a:wiki_nr, 1) if a:wiki_nr == vimwiki#vars#get_bufferlocal('wiki_nr') let cwd = vimwiki#path#wikify_path(expand('%:p:h')) @@ -485,7 +591,7 @@ function! vimwiki#base#get_wiki_directories(wiki_nr) endfunction -function! vimwiki#base#get_anchors(filename, syntax) +function! vimwiki#base#get_anchors(filename, syntax) abort if !filereadable(a:filename) return [] endif @@ -514,7 +620,7 @@ function! vimwiki#base#get_anchors(filename, syntax) else let current_complete_anchor = '' for l in range(level-1) - if anchor_level[l] != '' + if anchor_level[l] !=? '' let current_complete_anchor .= anchor_level[l].'#' endif endfor @@ -527,11 +633,11 @@ function! vimwiki#base#get_anchors(filename, syntax) let bold_count = 1 while 1 let bold_text = matchstr(line, rxbold, 0, bold_count) - if bold_text == '' + if bold_text ==? '' break endif call add(anchors, bold_text) - if current_complete_anchor != '' + if current_complete_anchor !=? '' call add(anchors, current_complete_anchor.'#'.bold_text) endif let bold_count += 1 @@ -541,12 +647,12 @@ function! vimwiki#base#get_anchors(filename, syntax) let tag_count = 1 while 1 let tag_group_text = matchstr(line, rxtag, 0, tag_count) - if tag_group_text == '' + if tag_group_text ==? '' break endif for tag_text in split(tag_group_text, ':') call add(anchors, tag_text) - if current_complete_anchor != '' + if current_complete_anchor !=? '' call add(anchors, current_complete_anchor.'#'.tag_text) endif endfor @@ -559,7 +665,7 @@ function! vimwiki#base#get_anchors(filename, syntax) endfunction -function! s:jump_to_anchor(anchor) +function! s:jump_to_anchor(anchor) abort let oldpos = getpos('.') call cursor(1, 1) @@ -592,13 +698,18 @@ endfunction " Returns: a list of all links inside the wiki file " Every list item has the form " [target file, anchor, line number of the link in source file, column number] -function! s:get_links(wikifile, idx) +function! s:get_links(wikifile, idx) abort if !filereadable(a:wikifile) return [] endif let syntax = vimwiki#vars#get_wikilocal('syntax', a:idx) - let rx_link = vimwiki#vars#get_syntaxlocal('wikilink', syntax) + if syntax ==# 'markdown' + let rx_link = vimwiki#vars#get_syntaxlocal('rxWeblink1MatchUrl', syntax) + else + let rx_link = vimwiki#vars#get_syntaxlocal('wikilink', syntax) + endif + let links = [] let lnum = 0 @@ -609,12 +720,12 @@ function! s:get_links(wikifile, idx) while 1 let col = match(line, rx_link, 0, link_count)+1 let link_text = matchstr(line, rx_link, 0, link_count) - if link_text == '' + if link_text ==? '' break endif let link_count += 1 let target = vimwiki#base#resolve_link(link_text, a:wikifile) - if target.filename != '' && target.scheme =~# '\mwiki\d\+\|diary\|file\|local' + if target.filename !=? '' && target.scheme =~# '\mwiki\d\+\|diary\|file\|local' call add(links, [target.filename, target.anchor, lnum, col]) endif endwhile @@ -624,7 +735,7 @@ function! s:get_links(wikifile, idx) endfunction -function! vimwiki#base#check_links() +function! vimwiki#base#check_links() abort let anchors_of_files = {} let links_of_files = {} let errors = [] @@ -639,26 +750,26 @@ function! vimwiki#base#check_links() for wikifile in keys(links_of_files) for [target_file, target_anchor, lnum, col] in links_of_files[wikifile] - if target_file == '' && target_anchor == '' + if target_file ==? '' && target_anchor ==? '' call add(errors, {'filename':wikifile, 'lnum':lnum, 'col':col, - \ 'text': "numbered scheme refers to a non-existent wiki"}) + \ 'text': 'numbered scheme refers to a non-existent wiki'}) elseif has_key(anchors_of_files, target_file) - if target_anchor != '' && index(anchors_of_files[target_file], target_anchor) < 0 + if target_anchor !=? '' && index(anchors_of_files[target_file], target_anchor) < 0 call add(errors, {'filename':wikifile, 'lnum':lnum, 'col':col, - \'text': "there is no such anchor: ".target_anchor}) + \'text': 'there is no such anchor: '.target_anchor}) endif else - if target_file =~ '\m/$' " maybe it's a link to a directory + if target_file =~? '\m/$' " maybe it's a link to a directory if !isdirectory(target_file) call add(errors, {'filename':wikifile, 'lnum':lnum, 'col':col, - \'text': "there is no such directory: ".target_file}) + \'text': 'there is no such directory: '.target_file}) endif else " maybe it's a non-wiki file if filereadable(target_file) let anchors_of_files[target_file] = [] else call add(errors, {'filename':wikifile, 'lnum':lnum, 'col':col, - \'text': "there is no such file: ".target_file}) + \'text': 'there is no such file: '.target_file}) endif endif endif @@ -699,7 +810,7 @@ function! vimwiki#base#check_links() break endif endfor - if next_unvisited_wikifile == '' + if next_unvisited_wikifile ==? '' break endif for [target_file, target_anchor, lnum, col] in links_of_files[next_unvisited_wikifile] @@ -711,7 +822,7 @@ function! vimwiki#base#check_links() for wf in keys(reachable_wikifiles) if reachable_wikifiles[wf] == 0 - call add(errors, {'text':wf." is not reachable from the index file"}) + call add(errors, {'text':wf.' is not reachable from the index file'}) endif endfor @@ -724,9 +835,9 @@ function! vimwiki#base#check_links() endfunction -function! vimwiki#base#edit_file(command, filename, anchor, ...) +function! vimwiki#base#edit_file(command, filename, anchor, ...) abort let fname = escape(a:filename, '% *|#`') - let dir = fnamemodify(a:filename, ":p:h") + let dir = fnamemodify(a:filename, ':p:h') let ok = vimwiki#path#mkdir(dir, 1) @@ -741,22 +852,16 @@ function! vimwiki#base#edit_file(command, filename, anchor, ...) " This hack is necessary because apparently Vim messes up the result of " getpos() directly after this command. Strange. if !(a:command ==# ':e ' && vimwiki#path#is_equal(a:filename, expand('%:p'))) - if &autowriteall && !&hidden " in this case, the file is saved before switching to the - " new buffer. This causes Vim to show two messages in the command line which triggers - " the annoying hit-enter prompt. Solution: show no messages at all. - silent execute a:command fname - else - try - execute a:command fname - catch /E37:/ - echomsg 'Vimwiki: Can''t leave the current buffer, because it is modified. Hint: Take a look at' - \ ''':h g:vimwiki_autowriteall'' to see how to save automatically.' - return - catch /E325:/ - echom 'Vimwiki: Vim couldn''t open the file, probably because a swapfile already exists. See :h E325.' - return - endtry - endif + try + execute a:command fname + catch /E37:/ + echomsg 'Vimwiki: Can''t leave the current buffer, because it is modified. Hint: Take a look at' + \ ''':h g:vimwiki_autowriteall'' to see how to save automatically.' + return + catch /E325:/ + echom 'Vimwiki: Vim couldn''t open the file, probably because a swapfile already exists. See :h E325.' + return + endtry " If the opened file was not already loaded by Vim, an autocommand is " triggered at this point @@ -764,11 +869,11 @@ function! vimwiki#base#edit_file(command, filename, anchor, ...) " Make sure no other plugin takes ownership over the new file. Vimwiki " rules them all! Well, except for directories, which may be opened with " Netrw - if &filetype != 'vimwiki' && fname !~ '\m/$' - setfiletype vimwiki + if !vimwiki#u#ft_is_vw() && fname !~? '\m/$' + call vimwiki#u#ft_set() endif endif - if a:anchor != '' + if a:anchor !=? '' call s:jump_to_anchor(a:anchor) endif @@ -776,12 +881,14 @@ function! vimwiki#base#edit_file(command, filename, anchor, ...) " a:1 -- previous vimwiki link to save " a:2 -- should we update previous link if a:0 && a:2 && len(a:1) > 0 - call vimwiki#vars#set_bufferlocal('prev_link', a:1) + let prev_links = vimwiki#vars#get_bufferlocal('prev_links') + call insert(prev_links, a:1) + call vimwiki#vars#set_bufferlocal('prev_links', prev_links) endif endfunction -function! vimwiki#base#search_word(wikiRx, cmd) +function! vimwiki#base#search_word(wikiRx, cmd) abort let match_line = search(a:wikiRx, 's'.a:cmd) if match_line == 0 echomsg 'Vimwiki: Wiki link not found' @@ -790,7 +897,7 @@ endfunction " Returns part of the line that matches wikiRX at cursor -function! vimwiki#base#matchstr_at_cursor(wikiRX) +function! vimwiki#base#matchstr_at_cursor(wikiRX) abort let col = col('.') - 1 let line = getline('.') let ebeg = -1 @@ -808,12 +915,12 @@ function! vimwiki#base#matchstr_at_cursor(wikiRX) if ebeg >= 0 return strpart(line, ebeg, elen) else - return "" + return '' endif endfunction -function! vimwiki#base#replacestr_at_cursor(wikiRX, sub) +function! vimwiki#base#replacestr_at_cursor(wikiRX, sub) abort let col = col('.') - 1 let line = getline('.') let ebeg = -1 @@ -836,25 +943,46 @@ function! vimwiki#base#replacestr_at_cursor(wikiRX, sub) endfunction -function! s:print_wiki_list() - let idx = 0 - while idx < vimwiki#vars#number_of_wikis() +function! s:print_wiki_list() abort + " find the max name length for prettier formatting + let max_len = 0 + for idx in range(vimwiki#vars#number_of_wikis()) + let wname = vimwiki#vars#get_wikilocal('name', idx) + if len(wname) > max_len + let max_len = len(wname) + endif + endfor + + " print each wiki, active wiki highlighted and marked with '*' + for idx in range(vimwiki#vars#number_of_wikis()) if idx == vimwiki#vars#get_bufferlocal('wiki_nr') - let sep = ' * ' + let sep = '*' echohl PmenuSel else - let sep = ' ' + let sep = ' ' echohl None endif - echo (idx + 1) . sep . vimwiki#vars#get_wikilocal('path', idx) - let idx += 1 - endwhile + let wname = vimwiki#vars#get_wikilocal('name', idx) + let wpath = vimwiki#vars#get_wikilocal('path', idx) + if wname ==? '' + let wname = '----' + if max_len < 4 + let max_len = 4 + endif + endif + let wname = '"' . wname . '"' + echo printf('%2d %s %-*s %s', idx+1, sep, max_len+2, wname, wpath) + endfor echohl None endfunction -function! s:update_wiki_link(fname, old, new) - echo "Updating links in ".a:fname +" Update link: in fname.ext +" Param: fname: the source file where to change links +" Param: old: url regex of old path relative to wiki root +" Param: new: url string of new path +function! s:update_wiki_link(fname, old, new) abort + echo 'Updating links in '.a:fname let has_updates = 0 let dest = [] for line in readfile(a:fname) @@ -862,7 +990,7 @@ function! s:update_wiki_link(fname, old, new) let has_updates = 1 endif " XXX: any other characters to escape!? - call add(dest, substitute(line, a:old, escape(a:new, "&"), "g")) + call add(dest, substitute(line, a:old, escape(a:new, '&'), 'g')) endfor " add exception handling... if has_updates @@ -873,72 +1001,88 @@ function! s:update_wiki_link(fname, old, new) endfunction -function! s:update_wiki_links_dir(wiki_nr, dir, old_fname, new_fname) - let old_fname = substitute(a:old_fname, '[/\\]', '[/\\\\]', 'g') - let new_fname = a:new_fname +" Update link for all files in dir +" Param: old_url, new_url: path of the old, new url relative to ... +" Param: dir: directory of the files, relative to wiki_root +function! s:update_wiki_links(wiki_nr, dir, old_url, new_url) abort + " Get list of wiki files + let wiki_root = vimwiki#vars#get_wikilocal('path', a:wiki_nr) + let fsources = vimwiki#base#find_files(a:wiki_nr, 0) - let old_fname_r = vimwiki#base#apply_template( - \ vimwiki#vars#get_syntaxlocal('WikiLinkMatchUrlTemplate', - \ vimwiki#vars#get_wikilocal('syntax', a:wiki_nr)), old_fname, '', '') + " Shorten dirname + let dir_rel_root = vimwiki#path#relpath(wiki_root, a:dir) - let files = split(glob(vimwiki#vars#get_wikilocal('path', a:wiki_nr).a:dir.'*'. - \ vimwiki#vars#get_wikilocal('ext', a:wiki_nr)), '\n') - for fname in l:files - call s:update_wiki_link(fname, old_fname_r, new_fname) + " Cache relative url, because they are often the same, like `../dir1/vim-vimwiki.md` + let cache_dict = {} + + " Regex from path + function! s:compute_old_url_r(wiki_nr, dir_rel_fsource, old_url) abort + " Old url + let old_url_r = a:dir_rel_fsource . a:old_url + " Add potential ./ + let old_url_r = '\%(\.[/\\]\)\?' . old_url_r + " Compute old url regex with filename between \zs and \ze + let old_url_r = vimwiki#base#apply_template( + \ vimwiki#vars#get_syntaxlocal('WikiLinkMatchUrlTemplate', + \ vimwiki#vars#get_wikilocal('syntax', a:wiki_nr)), old_url_r, '', '') + + return old_url_r + endfunction + + " For each wikifile + for fsource in fsources + " Shorten fname directory + let fsource_rel_root = vimwiki#path#relpath(wiki_root, fsource) + let fsource_rel_root = fnamemodify(fsource_rel_root, ':h') + + " Compute old_url relative to fname + let dir_rel_fsource = vimwiki#path#relpath(fsource_rel_root, dir_rel_root) + " TODO get relpath coherent (and remove next 2 stuff) + " Remove the trailing ./ + if dir_rel_fsource =~# '.[/\\]$' + let dir_rel_fsource = dir_rel_fsource[:-3] + endif + " Append a / if needed + if !empty(dir_rel_fsource) && dir_rel_fsource !~# '[/\\]$' + let dir_rel_fsource .= '/' + endif + + " New url + let new_url = dir_rel_fsource . a:new_url + + " Old url + " Avoid E713 + let key = empty(dir_rel_fsource) ? 'NaF' : dir_rel_fsource + if index(keys(cache_dict), key) == -1 + let cache_dict[key] = s:compute_old_url_r( + \ a:wiki_nr, dir_rel_fsource, a:old_url) + endif + let old_url_r = cache_dict[key] + + " Update url in source file + call s:update_wiki_link(fsource, old_url_r, new_url) endfor endfunction -function! s:tail_name(fname) - let result = substitute(a:fname, ":", "__colon__", "g") - let result = fnamemodify(result, ":t:r") - let result = substitute(result, "__colon__", ":", "g") +function! s:tail_name(fname) abort + let result = substitute(a:fname, ':', '__colon__', 'g') + let result = fnamemodify(result, ':t:r') + let result = substitute(result, '__colon__', ':', 'g') return result endfunction -function! s:update_wiki_links(wiki_nr, old_fname, new_fname,old_fname_relpath) - let old_fname = a:old_fname - let new_fname = a:new_fname - - let subdirs = split(a:old_fname_relpath, '[/\\]')[: -2] - - " TODO: Use Dictionary here... - let dirs_keys = [''] - let dirs_vals = [''] - if len(subdirs) > 0 - let dirs_keys = [''] - let dirs_vals = [join(subdirs, '/').'/'] - let idx = 0 - while idx < len(subdirs) - 1 - call add(dirs_keys, join(subdirs[: idx], '/').'/') - call add(dirs_vals, join(subdirs[idx+1 :], '/').'/') - let idx = idx + 1 - endwhile - call add(dirs_keys,join(subdirs, '/').'/') - call add(dirs_vals, '') - endif - - let idx = 0 - while idx < len(dirs_keys) - let dir = dirs_keys[idx] - let new_dir = dirs_vals[idx] - call s:update_wiki_links_dir(a:wiki_nr, dir, new_dir.old_fname, new_dir.new_fname) - let idx = idx + 1 - endwhile -endfunction - - -function! s:get_wiki_buffers() +function! s:get_wiki_buffers() abort let blist = [] let bcount = 1 - while bcount<=bufnr("$") + while bcount<=bufnr('$') if bufexists(bcount) - let bname = fnamemodify(bufname(bcount), ":p") + let bname = fnamemodify(bufname(bcount), ':p') " this may find buffers that are not part of the current wiki, but that " doesn't hurt - if bname =~# vimwiki#vars#get_wikilocal('ext')."$" - let bitem = [bname, vimwiki#vars#get_bufferlocal('prev_link', bcount)] + if bname =~# vimwiki#vars#get_wikilocal('ext').'$' + let bitem = [bname, vimwiki#vars#get_bufferlocal('prev_links', bcount)] call add(blist, bitem) endif endif @@ -948,10 +1092,10 @@ function! s:get_wiki_buffers() endfunction -function! s:open_wiki_buffer(item) +function! s:open_wiki_buffer(item) abort call vimwiki#base#edit_file(':e', a:item[0], '') if !empty(a:item[1]) - call vimwiki#vars#set_bufferlocal('prev_link', a:item[1], a:item[0]) + call vimwiki#vars#set_bufferlocal('prev_links', a:item[1], a:item[0]) endif endfunction @@ -972,12 +1116,18 @@ function! vimwiki#base#nested_syntax(filetype, start, end, textSnipHl) abort " let b:skip_set_iskeyword = 1 let is_keyword = &iskeyword - try - " keep going even if syntax file is not found + " Check for the existence of syntax files in the runtime path before + " attempting to include them. + " https://vi.stackexchange.com/a/10354 + " Previously, this used a try/catch block to intercept any errors thrown + " when attempting to include files. The error(s) interferred with running + " with Vader tests (specifically, testing VimwikiSearch). + if !empty(globpath(&runtimepath, 'syntax/'.a:filetype.'.vim')) execute 'syntax include @'.group.' syntax/'.a:filetype.'.vim' + endif + if !empty(globpath(&runtimepath, 'after/syntax/'.a:filetype.'.vim')) execute 'syntax include @'.group.' after/syntax/'.a:filetype.'.vim' - catch - endtry + endif let &iskeyword = is_keyword @@ -994,10 +1144,11 @@ function! vimwiki#base#nested_syntax(filetype, start, end, textSnipHl) abort let group='texMathZoneGroup' endif + let concealpre = vimwiki#vars#get_global('conceal_pre') ? ' concealends' : '' execute 'syntax region textSnip'.ft. \ ' matchgroup='.a:textSnipHl. \ ' start="'.a:start.'" end="'.a:end.'"'. - \ ' contains=@'.group.' keepend' + \ ' contains=@'.group.' keepend'.concealpre " A workaround to Issue 115: Nested Perl syntax highlighting differs from " regular one. @@ -1015,14 +1166,14 @@ endfunction " creates or updates auto-generated listings in a wiki file, like TOC, diary " links, tags list etc. -" - the listing consists of a level 1 header and a list of strings as content +" - the listing consists of a header and a list of strings provided by a funcref " - a:content_regex is used to determine how long a potentially existing list is " - a:default_lnum is the line number where the new listing should be placed if " it's not already present " - if a:create is true, it will be created if it doesn't exist, otherwise it " will only be updated if it already exists -function! vimwiki#base#update_listing_in_buffer(strings, start_header, - \ content_regex, default_lnum, create) +function! vimwiki#base#update_listing_in_buffer(Generator, start_header, + \ content_regex, default_lnum, header_level, create) abort " Vim behaves strangely when files change while in diff mode if &diff || &readonly return @@ -1031,7 +1182,8 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, " check if the listing is already there let already_there = 0 - let header_rx = '\m^\s*'.substitute(vimwiki#vars#get_syntaxlocal('rxH1_Template'), + let header_level = 'rxH' . a:header_level . '_Template' + let header_rx = '\m^\s*'.substitute(vimwiki#vars#get_syntaxlocal(header_level), \ '__Header__', a:start_header, '') .'\s*$' let start_lnum = 1 @@ -1077,23 +1229,39 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, let start_lnum = a:default_lnum let is_cursor_after_listing = ( cursor_line > a:default_lnum ) let whitespaces_in_first_line = '' + " append newline if not replacing first line + if start_lnum > 1 + keepjumps call append(start_lnum -1, '') + let start_lnum += 1 + endif endif let start_of_listing = start_lnum " write new listing let new_header = whitespaces_in_first_line - \ . s:safesubstitute(vimwiki#vars#get_syntaxlocal('rxH1_Template'), + \ . s:safesubstitute(vimwiki#vars#get_syntaxlocal(header_level), \ '__Header__', a:start_header, '') keepjumps call append(start_lnum - 1, new_header) let start_lnum += 1 - let lines_diff += 1 + len(a:strings) - for string in a:strings + let lines_diff += 1 + if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown' + for _ in range(vimwiki#vars#get_global('markdown_header_style')) + keepjumps call append(start_lnum - 1, '') + let start_lnum += 1 + let lines_diff += 1 + endfor + endif + for string in a:Generator.f() keepjumps call append(start_lnum - 1, string) let start_lnum += 1 + let lines_diff += 1 endfor - " append an empty line if there is not one - if start_lnum <= line('$') && getline(start_lnum) !~# '\m^\s*$' + + " remove empty line if end of file, otherwise append if needed + if start_lnum == line('$') + silent exe 'keepjumps ' . start_lnum.'delete _' + elseif start_lnum < line('$') && getline(start_lnum) !~# '\m^\s*$' keepjumps call append(start_lnum - 1, '') let lines_diff += 1 endif @@ -1110,23 +1278,28 @@ function! vimwiki#base#update_listing_in_buffer(strings, start_header, call winrestview(winview_save) endfunction +function! vimwiki#base#find_next_task() abort + let taskRegex = vimwiki#vars#get_syntaxlocal('rxListItemWithoutCB') + \ . '\+\(\[ \]\s\+\)\zs' + call vimwiki#base#search_word(taskRegex, '') +endfunction -function! vimwiki#base#find_next_link() +function! vimwiki#base#find_next_link() abort call vimwiki#base#search_word(vimwiki#vars#get_syntaxlocal('rxAnyLink'), '') endfunction -function! vimwiki#base#find_prev_link() +function! vimwiki#base#find_prev_link() abort "Jump 2 times if the cursor is in the middle of a link - if synIDattr(synID(line('.'), col('.'), 0), "name") =~# "VimwikiLink.*" && - \ synIDattr(synID(line('.'), col('.')-1, 0), "name") =~# "VimwikiLink.*" + if synIDattr(synID(line('.'), col('.'), 0), 'name') =~# 'VimwikiLink.*' && + \ synIDattr(synID(line('.'), col('.')-1, 0), 'name') =~# 'VimwikiLink.*' call vimwiki#base#search_word(vimwiki#vars#get_syntaxlocal('rxAnyLink'), 'b') endif call vimwiki#base#search_word(vimwiki#vars#get_syntaxlocal('rxAnyLink'), 'b') endfunction -function! vimwiki#base#follow_link(split, ...) +function! vimwiki#base#follow_link(split, ...) abort let reuse_other_split_window = a:0 >= 1 ? a:1 : 0 let move_cursor_to_new_window = a:0 >= 2 ? a:2 : 1 @@ -1137,30 +1310,44 @@ function! vimwiki#base#follow_link(split, ...) let lnk = matchstr(vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWikiLink')), \ vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchUrl')) " try WikiIncl - if lnk == "" + if lnk ==? '' let lnk = matchstr(vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_global('rxWikiIncl')), \ vimwiki#vars#get_global('rxWikiInclMatchUrl')) endif " try Weblink - if lnk == "" + if lnk ==? '' let lnk = matchstr(vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWeblink')), \ vimwiki#vars#get_syntaxlocal('rxWeblinkMatchUrl')) endif - if lnk != "" " cursor is indeed on a link + if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown' + " markdown image ![]() + if lnk ==# '' + let lnk = matchstr(vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_syntaxlocal('rxImage')), + \ vimwiki#vars#get_syntaxlocal('rxWeblinkMatchUrl')) + if lnk !=# '' + if lnk !~# '\%(\%('.vimwiki#vars#get_global('web_schemes1').'\):\%(\/\/\)\?\)\S\{-1,}' + " prepend file: scheme so link is opened by sytem handler if it isn't a web url + let lnk = 'file:'.lnk + endif + endif + endif + endif + + if lnk !=? '' " cursor is indeed on a link let processed_by_user_defined_handler = VimwikiLinkHandler(lnk) if processed_by_user_defined_handler return endif - if a:split ==# "hsplit" - let cmd = ":split " - elseif a:split ==# "vsplit" - let cmd = ":vsplit " - elseif a:split ==# "tab" - let cmd = ":tabnew " + if a:split ==# 'hsplit' + let cmd = ':split ' + elseif a:split ==# 'vsplit' + let cmd = ':vsplit ' + elseif a:split ==# 'tab' + let cmd = ':tabnew ' else - let cmd = ":e " + let cmd = ':e ' endif " if we want to and can reuse a split window, jump to that window and open @@ -1174,7 +1361,7 @@ function! vimwiki#base#follow_link(split, ...) endif - if vimwiki#vars#get_wikilocal('syntax') == 'markdown' + if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown' let processed_by_markdown_reflink = vimwiki#markdown_base#open_reflink(lnk) if processed_by_markdown_reflink return @@ -1197,18 +1384,26 @@ function! vimwiki#base#follow_link(split, ...) endif endif - else + else " cursor is not on a link if a:0 >= 3 - execute "normal! ".a:3 - else + execute 'normal! '.a:3 + elseif vimwiki#vars#get_global('create_link') call vimwiki#base#normalize_link(0) endif endif endfunction -function! vimwiki#base#go_back_link() - let prev_link = vimwiki#vars#get_bufferlocal('prev_link') +function! vimwiki#base#go_back_link() abort + " try pop previous link from buffer list + let prev_links = vimwiki#vars#get_bufferlocal('prev_links') + if !empty(prev_links) + let prev_link = remove(prev_links, 0) + call vimwiki#vars#set_bufferlocal('prev_links', prev_links) + else + let prev_link = [] + endif + if !empty(prev_link) " go back to saved wiki link call vimwiki#base#edit_file(':e ', prev_link[0], '') @@ -1220,20 +1415,23 @@ function! vimwiki#base#go_back_link() endfunction -function! vimwiki#base#goto_index(wnum, ...) +function! vimwiki#base#goto_index(wnum, ...) abort + + " if wnum = 0 the current wiki is used + if a:wnum == 0 + let idx = vimwiki#vars#get_bufferlocal('wiki_nr') + if idx < 0 " not in a wiki + let idx = 0 + endif + else + let idx = a:wnum - 1 " convert to 0 based counting + endif + if a:wnum > vimwiki#vars#number_of_wikis() echomsg 'Vimwiki Error: Wiki '.a:wnum.' is not registered in your Vimwiki settings!' return endif - " usually a:wnum is greater then 0 but with the following command it is == 0: - " vim -n -c ":VimwikiIndex" - if a:wnum > 0 - let idx = a:wnum - 1 - else - let idx = 0 - endif - if a:0 if a:1 == 1 let cmd = 'tabedit' @@ -1254,7 +1452,7 @@ function! vimwiki#base#goto_index(wnum, ...) endfunction -function! vimwiki#base#delete_link() +function! vimwiki#base#delete_link() abort " Delete wiki file you are in from filesystem let val = input('Delete "'.expand('%').'" [y]es/[N]o? ') if val !~? '^y' @@ -1269,22 +1467,26 @@ function! vimwiki#base#delete_link() endtry call vimwiki#base#go_back_link() - execute "bdelete! ".escape(fname, " ") + execute 'bdelete! '.escape(fname, ' ') " reread buffer => deleted wiki link should appear as non-existent - if expand('%:p') != "" - execute "e" + if expand('%:p') !=? '' + execute 'e' endif endfunction " Rename current file, update all links to it -function! vimwiki#base#rename_link() +function! vimwiki#base#rename_link() abort + " Get filename relative to wiki root let subdir = vimwiki#vars#get_bufferlocal('subdir') let old_fname = subdir.expand('%:t') + " Get current path + let old_dir = expand('%:p:h') + " there is no file (new one maybe) - if glob(expand('%:p')) == '' + if glob(expand('%:p')) ==? '' echomsg 'Vimwiki Error: Cannot rename "'.expand('%:p'). \'". It does not exist! (New file? Save it before renaming.)' return @@ -1302,23 +1504,23 @@ function! vimwiki#base#rename_link() return endif - if substitute(new_link, '\s', '', 'g') == '' + if substitute(new_link, '\s', '', 'g') ==? '' echomsg 'Vimwiki Error: Cannot rename to an empty filename!' return endif let url = matchstr(new_link, vimwiki#vars#get_syntaxlocal('rxWikiLinkMatchUrl')) - if url != '' + if url !=? '' let new_link = url endif let new_link = subdir.new_link - let wiki_nr = vimwiki#vars#get_bufferlocal("wiki_nr") + let wiki_nr = vimwiki#vars#get_bufferlocal('wiki_nr') let new_fname = vimwiki#vars#get_wikilocal('path') . new_link . vimwiki#vars#get_wikilocal('ext') " do not rename if file with such name exists let fname = glob(new_fname) - if fname != '' + if fname !=? '' echomsg 'Vimwiki Error: Cannot rename to "'.new_fname.'". File with that name exist!' return endif @@ -1327,16 +1529,16 @@ function! vimwiki#base#rename_link() echomsg 'Vimwiki: Renaming '.vimwiki#vars#get_wikilocal('path').old_fname.' to '.new_fname let res = rename(expand('%:p'), expand(new_fname)) if res != 0 - throw "Cannot rename!" + throw 'Cannot rename!' end catch /.*/ echomsg 'Vimwiki Error: Cannot rename "'.expand('%:t:r').'" to "'.new_fname.'"' return endtry - let &buftype="nofile" + let &buftype='nofile' - let cur_buffer = [expand('%:p'), vimwiki#vars#get_bufferlocal('prev_link')] + let cur_buffer = [expand('%:p'), vimwiki#vars#get_bufferlocal('prev_links')] let blist = s:get_wiki_buffers() @@ -1357,7 +1559,7 @@ function! vimwiki#base#rename_link() setlocal nomore " update links - call s:update_wiki_links(wiki_nr, s:tail_name(old_fname), s:tail_name(new_link),old_fname) + call s:update_wiki_links(wiki_nr, old_dir, s:tail_name(old_fname), s:tail_name(new_fname)) " restore wiki buffers for bitem in blist @@ -1375,17 +1577,21 @@ function! vimwiki#base#rename_link() endfunction -function! vimwiki#base#ui_select() +function! vimwiki#base#ui_select() abort call s:print_wiki_list() - let idx = input("Select Wiki (specify number): ") - if idx == "" + let idx = input('Select Wiki by number and press (empty cancels): ') + if idx ==# '' + return + elseif idx !~# '\m[0-9]\+' + echo "\n" + echom 'Invalid wiki selection.' return endif call vimwiki#base#goto_index(idx) endfunction -function! vimwiki#base#TO_header(inner, including_subheaders, count) +function! vimwiki#base#TO_header(inner, including_subheaders, count) abort let headers = s:collect_headers() if empty(headers) return @@ -1438,7 +1644,7 @@ function! vimwiki#base#TO_header(inner, including_subheaders, count) endfunction -function! vimwiki#base#TO_table_cell(inner, visual) +function! vimwiki#base#TO_table_cell(inner, visual) abort if col('.') == col('$')-1 return endif @@ -1455,7 +1661,7 @@ function! vimwiki#base#TO_table_cell(inner, visual) if !search('|\|\(-+-\)', 'cb', line('.')) return endif - if getline('.')[virtcol('.')] == '+' + if getline('.')[virtcol('.')] ==# '+' normal! l endif if a:inner @@ -1466,7 +1672,7 @@ function! vimwiki#base#TO_table_cell(inner, visual) normal! `> call search('|\|\(-+-\)', '', line('.')) - if getline('.')[virtcol('.')] == '+' + if getline('.')[virtcol('.')] ==# '+' normal! l endif if a:inner @@ -1494,7 +1700,7 @@ function! vimwiki#base#TO_table_cell(inner, visual) endif normal! v call search('|\|\(-+-\)', '', line('.')) - if !a:inner && getline('.')[virtcol('.')-1] == '|' + if !a:inner && getline('.')[virtcol('.')-1] ==# '|' normal! h elseif a:inner normal! 2h @@ -1503,7 +1709,7 @@ function! vimwiki#base#TO_table_cell(inner, visual) endfunction -function! vimwiki#base#TO_table_col(inner, visual) +function! vimwiki#base#TO_table_col(inner, visual) abort let t_rows = vimwiki#tbl#get_rows(line('.')) if empty(t_rows) return @@ -1537,7 +1743,7 @@ function! vimwiki#base#TO_table_col(inner, visual) return endif " -+- column separator is matched --> move cursor to the + sign - if getline('.')[virtcol('.')] == '+' + if getline('.')[virtcol('.')] ==# '+' normal! l endif " inner selection --> reduce selection @@ -1548,7 +1754,7 @@ function! vimwiki#base#TO_table_col(inner, visual) endif normal! `> - if !firsttime && getline('.')[virtcol('.')] == '|' + if !firsttime && getline('.')[virtcol('.')] ==# '|' normal! l elseif a:inner && getline('.')[virtcol('.')+1] =~# '[|+]' normal! 2l @@ -1557,7 +1763,7 @@ function! vimwiki#base#TO_table_col(inner, visual) call search('|\|\(-+-\)', '', line('.')) " Outer selection selects a column without border on the right. So we move " our cursor left if the previous search finds | border, not -+-. - if getline('.')[virtcol('.')] != '+' + if getline('.')[virtcol('.')] !=# '+' normal! h endif if a:inner @@ -1591,7 +1797,7 @@ function! vimwiki#base#TO_table_col(inner, visual) return endif " -+- column separator is matched --> move cursor to the + sign - if getline('.')[virtcol('.')] == '+' + if getline('.')[virtcol('.')] ==# '+' normal! l endif " inner selection --> reduce selection @@ -1605,7 +1811,7 @@ function! vimwiki#base#TO_table_col(inner, visual) call search('|\|\(-+-\)', '', line('.')) " Outer selection selects a column without border on the right. So we move " our cursor left if the previous search finds | border, not -+-. - if getline('.')[virtcol('.')] != '+' + if getline('.')[virtcol('.')] !=# '+' normal! h endif " reduce selection a bit more if inner. @@ -1618,7 +1824,10 @@ function! vimwiki#base#TO_table_col(inner, visual) endfunction -function! vimwiki#base#AddHeaderLevel() +function! vimwiki#base#AddHeaderLevel(...) abort + if a:1 > 1 + call vimwiki#base#AddHeaderLevel(a:1 - 1) + endif let lnum = line('.') let line = getline(lnum) let rxHdr = vimwiki#vars#get_syntaxlocal('rxH') @@ -1646,7 +1855,10 @@ function! vimwiki#base#AddHeaderLevel() endfunction -function! vimwiki#base#RemoveHeaderLevel() +function! vimwiki#base#RemoveHeaderLevel(...) abort + if a:1 > 1 + call vimwiki#base#RemoveHeaderLevel(a:1 - 1) + endif let lnum = line('.') let line = getline(lnum) let rxHdr = vimwiki#vars#get_syntaxlocal('rxH') @@ -1682,7 +1894,7 @@ endfunction " Returns all the headers in the current buffer as a list of the form " [[line_number, header_level, header_text], [...], [...], ...] -function! s:collect_headers() +function! s:collect_headers() abort let is_inside_pre_or_math = 0 " 1: inside pre, 2: inside math, 0: outside let headers = [] for lnum in range(1, line('$')) @@ -1706,6 +1918,11 @@ function! s:collect_headers() if line_content !~# vimwiki#vars#get_syntaxlocal('rxHeader') continue endif + if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown' + if stridx(line_content, vimwiki#vars#get_syntaxlocal('rxH')) > 0 + continue " markdown headers must start in the first column + endif + endif let header_level = vimwiki#u#count_first_sym(line_content) let header_text = \ vimwiki#u#trim(matchstr(line_content, vimwiki#vars#get_syntaxlocal('rxHeader'))) @@ -1716,7 +1933,7 @@ function! s:collect_headers() endfunction -function! s:current_header(headers, line_number) +function! s:current_header(headers, line_number) abort if empty(a:headers) return -1 endif @@ -1733,7 +1950,7 @@ function! s:current_header(headers, line_number) endfunction -function! s:get_another_header(headers, current_index, direction, operation) +function! s:get_another_header(headers, current_index, direction, operation) abort if empty(a:headers) || a:current_index < 0 return -1 endif @@ -1752,7 +1969,7 @@ function! s:get_another_header(headers, current_index, direction, operation) endfunction -function! vimwiki#base#goto_parent_header() +function! vimwiki#base#goto_parent_header() abort let headers = s:collect_headers() let current_header_index = s:current_header(headers, line('.')) let parent_header = s:get_another_header(headers, current_header_index, -1, '<') @@ -1764,7 +1981,7 @@ function! vimwiki#base#goto_parent_header() endfunction -function! vimwiki#base#goto_next_header() +function! vimwiki#base#goto_next_header() abort let headers = s:collect_headers() let current_header_index = s:current_header(headers, line('.')) if current_header_index >= 0 && current_header_index < len(headers) - 1 @@ -1777,7 +1994,7 @@ function! vimwiki#base#goto_next_header() endfunction -function! vimwiki#base#goto_prev_header() +function! vimwiki#base#goto_prev_header() abort let headers = s:collect_headers() let current_header_index = s:current_header(headers, line('.')) " if the cursor already was on a header, jump to the previous one @@ -1792,7 +2009,7 @@ function! vimwiki#base#goto_prev_header() endfunction -function! vimwiki#base#goto_sibling(direction) +function! vimwiki#base#goto_sibling(direction) abort let headers = s:collect_headers() let current_header_index = s:current_header(headers, line('.')) let next_potential_sibling = @@ -1808,7 +2025,7 @@ endfunction " a:create == 1: creates or updates TOC in current file " a:create == 0: update if TOC exists -function! vimwiki#base#table_of_contents(create) +function! vimwiki#base#table_of_contents(create) abort let headers = s:collect_headers() let toc_header_text = vimwiki#vars#get_global('toc_header') @@ -1828,54 +2045,66 @@ function! vimwiki#base#table_of_contents(create) endif endif - let numbering = vimwiki#vars#get_global('html_header_numbering') - let headers_levels = [['', 0], ['', 0], ['', 0], ['', 0], ['', 0], ['', 0]] - let complete_header_infos = [] - for header in headers - let h_text = header[2] - let h_level = header[1] - if h_text ==# toc_header_text " don't include the TOC's header itself - continue - endif - let headers_levels[h_level-1] = [h_text, headers_levels[h_level-1][1]+1] - for idx in range(h_level, 5) | let headers_levels[idx] = ['', 0] | endfor - - let h_complete_id = '' - for l in range(h_level-1) - if headers_levels[l][0] != '' - let h_complete_id .= headers_levels[l][0].'#' + " use a dictionary function for closure like capability + " copy all local variables into dict (add a: if arguments are needed) + let GeneratorTOC = copy(l:) + function! GeneratorTOC.f() abort + let numbering = vimwiki#vars#get_global('html_header_numbering') + let headers_levels = [['', 0], ['', 0], ['', 0], ['', 0], ['', 0], ['', 0]] + let complete_header_infos = [] + for header in self.headers + let h_text = header[2] + let h_level = header[1] + " don't include the TOC's header itself + if h_text ==# self.toc_header_text + continue endif + let headers_levels[h_level-1] = [h_text, headers_levels[h_level-1][1]+1] + for idx in range(h_level, 5) | let headers_levels[idx] = ['', 0] | endfor + + let h_complete_id = '' + if vimwiki#vars#get_global('toc_link_format') == 0 + for l in range(h_level-1) + if headers_levels[l][0] !=? '' + let h_complete_id .= headers_levels[l][0].'#' + endif + endfor + endif + let h_complete_id .= headers_levels[h_level-1][0] + + call add(complete_header_infos, [h_level, h_complete_id, h_text]) endfor - let h_complete_id .= headers_levels[h_level-1][0] - if numbering > 0 && numbering <= h_level - let h_number = join(map(copy(headers_levels[numbering-1 : h_level-1]), 'v:val[1]'), '.') - let h_number .= vimwiki#vars#get_global('html_header_numbering_sym') - let h_text = h_number.' '.h_text - endif + let lines = [] + let startindent = repeat(' ', vimwiki#lst#get_list_margin()) + let indentstring = repeat(' ', vimwiki#u#sw()) + let bullet = vimwiki#lst#default_symbol().' ' + for [lvl, link, desc] in complete_header_infos + if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown' + let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink2Template') + elseif vimwiki#vars#get_global('toc_link_format') == 0 + let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate2') + else + let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate1') + endif + let link = s:safesubstitute(link_tpl, '__LinkUrl__', + \ '#'.link, '') + let link = s:safesubstitute(link, '__LinkDescription__', desc, '') + call add(lines, startindent.repeat(indentstring, lvl-1).bullet.link) + endfor - call add(complete_header_infos, [h_level, h_complete_id, h_text]) - endfor + return lines + endfunction - let lines = [] - let startindent = repeat(' ', vimwiki#lst#get_list_margin()) - let indentstring = repeat(' ', vimwiki#u#sw()) - let bullet = vimwiki#lst#default_symbol().' ' - for [lvl, link, desc] in complete_header_infos - if vimwiki#vars#get_wikilocal('syntax') == 'markdown' - let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink1Template') - else - let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate2') - endif - let link = s:safesubstitute(link_tpl, '__LinkUrl__', - \ '#'.link, '') - let link = s:safesubstitute(link, '__LinkDescription__', desc, '') - call add(lines, startindent.repeat(indentstring, lvl-1).bullet.link) - endfor + let links_rx = '\%(^\s*$\)\|\%('.vimwiki#vars#get_syntaxlocal('rxListBullet').'\)' - let links_rx = '\m^\s*'.vimwiki#u#escape(vimwiki#lst#default_symbol()).' ' - - call vimwiki#base#update_listing_in_buffer(lines, toc_header_text, links_rx, 1, a:create) + call vimwiki#base#update_listing_in_buffer( + \ GeneratorTOC, + \ toc_header_text, + \ links_rx, + \ 1, + \ vimwiki#vars#get_global('toc_header_level'), + \ a:create) endfunction @@ -1884,54 +2113,72 @@ endfunction " for __LinkDescription__, and rxStyle for __LinkStyle__. The three " arguments rxUrl, rxDesc, and rxStyle are copied verbatim, without any " special character escapes or substitutions. -function! vimwiki#base#apply_template(template, rxUrl, rxDesc, rxStyle) +function! vimwiki#base#apply_template(template, rxUrl, rxDesc, rxStyle) abort let lnk = a:template - if a:rxUrl != "" + if a:rxUrl !=? '' let lnk = s:safesubstitute(lnk, '__LinkUrl__', a:rxUrl, 'g') endif - if a:rxDesc != "" + if a:rxDesc !=? '' let lnk = s:safesubstitute(lnk, '__LinkDescription__', a:rxDesc, 'g') endif - if a:rxStyle != "" + if a:rxStyle !=? '' let lnk = s:safesubstitute(lnk, '__LinkStyle__', a:rxStyle, 'g') endif return lnk endfunction -function! s:clean_url(url) +function! s:clean_url(url) abort + " don't use an extension as part of the description + let url = substitute(a:url, '\'.vimwiki#vars#get_wikilocal('ext').'$', '', '') " remove protocol and tld - let url = substitute(a:url, '^\a\+\d*:', '', '') + let url = substitute(url, '^\a\+\d*:', '', '') + " remove absolute path prefix let url = substitute(url, '^//', '', '') let url = substitute(url, '^\([^/]\+\)\.\a\{2,4}/', '\1/', '') - let url = split(url, '/\|=\|-\|&\|?\|\.') - let url = filter(url, 'v:val !=# ""') - if url[0] == "www" - let url = url[1:] + let url_l = split(url, '/\|=\|-\|&\|?\|\.') + " case only a '-' + if url_l == [] + return '' endif - if url[-1] =~ '^\(htm\|html\|php\)$' - let url = url[0:-2] + let url_l = filter(url_l, 'v:val !=# ""') + if url_l[0] ==# 'www' + let url_l = url_l[1:] endif - " remove words consisting of only hexadecimal digits or non-word characters - let url = filter(url, 'v:val !~ "^\\A\\{4,}$"') - let url = filter(url, 'v:val !~ "^\\x\\{4,}$" || v:val !~ "\\d"') - return join(url, " ") + if url_l[-1] =~# '^\(htm\|html\|php\)$' + let url_l = url_l[0:-2] + endif + " remove words with black listed codepoints + " TODO mutualize blacklist in a variable + let url_l = filter(url_l, 'v:val !~? "[!\"$%&''()*+,:;<=>?\[\]\\^`{}]"') + " remove words consisting of only hexadecimal digits + let url_l = filter(url_l, 'v:val !~? "^\\x\\{4,}$" || v:val !~? "\\d"') + return join(url_l, ' ') +endfunction + +" An optional second argument allows you to pass in a list of diary files rather +" than generating a list on each call to the function. +function! vimwiki#base#is_diary_file(filename, ...) abort + let l:diary_file_paths = a:0 > 0 ? a:1 : vimwiki#diary#get_diary_files() + let l:normalised_file_paths = + \ map(l:diary_file_paths, 'vimwiki#path#normalize(v:val)') + let l:matching_files = + \ filter(l:normalised_file_paths, 'v:val =~# a:filename') + return len(l:matching_files) > 0 " filename is a diary file if match is found endfunction -function! s:is_diary_file(filename) - let file_path = vimwiki#path#path_norm(a:filename) - let rel_path = vimwiki#vars#get_wikilocal('diary_rel_path') - let diary_path = vimwiki#path#path_norm(vimwiki#vars#get_wikilocal('path') . rel_path) - return rel_path != '' && file_path =~# '^'.vimwiki#u#escape(diary_path) -endfunction - - -function! vimwiki#base#normalize_link_helper(str, rxUrl, rxDesc, template) +function! vimwiki#base#normalize_link_helper(str, rxUrl, rxDesc, template) abort let url = matchstr(a:str, a:rxUrl) + if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown' && vimwiki#vars#get_global('markdown_link_ext') + " strip the extension if it exists so it doesn't get added multiple times + let url = substitute(url, '\'.vimwiki#vars#get_wikilocal('ext').'$', '', '') + endif let descr = matchstr(a:str, a:rxDesc) - if descr == "" + " Try to clean, do not work if bad link + if descr ==# '' let descr = s:clean_url(url) + if descr ==# '' | return url | endif endif let lnk = s:safesubstitute(a:template, '__LinkDescription__', descr, '') let lnk = s:safesubstitute(lnk, '__LinkUrl__', url, '') @@ -1939,33 +2186,33 @@ function! vimwiki#base#normalize_link_helper(str, rxUrl, rxDesc, template) endfunction -function! vimwiki#base#normalize_imagelink_helper(str, rxUrl, rxDesc, rxStyle, template) +function! vimwiki#base#normalize_imagelink_helper(str, rxUrl, rxDesc, rxStyle, template) abort let lnk = vimwiki#base#normalize_link_helper(a:str, a:rxUrl, a:rxDesc, a:template) let style = matchstr(a:str, a:rxStyle) let lnk = s:safesubstitute(lnk, '__LinkStyle__', style, '') return lnk endfunction - -function! s:normalize_link_in_diary(lnk) +function! vimwiki#base#normalize_link_in_diary(lnk) abort + let sc = vimwiki#vars#get_wikilocal('links_space_char') let link = a:lnk . vimwiki#vars#get_wikilocal('ext') - let link_wiki = vimwiki#vars#get_wikilocal('path') . '/' . link - let link_diary = vimwiki#vars#get_wikilocal('path') . '/' - \ . vimwiki#vars#get_wikilocal('diary_rel_path') . '/' . link + let link_wiki = substitute(vimwiki#vars#get_wikilocal('path') . '/' . link, '\s', sc, 'g') + let link_diary = substitute(vimwiki#vars#get_wikilocal('path') . '/' + \ . vimwiki#vars#get_wikilocal('diary_rel_path') . '/' . link, '\s', sc, 'g') let link_exists_in_diary = filereadable(link_diary) let link_exists_in_wiki = filereadable(link_wiki) let link_is_date = a:lnk =~# '\d\d\d\d-\d\d-\d\d' - if link_exists_in_diary || link_is_date + if link_is_date let str = a:lnk let rxUrl = vimwiki#vars#get_global('rxWord') - let rxDesc = '' + let rxDesc = '\d\d\d\d-\d\d-\d\d' let template = vimwiki#vars#get_global('WikiLinkTemplate1') elseif link_exists_in_wiki let depth = len(split(vimwiki#vars#get_wikilocal('diary_rel_path'), '/')) - let str = repeat('../', depth) . a:lnk . '|' . a:lnk - let rxUrl = '^.*\ze|' - let rxDesc = '|\zs.*$' + let str = repeat('../', depth) . a:lnk + let rxUrl = '.*' + let rxDesc = '[^/]*$' let template = vimwiki#vars#get_global('WikiLinkTemplate2') else let str = a:lnk @@ -1974,11 +2221,15 @@ function! s:normalize_link_in_diary(lnk) let template = vimwiki#vars#get_global('WikiLinkTemplate1') endif + if vimwiki#vars#get_wikilocal('syntax') ==? 'markdown' + let template = vimwiki#vars#get_syntaxlocal('Weblink1Template') + endif + return vimwiki#base#normalize_link_helper(str, rxUrl, rxDesc, template) endfunction -function! s:normalize_link_syntax_n() +function! s:normalize_link_syntax_n() abort " try WikiLink let lnk = vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_syntaxlocal('rxWikiLink')) @@ -2012,8 +2263,8 @@ function! s:normalize_link_syntax_n() " normalize_link_syntax_v let lnk = vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_global('rxWord')) if !empty(lnk) - if s:is_diary_file(expand("%:p")) - let sub = s:normalize_link_in_diary(lnk) + if vimwiki#base#is_diary_file(expand('%:p')) + let sub = vimwiki#base#normalize_link_in_diary(lnk) else let sub = s:safesubstitute( \ vimwiki#vars#get_global('WikiLinkTemplate1'), '__LinkUrl__', lnk, '') @@ -2025,9 +2276,9 @@ function! s:normalize_link_syntax_n() endfunction -function! s:normalize_link_syntax_v() +function! s:normalize_link_syntax_v() abort let sel_save = &selection - let &selection = "old" + let &selection = 'old' let default_register_save = @" let registertype_save = getregtype('"') @@ -2036,15 +2287,16 @@ function! s:normalize_link_syntax_v() normal! gv""y " Set substitution - if s:is_diary_file(expand("%:p")) - let sub = s:normalize_link_in_diary(@") + if vimwiki#base#is_diary_file(expand('%:p')) + let sub = vimwiki#base#normalize_link_in_diary(@") else let sub = s:safesubstitute(vimwiki#vars#get_global('WikiLinkTemplate1'), \ '__LinkUrl__', @", '') endif " Put substitution in register " and change text - call setreg('"', substitute(sub, '\n', '', ''), visualmode()) + let sc = vimwiki#vars#get_wikilocal('links_space_char') + call setreg('"', substitute(substitute(sub, '\n', '', ''), '\s', sc, 'g'), visualmode()) normal! `>""pgvd finally call setreg('"', default_register_save, registertype_save) @@ -2053,7 +2305,7 @@ function! s:normalize_link_syntax_v() endfunction -function! vimwiki#base#normalize_link(is_visual_mode) +function! vimwiki#base#normalize_link(is_visual_mode) abort if exists('*vimwiki#'.vimwiki#vars#get_wikilocal('syntax').'_base#normalize_link') " Syntax-specific links call vimwiki#{vimwiki#vars#get_wikilocal('syntax')}_base#normalize_link(a:is_visual_mode) @@ -2068,9 +2320,9 @@ function! vimwiki#base#normalize_link(is_visual_mode) endfunction -function! vimwiki#base#detect_nested_syntax() +function! vimwiki#base#detect_nested_syntax() abort let last_word = '\v.*<(\w+)\s*$' - let lines = map(filter(getline(1, "$"), 'v:val =~ "\\%({{{\\|```\\)" && v:val =~ last_word'), + let lines = map(filter(getline(1, '$'), 'v:val =~# "\\%({{{\\|`\\{3,\}\\|\\~\\{3,\}\\)" && v:val =~# last_word'), \ 'substitute(v:val, last_word, "\\=submatch(1)", "")') let dict = {} for elem in lines @@ -2080,13 +2332,60 @@ function! vimwiki#base#detect_nested_syntax() endfunction -function! vimwiki#base#complete_links_escaped(ArgLead, CmdLine, CursorPos) abort - " We can safely ignore args if we use -custom=complete option, Vim engine - " will do the job of filtering. - return vimwiki#base#get_globlinks_escaped() +function! vimwiki#base#complete_links_escaped(ArgLead, CmdLine, CursorPos) abort abort + return vimwiki#base#get_globlinks_escaped(a:ArgLead) endfunction +function! vimwiki#base#read_caption(file) abort + let rx_header = vimwiki#vars#get_syntaxlocal('rxHeader') + + if filereadable(a:file) + for line in readfile(a:file, '', g:vimwiki_max_scan_for_caption) + if line =~# rx_header + return vimwiki#u#trim(matchstr(line, rx_header)) + endif + endfor + endif + + return '' +endfunction + + +" For commands VimwikiSearch and VWS +function! vimwiki#base#search(search_pattern) abort + if empty(a:search_pattern) + echomsg 'Vimwiki Error: No search pattern given.' + return + endif + + let pattern = a:search_pattern + + " If the pattern does not start with a '/', then we'll assume that a + " literal search is intended and enclose and escape it: + if match(pattern, '^/') == -1 + let pattern = '/'.escape(pattern, '\').'/' + endif + + let path = fnameescape(vimwiki#vars#get_wikilocal('path')) + let ext = vimwiki#vars#get_wikilocal('ext') + let cmd = 'lvimgrep '.pattern.' '.path.'**/*'.ext + + " Catch E480 error from lvimgrep if there's no match and present + " a friendlier error message. + try + execute cmd + catch + echomsg 'VimwikiSearch: No match found.' + endtry +endfunction + +function! vimwiki#base#deprecate(old, new) abort + echohl WarningMsg + echo a:old 'is deprecated and will be removed in future versions, use' a:new 'instead.' + echohl None +endfunction + " ------------------------------------------------------------------------- " Load syntax-specific Wiki functionality for s:syn in s:vimwiki_get_known_syntaxes() diff --git a/autoload/vimwiki/customwiki2html.sh b/autoload/vimwiki/customwiki2html.sh index 6b0c17a..4818d02 100755 --- a/autoload/vimwiki/customwiki2html.sh +++ b/autoload/vimwiki/customwiki2html.sh @@ -2,7 +2,7 @@ # # This script converts markdown into html, to be used with vimwiki's -# "customwiki2html" option. Experiment with the two proposed methods by +# "customwiki2html" option. Experiment with the two proposed methods by # commenting / uncommenting the relevant lines below. # # NEW! An alternative converter was developed by Jason6Anderson, and can @@ -46,7 +46,7 @@ OUTPUT="$OUTPUTDIR"/$(basename "$INPUT" .$EXTENSION).html # # Method 1: # # markdown [-d] [-T] [-V] [-b url-base] [-C prefix] [-F bitmap] [-f flags] [-o file] [-s text] [-t text] [textfile] -# +# # URLBASE=http://example.com # $MARKDOWN -T -b $URLBASE -o $OUTPUT $INPUT diff --git a/autoload/vimwiki/default.tpl b/autoload/vimwiki/default.tpl index 3a4045f..35371d5 100644 --- a/autoload/vimwiki/default.tpl +++ b/autoload/vimwiki/default.tpl @@ -4,6 +4,7 @@ %title% + %content% diff --git a/autoload/vimwiki/diary.vim b/autoload/vimwiki/diary.vim index 37f6d5c..46d14ce 100644 --- a/autoload/vimwiki/diary.vim +++ b/autoload/vimwiki/diary.vim @@ -4,16 +4,13 @@ " Home: https://github.com/vimwiki/vimwiki/ -if exists("g:loaded_vimwiki_diary_auto") || &cp +if exists('g:loaded_vimwiki_diary_auto') || &compatible finish endif let g:loaded_vimwiki_diary_auto = 1 -let s:vimwiki_max_scan_for_caption = 5 - - -function! s:prefix_zero(num) +function! s:prefix_zero(num) abort if a:num < 10 return '0'.a:num endif @@ -21,20 +18,20 @@ function! s:prefix_zero(num) endfunction -function! s:diary_path(...) +function! s:diary_path(...) abort let idx = a:0 == 0 ? vimwiki#vars#get_bufferlocal('wiki_nr') : a:1 return vimwiki#vars#get_wikilocal('path', idx).vimwiki#vars#get_wikilocal('diary_rel_path', idx) endfunction -function! s:diary_index(...) +function! s:diary_index(...) abort let idx = a:0 == 0 ? vimwiki#vars#get_bufferlocal('wiki_nr') : a:1 return s:diary_path(idx).vimwiki#vars#get_wikilocal('diary_index', idx). \ vimwiki#vars#get_wikilocal('ext', idx) endfunction -function! vimwiki#diary#diary_date_link(...) +function! vimwiki#diary#diary_date_link(...) abort if a:0 return strftime('%Y-%m-%d', a:1) else @@ -43,11 +40,11 @@ function! vimwiki#diary#diary_date_link(...) endfunction -function! s:get_position_links(link) +function! s:get_position_links(link) abort let idx = -1 let links = [] if a:link =~# '^\d\{4}-\d\d-\d\d' - let links = map(s:get_diary_files(), 'fnamemodify(v:val, ":t:r")') + let links = map(vimwiki#diary#get_diary_files(), 'fnamemodify(v:val, ":t:r")') " include 'today' into links if index(links, vimwiki#diary#diary_date_link()) == -1 call add(links, vimwiki#diary#diary_date_link()) @@ -59,36 +56,108 @@ function! s:get_position_links(link) endfunction -function! s:get_month_name(month) +function! s:get_month_name(month) abort return vimwiki#vars#get_global('diary_months')[str2nr(a:month)] endfunction +function! s:get_first_header(fl) abort + " Get the first header in the file within the first s:vimwiki_max_scan_for_caption lines. + let header_rx = vimwiki#vars#get_syntaxlocal('rxHeader') -function! s:read_captions(files) + for line in readfile(a:fl, '', g:vimwiki_max_scan_for_caption) + if line =~# header_rx + return vimwiki#u#trim(matchstr(line, header_rx)) + endif + endfor + return '' +endfunction + +function! s:get_all_headers(fl, maxlevel) abort + " Get a list of all headers in a file up to a given level. + " Returns a list whose elements are pairs [level, title] + let headers_rx = {} + for i in range(1, a:maxlevel) + let headers_rx[i] = vimwiki#vars#get_syntaxlocal('rxH'.i.'_Text') + endfor + + let headers = [] + for line in readfile(a:fl, '') + for [i, header_rx] in items(headers_rx) + if line =~# header_rx + call add(headers, [i, vimwiki#u#trim(matchstr(line, header_rx))]) + break + endif + endfor + endfor + return headers +endfunction + +function! s:count_headers_level_less_equal(headers, maxlevel) abort + " Count headers with level <= maxlevel in a list of [level, title] pairs. + let l:count = 0 + for [header_level, _] in a:headers + if header_level <= a:maxlevel + let l:count += 1 + endif + endfor + return l:count +endfunction + +function! s:get_min_header_level(headers) abort + " The minimum level of any header in a list of [level, title] pairs. + if len(a:headers) == 0 + return 0 + endif + let minlevel = a:headers[0][0] + for [level, _] in a:headers + let minlevel = min([minlevel, level]) + endfor + return minlevel +endfunction + + +function! s:read_captions(files) abort let result = {} - let rx_header = vimwiki#vars#get_syntaxlocal('rxHeader') + let caption_level = vimwiki#vars#get_wikilocal('diary_caption_level') + for fl in a:files " remove paths and extensions - let fl_key = substitute(fnamemodify(fl, ':t'), vimwiki#vars#get_wikilocal('ext').'$', '', '') + let fl_captions = {} - if filereadable(fl) - for line in readfile(fl, '', s:vimwiki_max_scan_for_caption) - if line =~# rx_header && !has_key(result, fl_key) - let result[fl_key] = vimwiki#u#trim(matchstr(line, rx_header)) + " Default; no captions from the file. + let fl_captions['top'] = '' + let fl_captions['rest'] = [] + + if caption_level >= 0 && filereadable(fl) + if caption_level == 0 + " Take first header of any level as the top caption. + let fl_captions['top'] = s:get_first_header(fl) + else + let headers = s:get_all_headers(fl, caption_level) + if len(headers) > 0 + " If first header is the only one at its level or less, then make it the top caption. + let [first_level, first_header] = headers[0] + if s:count_headers_level_less_equal(headers, first_level) == 1 + let fl_captions['top'] = first_header + call remove(headers, 0) + endif + + let min_header_level = s:get_min_header_level(headers) + for [level, header] in headers + call add(fl_captions['rest'], [level - min_header_level, header]) + endfor endif - endfor - endif - - if !has_key(result, fl_key) - let result[fl_key] = '' + endif endif + let fl_key = substitute(fnamemodify(fl, ':t'), vimwiki#vars#get_wikilocal('ext').'$', '', '') + let result[fl_key] = fl_captions endfor return result endfunction -function! s:get_diary_files() +function! vimwiki#diary#get_diary_files() abort 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')) @@ -102,7 +171,7 @@ function! s:get_diary_files() endfunction -function! s:group_links(links) +function! s:group_links(links) abort let result = {} let p_year = 0 let p_month = 0 @@ -124,7 +193,7 @@ function! s:group_links(links) endfunction -function! s:sort(lst) +function! s:sort(lst) abort if vimwiki#vars#get_wikilocal('diary_sort') ==? 'desc' return reverse(sort(a:lst)) else @@ -132,52 +201,10 @@ function! s:sort(lst) endif endfunction - -function! s:format_diary() - let result = [] - - let links_with_captions = s:read_captions(s:get_diary_files()) - let g_files = s:group_links(links_with_captions) - - for year in s:sort(keys(g_files)) - call add(result, '') - call add(result, - \ substitute(vimwiki#vars#get_syntaxlocal('rxH2_Template'), '__Header__', year , '')) - - for month in s:sort(keys(g_files[year])) - call add(result, '') - call add(result, substitute(vimwiki#vars#get_syntaxlocal('rxH3_Template'), - \ '__Header__', s:get_month_name(month), '')) - - for [fl, cap] in s:sort(items(g_files[year][month])) - let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate2') - - if vimwiki#vars#get_wikilocal('syntax') == 'markdown' - let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink1Template') - - if empty(cap) " When using markdown syntax, we should ensure we always have a link description. - let cap = fl - endif - elseif empty(cap) - let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate1') - endif - - let entry = substitute(link_tpl, '__LinkUrl__', fl, '') - let entry = substitute(entry, '__LinkDescription__', cap, '') - call add(result, repeat(' ', vimwiki#lst#get_list_margin()).'* '.entry) - endfor - - endfor - endfor - - return result -endfunction - - " The given wiki number a:wnum is 1 for the first wiki, 2 for the second and so on. This is in " contrast to most other places, where counting starts with 0. When a:wnum is 0, the current wiki " is used. -function! vimwiki#diary#make_note(wnum, ...) +function! vimwiki#diary#make_note(wnum, ...) abort if a:wnum == 0 let wiki_nr = vimwiki#vars#get_bufferlocal('wiki_nr') if wiki_nr < 0 " this happens when e.g. VimwikiMakeDiaryNote was called outside a wiki buffer @@ -192,8 +219,6 @@ function! vimwiki#diary#make_note(wnum, ...) return endif - " TODO: refactor it. base#goto_index uses the same - call vimwiki#path#mkdir(vimwiki#vars#get_wikilocal('path', wiki_nr). \ vimwiki#vars#get_wikilocal('diary_rel_path', wiki_nr)) @@ -216,20 +241,23 @@ function! vimwiki#diary#make_note(wnum, ...) call vimwiki#base#open_link(cmd, link, s:diary_index(wiki_nr)) endfunction +function! vimwiki#diary#goto_diary_index(wnum) abort + + " if wnum = 0 the current wiki is used + if a:wnum == 0 + let idx = vimwiki#vars#get_bufferlocal('wiki_nr') + if idx < 0 " not in a wiki + let idx = 0 + endif + else + let idx = a:wnum - 1 " convert to 0 based counting + endif -function! vimwiki#diary#goto_diary_index(wnum) if a:wnum > vimwiki#vars#number_of_wikis() echomsg 'Vimwiki Error: Wiki '.a:wnum.' is not registered in g:vimwiki_list!' return endif - " TODO: refactor it. base#goto_index uses the same - if a:wnum > 0 - let idx = a:wnum - 1 - else - let idx = 0 - endif - call vimwiki#base#edit_file('e', s:diary_index(idx), '') if vimwiki#vars#get_wikilocal('auto_diary_index') @@ -239,7 +267,7 @@ function! vimwiki#diary#goto_diary_index(wnum) endfunction -function! vimwiki#diary#goto_next_day() +function! vimwiki#diary#goto_next_day() abort let link = '' let [idx, links] = s:get_position_links(expand('%:t:r')) @@ -260,7 +288,7 @@ function! vimwiki#diary#goto_next_day() endfunction -function! vimwiki#diary#goto_prev_day() +function! vimwiki#diary#goto_prev_day() abort let link = '' let [idx, links] = s:get_position_links(expand('%:t:r')) @@ -281,13 +309,95 @@ function! vimwiki#diary#goto_prev_day() endfunction -function! vimwiki#diary#generate_diary_section() - let current_file = vimwiki#path#path_norm(expand("%:p")) +function! vimwiki#diary#generate_diary_section() abort + + let GeneratorDiary = copy(l:) + function! GeneratorDiary.f() abort + let lines = [] + + let links_with_captions = s:read_captions(vimwiki#diary#get_diary_files()) + let g_files = s:group_links(links_with_captions) + let g_keys = s:sort(keys(g_files)) + + for year in g_keys + if len(lines) > 0 + call add(lines, '') + endif + + call add(lines, substitute(vimwiki#vars#get_syntaxlocal('rxH2_Template'), '__Header__', year , '')) + + for month in s:sort(keys(g_files[year])) + call add(lines, '') + call add(lines, substitute(vimwiki#vars#get_syntaxlocal('rxH3_Template'), + \ '__Header__', s:get_month_name(month), '')) + + if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown' + for _ in range(vimwiki#vars#get_global('markdown_header_style')) + call add(lines, '') + endfor + endif + + for [fl, captions] in s:sort(items(g_files[year][month])) + let topcap = captions['top'] + let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate2') + + if vimwiki#vars#get_wikilocal('syntax') ==# 'markdown' + let link_tpl = vimwiki#vars#get_syntaxlocal('Weblink1Template') + + if empty(topcap) " When using markdown syntax, we should ensure we always have a link description. + let topcap = fl + endif + endif + + if empty(topcap) + let top_link_tpl = vimwiki#vars#get_global('WikiLinkTemplate1') + else + let top_link_tpl = link_tpl + endif + + let bullet = vimwiki#lst#default_symbol().' ' + let entry = substitute(top_link_tpl, '__LinkUrl__', fl, '') + let entry = substitute(entry, '__LinkDescription__', topcap, '') + " If single H1 then that will be used as the description for the link to the file + " if multple H1 then the filename will be used as the description for the link to the + " file and multiple H1 headers will be indented by shiftwidth + call add(lines, repeat(' ', vimwiki#lst#get_list_margin()).bullet.entry) + + let startindent = repeat(' ', vimwiki#lst#get_list_margin()) + let indentstring = repeat(' ', vimwiki#u#sw()) + + for [depth, subcap] in captions['rest'] + if empty(subcap) + continue + endif + let entry = substitute(link_tpl, '__LinkUrl__', fl.'#'.subcap, '') + let entry = substitute(entry, '__LinkDescription__', subcap, '') + " if single H1 then depth H2=0, H3=1, H4=2, H5=3, H6=4 + " if multiple H1 then depth H1= 0, H2=1, H3=2, H4=3, H5=4, H6=5 + " indent subsequent headers levels by shiftwidth + call add(lines, startindent.repeat(indentstring, depth+1).bullet.entry) + endfor + endfor + + endfor + endfor + + return lines + endfunction + + let current_file = vimwiki#path#path_norm(expand('%:p')) let diary_file = vimwiki#path#path_norm(s:diary_index()) if vimwiki#path#is_equal(current_file, diary_file) - let content_rx = '^\%(\s*\* \)\|\%(^\s*$\)\|\%('.vimwiki#vars#get_syntaxlocal('rxHeader').'\)' - call vimwiki#base#update_listing_in_buffer(s:format_diary(), - \ vimwiki#vars#get_wikilocal('diary_header'), content_rx, line('$')+1, 1) + let content_rx = '^\%('.vimwiki#vars#get_syntaxlocal('rxHeader').'\)\|'. + \ '\%(^\s*$\)\|\%('.vimwiki#vars#get_syntaxlocal('rxListBullet').'\)' + + call vimwiki#base#update_listing_in_buffer( + \ GeneratorDiary, + \ vimwiki#vars#get_wikilocal('diary_header'), + \ content_rx, + \ 1, + \ 1, + \ 1) else echomsg 'Vimwiki Error: You can generate diary links only in a diary index page!' endif @@ -295,7 +405,7 @@ endfunction " Callback function for Calendar.vim -function! vimwiki#diary#calendar_action(day, month, year, week, dir) +function! vimwiki#diary#calendar_action(day, month, year, week, dir) abort let day = s:prefix_zero(a:day) let month = s:prefix_zero(a:month) @@ -317,11 +427,10 @@ function! vimwiki#diary#calendar_action(day, month, year, week, dir) endfunction -function vimwiki#diary#calendar_sign(day, month, year) +function! vimwiki#diary#calendar_sign(day, month, year) abort let day = s:prefix_zero(a:day) let month = s:prefix_zero(a:month) let sfile = vimwiki#vars#get_wikilocal('path').vimwiki#vars#get_wikilocal('diary_rel_path'). \ a:year.'-'.month.'-'.day.vimwiki#vars#get_wikilocal('ext') return filereadable(expand(sfile)) endfunction - diff --git a/autoload/vimwiki/html.vim b/autoload/vimwiki/html.vim index ba2cc4c..0da3d81 100644 --- a/autoload/vimwiki/html.vim +++ b/autoload/vimwiki/html.vim @@ -4,30 +4,30 @@ " Home: https://github.com/vimwiki/vimwiki/ -if exists("g:loaded_vimwiki_html_auto") || &cp +if exists('g:loaded_vimwiki_html_auto') || &compatible finish endif let g:loaded_vimwiki_html_auto = 1 -function! s:root_path(subdir) +function! s:root_path(subdir) abort return repeat('../', len(split(a:subdir, '[/\\]'))) endfunction -function! s:syntax_supported() - return vimwiki#vars#get_wikilocal('syntax') ==? "default" +function! s:syntax_supported() abort + return vimwiki#vars#get_wikilocal('syntax') ==? 'default' endfunction -function! s:remove_blank_lines(lines) +function! s:remove_blank_lines(lines) abort while !empty(a:lines) && a:lines[-1] =~# '^\s*$' call remove(a:lines, -1) endwhile endfunction -function! s:is_web_link(lnk) +function! s:is_web_link(lnk) abort if a:lnk =~# '^\%(https://\|http://\|www.\|ftp://\|file://\|mailto:\)' return 1 endif @@ -35,7 +35,7 @@ function! s:is_web_link(lnk) endfunction -function! s:is_img_link(lnk) +function! s:is_img_link(lnk) abort if tolower(a:lnk) =~# '\.\%(png\|jpg\|gif\|jpeg\)$' return 1 endif @@ -43,7 +43,7 @@ function! s:is_img_link(lnk) endfunction -function! s:has_abs_path(fname) +function! s:has_abs_path(fname) abort if a:fname =~# '\(^.:\)\|\(^/\)' return 1 endif @@ -51,10 +51,10 @@ function! s:has_abs_path(fname) endfunction -function! s:find_autoload_file(name) +function! s:find_autoload_file(name) abort for path in split(&runtimepath, ',') let fname = path.'/autoload/vimwiki/'.a:name - if glob(fname) != '' + if glob(fname) !=? '' return fname endif endfor @@ -62,19 +62,19 @@ function! s:find_autoload_file(name) endfunction -function! s:default_CSS_full_name(path) +function! s:default_CSS_full_name(path) abort let path = expand(a:path) let css_full_name = path . vimwiki#vars#get_wikilocal('css_name') return css_full_name endfunction -function! s:create_default_CSS(path) +function! s:create_default_CSS(path) abort let css_full_name = s:default_CSS_full_name(a:path) - if glob(css_full_name) == "" + if glob(css_full_name) ==? '' call vimwiki#path#mkdir(fnamemodify(css_full_name, ':p:h')) let default_css = s:find_autoload_file('style.css') - if default_css != '' + if default_css !=? '' let lines = readfile(default_css) call writefile(lines, css_full_name) return 1 @@ -84,8 +84,8 @@ function! s:create_default_CSS(path) endfunction -function! s:template_full_name(name) - if a:name == '' +function! s:template_full_name(name) abort + if a:name ==? '' let name = vimwiki#vars#get_wikilocal('template_default') else let name = a:name @@ -102,11 +102,11 @@ function! s:template_full_name(name) endfunction -function! s:get_html_template(template) +function! s:get_html_template(template) abort " TODO: refactor it!!! let lines=[] - if a:template != '' + if a:template !=? '' let template_name = s:template_full_name(a:template) try let lines = readfile(template_name) @@ -118,7 +118,7 @@ function! s:get_html_template(template) let default_tpl = s:template_full_name('') - if default_tpl == '' + if default_tpl ==? '' let default_tpl = s:find_autoload_file('default.tpl') endif @@ -127,19 +127,19 @@ function! s:get_html_template(template) endfunction -function! s:safe_html_preformatted(line) +function! s:safe_html_preformatted(line) abort let line = substitute(a:line,'<','\<', 'g') let line = substitute(line,'>','\>', 'g') return line endfunction -function! s:escape_html_attribute(string) +function! s:escape_html_attribute(string) abort return substitute(a:string, '"', '\"', 'g') endfunction -function! s:safe_html_line(line) +function! s:safe_html_line(line) abort " escape & < > when producing HTML text " s:lt_pattern, s:gt_pattern depend on g:vimwiki_valid_html_tags " and are set in vimwiki#html#Wiki2HTML() @@ -151,18 +151,18 @@ function! s:safe_html_line(line) endfunction -function! s:delete_html_files(path) +function! s:delete_html_files(path) abort let htmlfiles = split(glob(a:path.'**/*.html'), '\n') for fname in htmlfiles " ignore user html files, e.g. search.html,404.html - if stridx(vimwiki#vars#get_global('user_htmls'), fnamemodify(fname, ":t")) >= 0 + if stridx(vimwiki#vars#get_global('user_htmls'), fnamemodify(fname, ':t')) >= 0 continue endif " delete if there is no corresponding wiki file let subdir = vimwiki#base#subdir(vimwiki#vars#get_wikilocal('path_html'), fname) let wikifile = vimwiki#vars#get_wikilocal('path').subdir. - \fnamemodify(fname, ":t:r").vimwiki#vars#get_wikilocal('ext') + \fnamemodify(fname, ':t:r').vimwiki#vars#get_wikilocal('ext') if filereadable(wikifile) continue endif @@ -176,22 +176,22 @@ function! s:delete_html_files(path) endfunction -function! s:mid(value, cnt) +function! s:mid(value, cnt) abort return strpart(a:value, a:cnt, len(a:value) - 2 * a:cnt) endfunction -function! s:subst_func(line, regexp, func, ...) +function! s:subst_func(line, regexp, func, ...) abort " Substitute text found by regexp with result of " func(matched) function. let pos = 0 let lines = split(a:line, a:regexp, 1) - let res_line = "" + let res_line = '' for line in lines let res_line = res_line.line let matched = matchstr(a:line, a:regexp, pos) - if matched != "" + if matched !=? '' if a:0 let res_line = res_line.{a:func}(matched, a:1) else @@ -204,7 +204,7 @@ function! s:subst_func(line, regexp, func, ...) endfunction -function! s:process_date(placeholders, default_date) +function! s:process_date(placeholders, default_date) abort if !empty(a:placeholders) for [placeholder, row, idx] in a:placeholders let [type, param] = placeholder @@ -217,7 +217,7 @@ function! s:process_date(placeholders, default_date) endfunction -function! s:process_title(placeholders, default_title) +function! s:process_title(placeholders, default_title) abort if !empty(a:placeholders) for [placeholder, row, idx] in a:placeholders let [type, param] = placeholder @@ -230,17 +230,24 @@ function! s:process_title(placeholders, default_title) endfunction -function! s:is_html_uptodate(wikifile) +function! s:is_html_uptodate(wikifile) abort let tpl_time = -1 let tpl_file = s:template_full_name('') - if tpl_file != '' + if tpl_file !=? '' let tpl_time = getftime(tpl_file) endif - let wikifile = fnamemodify(a:wikifile, ":p") - let htmlfile = expand(vimwiki#vars#get_wikilocal('path_html') . - \ vimwiki#vars#get_bufferlocal('subdir') . fnamemodify(wikifile, ":t:r").".html") + let wikifile = fnamemodify(a:wikifile, ':p') + + if vimwiki#vars#get_wikilocal('html_filename_parameterization') + let parameterized_wikiname = s:parameterized_wikiname(wikifile) + let htmlfile = expand(vimwiki#vars#get_wikilocal('path_html') . + \ vimwiki#vars#get_bufferlocal('subdir') . parameterized_wikiname) + else + let htmlfile = expand(vimwiki#vars#get_wikilocal('path_html') . + \ vimwiki#vars#get_bufferlocal('subdir') . fnamemodify(wikifile, ':t:r').'.html') + endif if getftime(wikifile) <= getftime(htmlfile) && tpl_time <= getftime(htmlfile) return 1 @@ -248,8 +255,17 @@ function! s:is_html_uptodate(wikifile) return 0 endfunction +function! s:parameterized_wikiname(wikifile) abort + let initial = fnamemodify(a:wikifile, ':t:r') + let lower_sanitized = tolower(initial) + let substituted = substitute(lower_sanitized, '[^a-z0-9_-]\+','-', 'g') + let substituted = substitute(substituted, '\-\+','-', 'g') + let substituted = substitute(substituted, '^-', '', 'g') + let substituted = substitute(substituted, '-$', '', 'g') + return substitute(substituted, '\-\+','-', 'g') . '.html' +endfunction -function! s:html_insert_contents(html_lines, content) +function! s:html_insert_contents(html_lines, content) abort let lines = [] for line in a:html_lines if line =~# '%content%' @@ -272,27 +288,27 @@ function! s:html_insert_contents(html_lines, content) endfunction -function! s:tag_eqin(value) +function! s:tag_eqin(value) abort " mathJAX wants \( \) for inline maths return '\('.s:mid(a:value, 1).'\)' endfunction -function! s:tag_em(value) +function! s:tag_em(value) abort return ''.s:mid(a:value, 1).'' endfunction -function! s:tag_strong(value, header_ids) +function! s:tag_strong(value, header_ids) abort let text = s:mid(a:value, 1) let id = s:escape_html_attribute(text) let complete_id = '' for l in range(6) - if a:header_ids[l][0] != '' + if a:header_ids[l][0] !=? '' let complete_id .= a:header_ids[l][0].'-' endif endfor - if a:header_ids[5][0] == '' + if a:header_ids[5][0] ==? '' let complete_id = complete_id[:-2] endif let complete_id .= '-'.id @@ -301,14 +317,14 @@ function! s:tag_strong(value, header_ids) endfunction -function! s:tag_tags(value, header_ids) +function! s:tag_tags(value, header_ids) abort let complete_id = '' for level in range(6) - if a:header_ids[level][0] != '' + if a:header_ids[level][0] !=? '' let complete_id .= a:header_ids[level][0].'-' endif endfor - if a:header_ids[5][0] == '' + if a:header_ids[5][0] ==? '' let complete_id = complete_id[:-2] endif let complete_id = s:escape_html_attribute(complete_id) @@ -323,34 +339,54 @@ function! s:tag_tags(value, header_ids) endfunction -function! s:tag_todo(value) +function! s:tag_todo(value) abort return ''.a:value.'' endfunction -function! s:tag_strike(value) +function! s:tag_strike(value) abort return ''.s:mid(a:value, 2).'' endfunction -function! s:tag_super(value) +function! s:tag_super(value) abort return ''.s:mid(a:value, 1).'' endfunction -function! s:tag_sub(value) +function! s:tag_sub(value) abort return ''.s:mid(a:value, 2).'' endfunction -function! s:tag_code(value) - return ''.s:safe_html_preformatted(s:mid(a:value, 1)).'' +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 " match n-th ARG within {{URL[|ARG1|ARG2|...]}} " *c,d,e),... -function! s:incl_match_arg(nn_index) +function! s:incl_match_arg(nn_index) abort 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) @@ -364,10 +400,10 @@ function! s:incl_match_arg(nn_index) endfunction -function! s:linkify_link(src, descr) +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 = (descr ==? '' ? a:src : descr) let descr_str = (descr =~# vimwiki#vars#get_global('rxWikiIncl') \ ? s:tag_wikiincl(descr) \ : descr) @@ -375,15 +411,15 @@ function! s:linkify_link(src, descr) endfunction -function! s:linkify_image(src, descr, verbatim_str) +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 : '') + let descr_str = (a:descr !=? '' ? ' alt="'.a:descr.'"' : '') + let verbatim_str = (a:verbatim_str !=? '' ? ' '.a:verbatim_str : '') return '' endfunction -function! s:tag_weblink(value) +function! s:tag_weblink(value) abort " Weblink Template -> descr let str = a:value let url = matchstr(str, vimwiki#vars#get_syntaxlocal('rxWeblinkMatchUrl')) @@ -393,7 +429,7 @@ function! s:tag_weblink(value) endfunction -function! s:tag_wikiincl(value) +function! s:tag_wikiincl(value) abort " {{imgurl|arg1|arg2}} -> ??? " {{imgurl}} -> " {{imgurl|descr|style="A"}} -> descr @@ -402,7 +438,7 @@ function! s:tag_wikiincl(value) " custom transclusions let line = VimwikiWikiIncludeHandler(str) " otherwise, assume image transclusion - if line == '' + 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)) @@ -427,7 +463,7 @@ function! s:tag_wikiincl(value) endfunction -function! s:tag_wikilink(value) +function! s:tag_wikilink(value) abort " [[url]] -> url " [[url|descr]] -> descr " [[url|{{...}}]] -> ... @@ -439,10 +475,10 @@ function! s:tag_wikilink(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 descr = (descr !=? '' ? descr : url) let line = VimwikiLinkConverter(url, s:current_wiki_file, s:current_html_file) - if line == '' + if line ==? '' let link_infos = vimwiki#base#resolve_link(url, s:current_wiki_file) if link_infos.scheme ==# 'file' @@ -456,14 +492,14 @@ function! s:tag_wikilink(value) let html_link = vimwiki#path#relpath( \ fnamemodify(s:current_wiki_file, ':h'), \ fnamemodify(link_infos.filename, ':r')) - if html_link !~ '\m/$' + 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 != '' + if link_infos.anchor !=? '' let anchor = substitute(link_infos.anchor, '#', '-', 'g') let html_link .= '#'.anchor endif @@ -475,19 +511,19 @@ function! s:tag_wikilink(value) endfunction -function! s:tag_remove_internal_link(value) +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) + let link_parts = split(value, '|', 1) else - let link_parts = split(value, "][", 1) + let link_parts = split(value, '][', 1) endif if len(link_parts) > 1 if len(link_parts) < 3 - let style = "" + let style = '' else let style = link_parts[2] endif @@ -499,7 +535,7 @@ function! s:tag_remove_internal_link(value) endfunction -function! s:tag_remove_external_link(value) +function! s:tag_remove_external_link(value) abort let value = s:mid(a:value, 1) let line = '' @@ -507,7 +543,7 @@ function! s:tag_remove_external_link(value) let lnkElements = split(value) let head = lnkElements[0] let rest = join(lnkElements[1:]) - if rest == "" + if rest ==? '' let rest = head endif let line = rest @@ -522,7 +558,7 @@ function! s:tag_remove_external_link(value) endfunction -function! s:make_tag(line, regexp, func, ...) +function! s:make_tag(line, regexp, func, ...) abort " Make tags for a given matched regexp. " Exclude preformatted text and href links. " FIXME @@ -548,7 +584,7 @@ function! s:make_tag(line, regexp, func, ...) " result: " ['hello world ', ' simple ', 'type of', ' prg'] let lines = split(a:line, patt_splitter, 1) - let res_line = "" + let res_line = '' for line in lines if a:0 let res_line = res_line.s:subst_func(line, a:regexp, a:func, a:1) @@ -563,7 +599,7 @@ function! s:make_tag(line, regexp, func, ...) endfunction -function! s:process_tags_remove_links(line) +function! s:process_tags_remove_links(line) abort let line = a:line let line = s:make_tag(line, '\[\[.\{-}\]\]', 's:tag_remove_internal_link') let line = s:make_tag(line, '\[.\{-}\]', 's:tag_remove_external_link') @@ -571,7 +607,7 @@ function! s:process_tags_remove_links(line) endfunction -function! s:process_tags_typefaces(line, header_ids) +function! s:process_tags_typefaces(line, header_ids) abort let line = a:line let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxItalic'), 's:tag_em') let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxBold'), 's:tag_strong', a:header_ids) @@ -586,7 +622,7 @@ function! s:process_tags_typefaces(line, header_ids) endfunction -function! s:process_tags_links(line) +function! s:process_tags_links(line) abort let line = a:line let line = s:make_tag(line, vimwiki#vars#get_syntaxlocal('rxWikiLink'), 's:tag_wikilink') let line = s:make_tag(line, vimwiki#vars#get_global('rxWikiIncl'), 's:tag_wikiincl') @@ -595,23 +631,23 @@ function! s:process_tags_links(line) endfunction -function! s:process_inline_tags(line, header_ids) +function! s:process_inline_tags(line, header_ids) abort let line = s:process_tags_links(a:line) let line = s:process_tags_typefaces(line, a:header_ids) return line endfunction -function! s:close_tag_pre(pre, ldest) +function! s:close_tag_pre(pre, ldest) abort if a:pre[0] - call insert(a:ldest, "") + call insert(a:ldest, '') return 0 endif return a:pre endfunction -function! s:close_tag_math(math, ldest) +function! s:close_tag_math(math, ldest) abort if a:math[0] call insert(a:ldest, "\\\]") return 0 @@ -620,25 +656,25 @@ function! s:close_tag_math(math, ldest) endfunction -function! s:close_tag_quote(quote, ldest) +function! s:close_tag_quote(quote, ldest) abort if a:quote - call insert(a:ldest, "") + call insert(a:ldest, '') return 0 endif return a:quote endfunction -function! s:close_tag_para(para, ldest) +function! s:close_tag_para(para, ldest) abort if a:para - call insert(a:ldest, "

") + call insert(a:ldest, '

') return 0 endif return a:para endfunction -function! s:close_tag_table(table, ldest, header_ids) +function! s:close_tag_table(table, ldest, header_ids) abort " The first element of table list is a string which tells us if table should be centered. " The rest elements are rows which are lists of columns: " ['center', @@ -648,7 +684,7 @@ function! s:close_tag_table(table, ldest, header_ids) " ] " And CELLx is: { 'body': 'col_x', 'rowspan': r, 'colspan': c } - function! s:sum_rowspan(table) + function! s:sum_rowspan(table) abort let table = a:table " Get max cells @@ -680,7 +716,7 @@ function! s:close_tag_table(table, ldest, header_ids) endfor endfunction - function! s:sum_colspan(table) + function! s:sum_colspan(table) abort for row in a:table[1:] let cols = 1 @@ -695,7 +731,7 @@ function! s:close_tag_table(table, ldest, header_ids) endfor endfunction - function! s:close_tag_row(row, header, ldest, header_ids) + function! s:close_tag_row(row, header, ldest, header_ids) abort call add(a:ldest, '') " Set tag element of columns @@ -739,7 +775,7 @@ function! s:close_tag_table(table, ldest, header_ids) if table[0] ==# 'center' call add(ldest, "") else - call add(ldest, "
") + call add(ldest, '
') endif " Empty lists are table separators. @@ -767,14 +803,14 @@ function! s:close_tag_table(table, ldest, header_ids) call s:close_tag_row(row, 0, ldest, a:header_ids) endfor endif - call add(ldest, "
") + call add(ldest, '') let table = [] endif return table endfunction -function! s:close_tag_list(lists, ldest) +function! s:close_tag_list(lists, ldest) abort while len(a:lists) let item = remove(a:lists, 0) call insert(a:ldest, item[0]) @@ -782,16 +818,16 @@ function! s:close_tag_list(lists, ldest) endfunction -function! s:close_tag_def_list(deflist, ldest) +function! s:close_tag_def_list(deflist, ldest) abort if a:deflist - call insert(a:ldest, "") + call insert(a:ldest, '') return 0 endif return a:deflist endfunction -function! s:process_tag_pre(line, pre) +function! s:process_tag_pre(line, pre) abort " pre is the list of [is_in_pre, indent_of_pre] "XXX always outputs a single line or empty list! let lines = [] @@ -803,16 +839,16 @@ function! s:process_tag_pre(line, pre) let class = matchstr(a:line, '{{{\zs.*$') "FIXME class cannot contain arbitrary strings let class = substitute(class, '\s\+$', '', 'g') - if class != "" - call add(lines, "
")
+    if class !=? ''
+      call add(lines, '
')
     else
-      call add(lines, "
")
+      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, "
") + call add(lines, '
') let processed = 1 elseif pre[0] let processed = 1 @@ -824,7 +860,7 @@ function! s:process_tag_pre(line, pre) endfunction -function! s:process_tag_math(line, math) +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 @@ -836,9 +872,9 @@ function! s:process_tag_math(line, math) " 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 != "" + if s:current_math_env !=? '' call add(lines, substitute(class, '^%\(\S\+\)%', '\\begin{\1}', '')) - elseif class != "" + elseif class !=? '' call add(lines, "\\\[".class) else call add(lines, "\\\[") @@ -847,8 +883,8 @@ function! s:process_tag_math(line, math) 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."}") + if s:current_math_env !=? '' + call add(lines, "\\end{".s:current_math_env.'}') else call add(lines, "\\\]") endif @@ -861,28 +897,28 @@ function! s:process_tag_math(line, math) endfunction -function! s:process_tag_quote(line, quote) +function! s:process_tag_quote(line, quote) abort let lines = [] let quote = a:quote let processed = 0 if a:line =~# '^\s\{4,}\S' if !quote - call add(lines, "
") + call add(lines, '
') let quote = 1 endif let processed = 1 call add(lines, substitute(a:line, '^\s*', '', '')) elseif quote - call add(lines, "
") + call add(lines, '
') let quote = 0 endif return [processed, lines, quote] endfunction -function! s:process_tag_list(line, lists) +function! s:process_tag_list(line, lists) abort - function! s:add_checkbox(line, rx_list) + function! s:add_checkbox(line, rx_list) abort let st_tag = '
  • ' let chk = matchlist(a:line, a:rx_list) if !empty(chk) && len(chk[1]) > 0 @@ -933,7 +969,7 @@ function! s:process_tag_list(line, lists) let lstRegExp = '' endif - if lstSym != '' + if lstSym !=? '' " To get proper indent level 'retab' the line -- change all tabs " to spaces*tabstop let line = substitute(a:line, '\t', repeat(' ', &tabstop), 'g') @@ -979,55 +1015,55 @@ function! s:process_tag_list(line, lists) endfunction -function! s:process_tag_def_list(line, deflist) +function! s:process_tag_def_list(line, deflist) abort let lines = [] let deflist = a:deflist let processed = 0 let matches = matchlist(a:line, '\(^.*\)::\%(\s\|$\)\(.*\)') if !deflist && len(matches) > 0 - call add(lines, "
    ") + call add(lines, '
    ') let deflist = 1 endif if deflist && len(matches) > 0 - if matches[1] != '' - call add(lines, "
    ".matches[1]."
    ") + if matches[1] !=? '' + call add(lines, '
    '.matches[1].'
    ') endif - if matches[2] != '' - call add(lines, "
    ".matches[2]."
    ") + if matches[2] !=? '' + call add(lines, '
    '.matches[2].'
    ') endif let processed = 1 elseif deflist let deflist = 0 - call add(lines, "
    ") + call add(lines, '
    ') endif return [processed, lines, deflist] endfunction -function! s:process_tag_para(line, para) +function! s:process_tag_para(line, para) abort let lines = [] let para = a:para let processed = 0 if a:line =~# '^\s\{,3}\S' if !para - call add(lines, "

    ") + call add(lines, '

    ') let para = 1 endif let processed = 1 if vimwiki#vars#get_global('text_ignore_newline') call add(lines, a:line) else - call add(lines, a:line."
    ") + call add(lines, a:line.'
    ') endif elseif para && a:line =~# '^\s*$' - call add(lines, "

    ") + call add(lines, '

    ') let para = 0 endif return [processed, lines, para] endfunction -function! s:process_tag_h(line, id) +function! s:process_tag_h(line, id) abort let line = a:line let processed = 0 let h_level = 0 @@ -1056,7 +1092,7 @@ function! s:process_tag_h(line, id) for l in range(h_level-1) let h_number .= a:id[l][1].'.' - if a:id[l][0] != '' + if a:id[l][0] !=? '' let h_complete_id .= a:id[l][0].'-' endif endfor @@ -1078,7 +1114,7 @@ function! s:process_tag_h(line, id) else - let h_part = '

    + " inserts the line above to the final html file (without %plainhtml prefix) + let trigger = '%plainhtml' + if line =~# '^\s*' . trigger + let lines = [] + let processed = 1 + + " if something precedes the plain text line, + " make sure everything gets closed properly + " before inserting plain text. this ensures that + " the plain text is not considered as + " part of the preceding structure + if processed && len(state.table) + let state.table = s:close_tag_table(state.table, lines, state.header_ids) + endif + if processed && state.deflist + let state.deflist = s:close_tag_def_list(state.deflist, lines) + endif + if processed && state.quote + let state.quote = s:close_tag_quote(state.quote, lines) + endif + if processed && state.para + let state.para = s:close_tag_para(state.para, lines) + endif + + " remove the trigger prefix + let pp = split(line, trigger)[0] + + call add(lines, pp) + call extend(res_lines, lines) + endif + endif let line = s:safe_html_line(a:line) - let processed = 0 - " pres if !processed let [processed, lines, state.pre] = s:process_tag_pre(line, state.pre) @@ -1392,16 +1464,16 @@ function! s:parse_line(line, state) endfunction -function! s:use_custom_wiki2html() +function! s:use_custom_wiki2html() abort let custom_wiki2html = vimwiki#vars#get_wikilocal('custom_wiki2html') return !empty(custom_wiki2html) && \ (s:file_exists(custom_wiki2html) || s:binary_exists(custom_wiki2html)) endfunction -function! vimwiki#html#CustomWiki2HTML(path, wikifile, force) +function! vimwiki#html#CustomWiki2HTML(path, wikifile, force) abort call vimwiki#path#mkdir(a:path) - echomsg system(vimwiki#vars#get_wikilocal('custom_wiki2html'). ' '. + let output = system(vimwiki#vars#get_wikilocal('custom_wiki2html'). ' '. \ a:force. ' '. \ vimwiki#vars#get_wikilocal('syntax'). ' '. \ strpart(vimwiki#vars#get_wikilocal('ext'), 1). ' '. @@ -1418,16 +1490,20 @@ function! vimwiki#html#CustomWiki2HTML(path, wikifile, force) \ shellescape(s:root_path(vimwiki#vars#get_bufferlocal('subdir'))) : '-'). ' '. \ (len(vimwiki#vars#get_wikilocal('custom_wiki2html_args')) > 0 ? \ vimwiki#vars#get_wikilocal('custom_wiki2html_args') : '-')) + " Echo if non void + if output !~? '^\s*$' + echomsg output + endif endfunction -function! s:convert_file(path_html, wikifile) +function! s:convert_file(path_html, wikifile) abort let done = 0 - let wikifile = fnamemodify(a:wikifile, ":p") + let wikifile = fnamemodify(a:wikifile, ':p') let path_html = expand(a:path_html).vimwiki#vars#get_bufferlocal('subdir') - let htmlfile = fnamemodify(wikifile, ":t:r").'.html' + let htmlfile = fnamemodify(wikifile, ':t:r').'.html' " the currently processed file name is needed when processing links " yeah yeah, shame on me for using (quasi-) global variables @@ -1471,7 +1547,7 @@ function! s:convert_file(path_html, wikifile) " prepare constants for s:safe_html_line() let s:lt_pattern = '<' let s:gt_pattern = '>' - if vimwiki#vars#get_global('valid_html_tags') != '' + if vimwiki#vars#get_global('valid_html_tags') !=? '' let tags = join(split(vimwiki#vars#get_global('valid_html_tags'), '\s*,\s*'), '\|') let s:lt_pattern = '\c<\%(/\?\%('.tags.'\)\%(\s\{-1}\S\{-}\)\{-}/\?>\)\@!' let s:gt_pattern = '\c\%(' @@ -1509,7 +1585,7 @@ function! s:convert_file(path_html, wikifile) if nohtml - echon "\r"."%nohtml placeholder found" + echon "\r".'%nohtml placeholder found' return '' endif @@ -1527,8 +1603,9 @@ function! s:convert_file(path_html, wikifile) call s:close_tag_table(state.table, lines, state.header_ids) call extend(ldest, lines) - let title = s:process_title(placeholders, fnamemodify(a:wikifile, ":t:r")) + let title = s:process_title(placeholders, fnamemodify(a:wikifile, ':t:r')) let date = s:process_date(placeholders, strftime('%Y-%m-%d')) + let wiki_path = strpart(s:current_wiki_file, strlen(vimwiki#vars#get_wikilocal('path'))) let html_lines = s:get_html_template(template_name) @@ -1537,13 +1614,14 @@ function! s:convert_file(path_html, wikifile) call map(html_lines, 'substitute(v:val, "%date%", "'. date .'", "g")') call map(html_lines, 'substitute(v:val, "%root_path%", "'. \ s:root_path(vimwiki#vars#get_bufferlocal('subdir')) .'", "g")') + call map(html_lines, 'substitute(v:val, "%wiki_path%", "'. wiki_path .'", "g")') let css_name = expand(vimwiki#vars#get_wikilocal('css_name')) let css_name = substitute(css_name, '\', '/', 'g') call map(html_lines, 'substitute(v:val, "%css%", "'. css_name .'", "g")') let enc = &fileencoding - if enc == '' + if enc ==? '' let enc = &encoding endif call map(html_lines, 'substitute(v:val, "%encoding%", "'. enc .'", "g")') @@ -1564,16 +1642,16 @@ function! s:convert_file(path_html, wikifile) endfunction -function! vimwiki#html#Wiki2HTML(path_html, wikifile) +function! vimwiki#html#Wiki2HTML(path_html, wikifile) abort let result = s:convert_file(a:path_html, a:wikifile) - if result != '' + if result !=? '' call s:create_default_CSS(a:path_html) endif return result endfunction -function! vimwiki#html#WikiAll2HTML(path_html) +function! vimwiki#html#WikiAll2HTML(path_html, force) abort if !s:syntax_supported() && !s:use_custom_wiki2html() echomsg 'Vimwiki Error: Conversion to HTML is not supported for this syntax' return @@ -1581,7 +1659,7 @@ function! vimwiki#html#WikiAll2HTML(path_html) echomsg 'Vimwiki: Saving Vimwiki files ...' let save_eventignore = &eventignore - let &eventignore = "all" + let &eventignore = 'all' try wall catch @@ -1592,8 +1670,10 @@ function! vimwiki#html#WikiAll2HTML(path_html) let path_html = expand(a:path_html) call vimwiki#path#mkdir(path_html) - echomsg 'Vimwiki: Deleting non-wiki html files ...' - call s:delete_html_files(path_html) + if !vimwiki#vars#get_wikilocal('html_filename_parameterization') + echomsg 'Vimwiki: Deleting non-wiki html files ...' + call s:delete_html_files(path_html) + endif echomsg 'Vimwiki: Converting wiki to html files ...' let setting_more = &more @@ -1606,14 +1686,14 @@ function! vimwiki#html#WikiAll2HTML(path_html) let wikifiles = split(glob(vimwiki#vars#get_wikilocal('path').'**/*'. \ vimwiki#vars#get_wikilocal('ext')), '\n') for wikifile in wikifiles - let wikifile = fnamemodify(wikifile, ":p") + let wikifile = fnamemodify(wikifile, ':p') " temporarily adjust 'subdir' and 'invsubdir' state variables let subdir = vimwiki#base#subdir(vimwiki#vars#get_wikilocal('path'), wikifile) call vimwiki#vars#set_bufferlocal('subdir', subdir) call vimwiki#vars#set_bufferlocal('invsubdir', vimwiki#base#invsubdir(subdir)) - if !s:is_html_uptodate(wikifile) + if a:force || !s:is_html_uptodate(wikifile) echomsg 'Vimwiki: Processing '.wikifile call s:convert_file(path_html, wikifile) @@ -1636,29 +1716,29 @@ function! vimwiki#html#WikiAll2HTML(path_html) endfunction -function! s:file_exists(fname) +function! s:file_exists(fname) abort return !empty(getftype(expand(a:fname))) endfunction -function! s:binary_exists(fname) +function! s:binary_exists(fname) abort return executable(expand(a:fname)) endfunction -function! s:get_wikifile_url(wikifile) +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' + \ fnamemodify(a:wikifile, ':t:r').'.html' endfunction -function! vimwiki#html#PasteUrl(wikifile) +function! vimwiki#html#PasteUrl(wikifile) abort execute 'r !echo file://'.s:get_wikifile_url(a:wikifile) endfunction -function! vimwiki#html#CatUrl(wikifile) +function! vimwiki#html#CatUrl(wikifile) abort execute '!echo file://'.s:get_wikifile_url(a:wikifile) endfunction diff --git a/autoload/vimwiki/lst.vim b/autoload/vimwiki/lst.vim index 201a658..bebd89b 100644 --- a/autoload/vimwiki/lst.vim +++ b/autoload/vimwiki/lst.vim @@ -4,7 +4,7 @@ " Home: https://github.com/vimwiki/vimwiki/ -if exists("g:loaded_vimwiki_list_auto") || &cp +if exists('g:loaded_vimwiki_list_auto') || &compatible finish endif let g:loaded_vimwiki_list_auto = 1 @@ -14,12 +14,12 @@ let g:loaded_vimwiki_list_auto = 1 " incrementation functions for the various kinds of numbers " --------------------------------------------------------- -function! s:increment_1(value) +function! s:increment_1(value) abort return eval(a:value) + 1 endfunction -function! s:increment_A(value) +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))) @@ -39,7 +39,7 @@ function! s:increment_A(value) endfunction -function! s:increment_a(value) +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))) @@ -59,7 +59,7 @@ function! s:increment_a(value) endfunction -function! s:increment_I(value) +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'], @@ -74,7 +74,7 @@ function! s:increment_I(value) endfunction -function! s:increment_i(value) +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'], @@ -93,41 +93,41 @@ endfunction " utility functions " --------------------------------------------------------- -function! s:substitute_rx_in_line(lnum, pattern, new_string) +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) +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) +function! s:first_char(string) abort return matchstr(a:string, '^.') endfunction -if exists("*strdisplaywidth") - function! s:string_length(str) +if exists('*strdisplaywidth') + function! s:string_length(str) abort return strdisplaywidth(a:str) endfunction else - function! s:string_length(str) + function! s:string_length(str) abort return strlen(substitute(a:str, '.', 'x', 'g')) endfunction endif -function! vimwiki#lst#default_symbol() +function! vimwiki#lst#default_symbol() abort return vimwiki#vars#get_syntaxlocal('list_markers')[0] endfunction -function! vimwiki#lst#get_list_margin() +function! vimwiki#lst#get_list_margin() abort let list_margin = vimwiki#vars#get_wikilocal('list_margin') if list_margin < 0 - return &sw + return &shiftwidth else return list_margin endif @@ -136,7 +136,7 @@ endfunction "Returns: the column where the text of a line starts (possible list item "markers and checkboxes are skipped) -function! s:text_begin(lnum) +function! s:text_begin(lnum) abort return s:string_length(matchstr(getline(a:lnum), vimwiki#vars#get_syntaxlocal('rxListItem'))) endfunction @@ -144,7 +144,7 @@ endfunction "Returns: 2 if there is a marker and text " 1 for a marker and no text " 0 for no marker at all (empty line or only text) -function! s:line_has_marker(lnum) +function! s:line_has_marker(lnum) abort if getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxListItem').'\s*$' return 1 elseif getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxListItem').'\s*\S' @@ -165,7 +165,7 @@ endfunction "type - 1 for bulleted item, 2 for numbered item, 0 for a regular line "mrkr - the concrete marker, e.g. '**' or 'b)' "cb - the char in the checkbox or '' if there is no checkbox -function! s:get_item(lnum) +function! s:get_item(lnum) abort let item = {'lnum': a:lnum} if a:lnum == 0 || a:lnum > line('$') let item.type = 0 @@ -174,15 +174,15 @@ function! s:get_item(lnum) let matches = matchlist(getline(a:lnum), vimwiki#vars#get_syntaxlocal('rxListItem')) if matches == [] || - \ (matches[1] == '' && matches[2] == '') || - \ (matches[1] != '' && matches[2] != '') + \ (matches[1] ==? '' && matches[2] ==? '') || + \ (matches[1] !=? '' && matches[2] !=? '') let item.type = 0 return item endif let item.cb = matches[3] - if matches[1] != '' + if matches[1] !=? '' let item.type = 1 let item.mrkr = matches[1] else @@ -194,14 +194,14 @@ function! s:get_item(lnum) endfunction -function! s:empty_item() +function! s:empty_item() abort return {'type': 0} endfunction "Returns: level of the line "0 is the 'highest' level -function! s:get_level(lnum) +function! s:get_level(lnum) abort if getline(a:lnum) =~# '^\s*$' return 0 endif @@ -209,7 +209,7 @@ function! s:get_level(lnum) let level = indent(a:lnum) else let level = s:string_length(matchstr(getline(a:lnum), - \ vimwiki#vars#get_syntaxlocal(rx_bullet_chars)))-1 + \ vimwiki#vars#get_syntaxlocal('rx_bullet_chars')))-1 if level < 0 let level = (indent(a:lnum) == 0) ? 0 : 9999 endif @@ -221,7 +221,7 @@ endfunction "Returns: 1, a, i, A, I or '' "If in doubt if alphanumeric character or romanian "numeral, peek in the previous line -function! s:guess_kind_of_numbered_item(item) +function! s:guess_kind_of_numbered_item(item) abort if a:item.type != 2 | return '' | endif let number_chars = a:item.mrkr[:-2] let divisor = a:item.mrkr[-1:] @@ -282,14 +282,14 @@ function! s:guess_kind_of_numbered_item(item) endfunction -function! s:regexp_of_marker(item) +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 != '' + if match !=? '' return '\'.ki.'\+'.vimwiki#u#escape(match[-1:]) endif endfor @@ -300,7 +300,7 @@ endfunction " Returns: Whether or not the checkbox of a list item is [X] or [-] -function! s:is_closed(item) +function! s:is_closed(item) abort let state = a:item.cb return state ==# vimwiki#vars#get_syntaxlocal('listsyms_list')[-1] \ || state ==# vimwiki#vars#get_global('listsym_rejected') @@ -312,7 +312,7 @@ endfunction "Returns: the list item after a:item or an empty item "If a:ignore_kind is 1, the markers can differ -function! s:get_next_list_item(item, ignore_kind) +function! s:get_next_list_item(item, ignore_kind) abort let org_lvl = s:get_level(a:item.lnum) if !a:ignore_kind let org_regex = s:regexp_of_marker(a:item) @@ -336,7 +336,7 @@ endfunction "Returns: the list item before a:item or an empty item "If a:ignore_kind is 1, the markers can differ -function! s:get_prev_list_item(item, ignore_kind) +function! s:get_prev_list_item(item, ignore_kind) abort let org_lvl = s:get_level(a:item.lnum) if !a:ignore_kind let org_regex = s:regexp_of_marker(a:item) @@ -358,7 +358,7 @@ function! s:get_prev_list_item(item, ignore_kind) endfunction -function! s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex) +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' @@ -372,7 +372,7 @@ function! s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex) endfunction -function! s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl) +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 @@ -381,7 +381,7 @@ function! s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl) endfunction -function! s:get_first_item_in_list(item, ignore_kind) +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) @@ -395,7 +395,7 @@ function! s:get_first_item_in_list(item, ignore_kind) endfunction -function! s:get_last_item_in_list(item, ignore_kind) +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) @@ -413,17 +413,19 @@ endfunction "0 in case of nonvalid line. "If there is no second argument, 0 is returned at a header, otherwise the "header is skipped -function! s:get_next_line(lnum, ...) +function! s:get_next_line(lnum, ...) abort 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 + let next_line = cur_ln + 1 else - let next_line = nextnonblank(a:lnum+1) + 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 @@ -439,20 +441,20 @@ endfunction "Returns: lnum-1 in most cases, but skips blank lines and preformatted text "0 in case of nonvalid line and a header, because a header ends every list -function! s:get_prev_line(lnum) - let prev_line = prevnonblank(a:lnum-1) +function! s:get_prev_line(lnum) abort + let cur_ln = a:lnum - 1 - if getline(prev_line) =~# vimwiki#vars#get_syntaxlocal('rxPreEnd') - 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 - let prev_line = cur_ln endif + let prev_line = prevnonblank(cur_ln) + if prev_line < 0 || prev_line > line('$') || \ getline(prev_line) =~# vimwiki#vars#get_syntaxlocal('rxHeader') return 0 @@ -462,7 +464,7 @@ function! s:get_prev_line(lnum) endfunction -function! s:get_first_child(item) +function! s:get_first_child(item) abort if a:item.lnum >= line('$') return s:empty_item() endif @@ -483,7 +485,7 @@ endfunction "Returns: the next sibling of a:child, given the parent item "Used for iterating over children "Note: child items do not necessarily have the same indent, i.e. level -function! s:get_next_child_item(parent, child) +function! s:get_next_child_item(parent, child) abort 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) @@ -502,7 +504,7 @@ function! s:get_next_child_item(parent, child) endfunction -function! s:get_parent(item) +function! s:get_parent(item) abort let parent_line = 0 let cur_ln = prevnonblank(a:item.lnum) @@ -530,7 +532,7 @@ endfunction "Returns: the item above or the item below or an empty item -function! s:get_a_neighbor_item(item) +function! s:get_a_neighbor_item(item) abort let prev_item = s:get_prev_list_item(a:item, 1) if prev_item.type != 0 return prev_item @@ -544,7 +546,7 @@ function! s:get_a_neighbor_item(item) endfunction -function! s:get_a_neighbor_item_in_column(lnum, column) +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 @@ -558,7 +560,7 @@ endfunction "Returns: the item if there is one in a:lnum "else the multiline item a:lnum belongs to -function! s:get_corresponding_item(lnum) +function! s:get_corresponding_item(lnum) abort let item = s:get_item(a:lnum) if item.type != 0 return item @@ -581,7 +583,7 @@ endfunction "Returns: the last line of a (possibly multiline) item, including all children -function! s:get_last_line_of_item_incl_children(item) +function! s:get_last_line_of_item_incl_children(item) abort let cur_ln = a:item.lnum let org_lvl = s:get_level(a:item.lnum) while 1 @@ -596,7 +598,7 @@ endfunction "Returns: the last line of a (possibly multiline) item "Note: there can be other list items between the first and last line -function! s:get_last_line_of_item(item) +function! s:get_last_line_of_item(item) abort if a:item.type == 0 | return 0 | endif let org_lvl = s:get_level(a:item.lnum) let last_corresponding_line = a:item.lnum @@ -625,7 +627,7 @@ endfunction "Renumbers the current list from a:item on downwards "Returns: the last item that was adjusted -function! s:adjust_numbered_list_below(item, recursive) +function! s:adjust_numbered_list_below(item, recursive) abort if !(a:item.type == 2 || (a:item.type == 1 && a:recursive)) return a:item endif @@ -655,7 +657,7 @@ function! s:adjust_numbered_list_below(item, recursive) endfunction -function! s:adjust_items_recursively(parent) +function! s:adjust_items_recursively(parent) abort if a:parent.type == 0 return s:empty_item() end @@ -679,7 +681,7 @@ endfunction "If a:ignore_kind == 0, only the items which have the same kind of marker as "a:item are considered, otherwise all items. "Returns: the last item that was adjusted -function! s:adjust_numbered_list(item, ignore_kind, recursive) +function! s:adjust_numbered_list(item, ignore_kind, recursive) abort if !(a:item.type == 2 || (a:item.type == 1 && (a:ignore_kind || a:recursive))) return s:empty_item() end @@ -706,7 +708,7 @@ endfunction "Renumbers the list the cursor is in "also update its parents checkbox state -function! vimwiki#lst#adjust_numbered_list() +function! vimwiki#lst#adjust_numbered_list() abort let cur_item = s:get_corresponding_item(line('.')) if cur_item.type == 0 | return | endif call s:adjust_numbered_list(cur_item, 1, 0) @@ -716,7 +718,7 @@ endfunction "Renumbers all lists of the buffer "of course, this might take some seconds -function! vimwiki#lst#adjust_whole_buffer() +function! vimwiki#lst#adjust_whole_buffer() abort let cur_ln = 1 while 1 let cur_item = s:get_item(cur_ln) @@ -736,8 +738,8 @@ endfunction " --------------------------------------------------------- "Returns: the rate of checkboxed list item in percent -function! s:get_rate(item) - if a:item.type == 0 || a:item.cb == '' +function! s:get_rate(item) abort + if a:item.type == 0 || a:item.cb ==? '' return -1 endif let state = a:item.cb @@ -751,7 +753,7 @@ endfunction "Set state of the list item to [ ] or [o] or whatever "Returns: 1 if the state changed, 0 otherwise -function! s:set_state(item, new_rate) +function! s:set_state(item, new_rate) abort 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 @@ -766,7 +768,7 @@ endfunction " Sets the state of the list item to [ ] or [o] or whatever. Updates the states of its child items. " If the new state should be [X] or [-], the state of the current list item is changed to this " state, but if a child item already has [X] or [-] it is left alone. -function! s:set_state_plus_children(item, new_rate, ...) +function! s:set_state_plus_children(item, new_rate, ...) abort 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)) @@ -810,7 +812,7 @@ function! s:set_state_plus_children(item, new_rate, ...) if child_item.type == 0 break endif - if child_item.cb != '' + 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) @@ -819,7 +821,7 @@ endfunction "Returns: the appropriate symbol for a given percent rate -function! s:rate_to_state(rate) +function! s:rate_to_state(rate) abort let listsyms_list = vimwiki#vars#get_syntaxlocal('listsyms_list') let state = '' let n = len(listsyms_list) @@ -839,8 +841,8 @@ endfunction "updates the symbol of a checkboxed item according to the symbols of its "children -function! s:update_state(item) - if a:item.type == 0 || a:item.cb == '' +function! s:update_state(item) abort + if a:item.type == 0 || a:item.cb ==? '' return endif @@ -854,7 +856,7 @@ function! s:update_state(item) if child_item.type == 0 break endif - if child_item.cb != '' + 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 ... @@ -884,7 +886,7 @@ function! s:update_state(item) endfunction -function! s:set_state_recursively(item, new_rate) +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)) @@ -894,8 +896,8 @@ endfunction "Creates checkbox in a list item. "Returns: 1 if successful -function! s:create_cb(item, start_rate) - if a:item.type == 0 || a:item.cb != '' +function! s:create_cb(item, start_rate) abort + if a:item.type == 0 || a:item.cb !=? '' return 0 endif @@ -909,9 +911,9 @@ function! s:create_cb(item, start_rate) endfunction -function! s:remove_cb(item) +function! s:remove_cb(item) abort let item = a:item - if item.type != 0 && item.cb != '' + if item.type != 0 && item.cb !=? '' let item.cb = '' call s:substitute_rx_in_line(item.lnum, '\s\+\[.\]', '') endif @@ -920,7 +922,7 @@ endfunction " Change state of the checkboxes in the lines of the given range -function! s:change_cb(from_line, to_line, new_rate) +function! s:change_cb(from_line, to_line, new_rate) abort let from_item = s:get_corresponding_item(a:from_line) if from_item.type == 0 return @@ -930,7 +932,7 @@ function! s:change_cb(from_line, to_line, new_rate) 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 != '' + 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 @@ -948,13 +950,13 @@ endfunction " Toggles checkbox between two states in the lines of the given range, creates checkboxes (with " a:start_rate as state) if there aren't any. -function! s:toggle_create_cb(from_line, to_line, state1, state2, start_rate) +function! s:toggle_create_cb(from_line, to_line, state1, state2, start_rate) abort let from_item = s:get_corresponding_item(a:from_line) if from_item.type == 0 return endif - if from_item.cb == '' + if from_item.cb ==? '' "if from_line has no CB, make a CB in every selected line let parent_items_of_lines = [] @@ -989,7 +991,7 @@ endfunction "Decrement checkbox between [ ] and [X] "in the lines of the given range -function! vimwiki#lst#decrement_cb(from_line, to_line) +function! vimwiki#lst#decrement_cb(from_line, to_line) abort let from_item = s:get_corresponding_item(a:from_line) if from_item.type == 0 return @@ -1007,7 +1009,7 @@ endfunction "Increment checkbox between [ ] and [X] "in the lines of the given range -function! vimwiki#lst#increment_cb(from_line, to_line) +function! vimwiki#lst#increment_cb(from_line, to_line) abort let from_item = s:get_corresponding_item(a:from_line) if from_item.type == 0 return @@ -1025,19 +1027,19 @@ endfunction "Toggles checkbox between [ ] and [X] or creates one "in the lines of the given range -function! vimwiki#lst#toggle_cb(from_line, to_line) +function! vimwiki#lst#toggle_cb(from_line, to_line) abort return s:toggle_create_cb(a:from_line, a:to_line, 100, 0, 0) endfunction "Toggles checkbox between [ ] and [-] or creates one "in the lines of the given range -function! vimwiki#lst#toggle_rejected_cb(from_line, to_line) +function! vimwiki#lst#toggle_rejected_cb(from_line, to_line) abort return s:toggle_create_cb(a:from_line, a:to_line, -1, 0, -1) endfunction -function! vimwiki#lst#remove_cb(first_line, last_line) +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) @@ -1065,7 +1067,7 @@ function! vimwiki#lst#remove_cb(first_line, last_line) endfunction -function! vimwiki#lst#remove_cb_in_list() +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 @@ -1088,7 +1090,7 @@ endfunction " change the level of list items " --------------------------------------------------------- -function! s:set_indent(lnum, new_indent) +function! s:set_indent(lnum, new_indent) abort if &expandtab let indentstring = repeat(' ', a:new_indent) else @@ -1098,7 +1100,7 @@ function! s:set_indent(lnum, new_indent) endfunction -function! s:decrease_level(item) +function! s:decrease_level(item) abort let removed_indent = 0 if vimwiki#vars#get_syntaxlocal('recurring_bullets') && a:item.type == 1 && \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), @@ -1121,7 +1123,7 @@ function! s:decrease_level(item) endfunction -function! s:increase_level(item) +function! s:increase_level(item) abort let additional_indent = 0 if vimwiki#vars#get_syntaxlocal('recurring_bullets') && a:item.type == 1 && \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), @@ -1145,7 +1147,7 @@ endfunction "adds a:indent_by to the current indent "a:indent_by can be negative -function! s:indent_line_by(lnum, indent_by) +function! s:indent_line_by(lnum, indent_by) abort let item = s:get_item(a:lnum) if vimwiki#vars#get_syntaxlocal('recurring_bullets') && item.type == 1 && \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), @@ -1162,12 +1164,12 @@ endfunction "changes lvl of lines in selection -function! s:change_level(from_line, to_line, direction, plus_children) +function! s:change_level(from_line, to_line, direction, plus_children) abort let from_item = s:get_corresponding_item(a:from_line) if from_item.type == 0 if a:direction ==# 'increase' && a:from_line == a:to_line && empty(getline(a:from_line)) "that's because :> doesn't work on an empty line - normal! gi + exe 'normal!' "gi\" else execute a:from_line.','.a:to_line.(a:direction ==# 'increase' ? '>' : '<') endif @@ -1225,7 +1227,7 @@ function! s:change_level(from_line, to_line, direction, plus_children) endif call s:update_state(old_parent) let from_item = s:get_item(from_item.lnum) - if from_item.cb != '' + if from_item.cb !=? '' call s:update_state(from_item) call s:update_state(s:get_parent(from_item)) endif @@ -1239,7 +1241,7 @@ function! s:change_level(from_line, to_line, direction, plus_children) endfunction -function! vimwiki#lst#change_level(from_line, to_line, direction, plus_children) +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) @@ -1247,7 +1249,7 @@ endfunction "indent line a:lnum to be the continuation of a:prev_item -function! s:indent_multiline(prev_item, lnum) +function! s:indent_multiline(prev_item, lnum) abort if a:prev_item.type != 0 call s:set_indent(a:lnum, s:text_begin(a:prev_item.lnum)) endif @@ -1259,7 +1261,7 @@ endfunction " --------------------------------------------------------- "Returns: the position of a marker in g:vimwiki_list_markers -function! s:get_idx_list_markers(item) +function! s:get_idx_list_markers(item) abort if a:item.type == 1 let m = s:first_char(a:item.mrkr) else @@ -1270,7 +1272,7 @@ endfunction "changes the marker of the given item to the next in g:vimwiki_list_markers -function! s:get_next_mrkr(item) +function! s:get_next_mrkr(item) abort let markers = vimwiki#vars#get_syntaxlocal('list_markers') if a:item.type == 0 let new_mrkr = markers[0] @@ -1283,7 +1285,7 @@ endfunction "changes the marker of the given item to the previous in g:vimwiki_list_markers -function! s:get_prev_mrkr(item) +function! s:get_prev_mrkr(item) abort let markers = vimwiki#vars#get_syntaxlocal('list_markers') if a:item.type == 0 return markers[-1] @@ -1297,7 +1299,7 @@ function! s:get_prev_mrkr(item) endfunction -function! s:set_new_mrkr(item, new_mrkr) +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') @@ -1309,16 +1311,16 @@ function! s:set_new_mrkr(item, new_mrkr) endfunction -function! vimwiki#lst#change_marker(from_line, to_line, new_mrkr, mode) - let cur_col_from_eol = col("$") - (a:mode ==# "i" ? col("'^") : col('.')) +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" + if new_mrkr ==# 'next' let new_mrkr = s:get_next_mrkr(cur_item) - elseif new_mrkr ==# "prev" + elseif new_mrkr ==# 'prev' let new_mrkr = s:get_prev_mrkr(cur_item) endif @@ -1363,7 +1365,7 @@ function! vimwiki#lst#change_marker(from_line, to_line, new_mrkr, mode) endfunction -function! vimwiki#lst#change_marker_in_list(new_mrkr) +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) @@ -1381,7 +1383,7 @@ endfunction "sets kind of the item depending on neighbor items and the parent item -function! s:adjust_mrkr(item) +function! s:adjust_mrkr(item) abort if a:item.type == 0 || vimwiki#vars#get_syntaxlocal('recurring_bullets') return endif @@ -1407,14 +1409,14 @@ function! s:adjust_mrkr(item) endfunction -function! s:clone_marker_from_to(from, to) +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 != '' + 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 @@ -1425,9 +1427,9 @@ function! s:clone_marker_from_to(from, to) endfunction -function! s:remove_mrkr(item) +function! s:remove_mrkr(item) abort let item = a:item - if item.cb != '' + if item.cb !=? '' let item = s:remove_cb(item) let parent_item = s:get_parent(item) else @@ -1442,7 +1444,7 @@ function! s:remove_mrkr(item) endfunction -function! s:create_marker(lnum) +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('.')) @@ -1461,38 +1463,43 @@ endfunction " handle keys " --------------------------------------------------------- -function! vimwiki#lst#kbd_o() +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 - normal! ox - if cur_item.lnum < s:get_last_line_of_item(cur_item) - call s:indent_multiline(cur_item, cur_item.lnum+1) - else - call s:clone_marker_from_to(cur_item.lnum, cur_item.lnum+1) + 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() - normal! Ox +function! vimwiki#lst#kbd_O() abort + exe 'normal!' "Ox\" let cur_ln = line('.') - if getline(cur_ln+1) !~# '^\s*$' - call s:clone_marker_from_to(cur_ln+1, cur_ln) - else - call s:clone_marker_from_to(cur_ln-1, cur_ln) + 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) +function! s:cr_on_empty_list_item(lnum, behavior) abort if a:behavior == 1 "just make a new list item - normal! gi  + exe 'normal!' "gi\\" call s:clone_marker_from_to(a:lnum, a:lnum+1) startinsert! return @@ -1506,7 +1513,7 @@ function! s:cr_on_empty_list_item(lnum, behavior) 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() + 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) @@ -1518,8 +1525,8 @@ function! s:cr_on_empty_list_item(lnum, behavior) 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 + 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) @@ -1534,7 +1541,7 @@ function! s:cr_on_empty_list_item(lnum, behavior) 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() + 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) @@ -1545,21 +1552,28 @@ function! s:cr_on_empty_list_item(lnum, behavior) endif endfunction +function! s:cr_on_empty_line(lnum, behavior) abort + let lst = s:get_corresponding_item(a:lnum) -function! s:cr_on_empty_line(lnum, behavior) "inserting and deleting the x is necessary "because otherwise the indent is lost - normal! gi x + exe 'normal!' "gi\x\\" + if a:behavior == 2 || a:behavior == 3 - call s:create_marker(a:lnum+1) + 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) +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 - normal! gi  + 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) =~# ':$' @@ -1568,14 +1582,14 @@ function! s:cr_on_list_item(lnum, insert_new_marker, not_at_eol) else " || (cur_item.lnum < s:get_last_line_of_item(cur_item)) "indent this line so that it becomes the continuation of the line above - normal! gi  + 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) +function! vimwiki#lst#kbd_cr(normal, just_mrkr) abort let lnum = line('.') let has_bp = s:line_has_marker(lnum) @@ -1594,8 +1608,8 @@ function! vimwiki#lst#kbd_cr(normal, just_mrkr) if getline('.')[col("'^")-1:] =~# '^\s\+$' let cur_col = 0 else - let cur_col = col("$") - col("'^") - if getline('.')[col("'^")-1] =~# '\s' && exists("*strdisplaywidth") + let cur_col = col('$') - col("'^") + if getline('.')[col("'^")-1] =~# '\s' && exists('*strdisplaywidth') let ws_behind_cursor = \ strdisplaywidth(matchstr(getline('.')[col("'^")-1:], '\s\+'), \ virtcol("'^")-1) @@ -1614,7 +1628,7 @@ function! vimwiki#lst#kbd_cr(normal, just_mrkr) call s:cr_on_list_item(lnum, insert_new_marker, cur_col) endif - call cursor(lnum+1, col("$") - cur_col) + call cursor(lnum+1, col('$') - cur_col) if cur_col == 0 startinsert! else @@ -1625,8 +1639,8 @@ endfunction "creates a list item in the current line or removes it -function! vimwiki#lst#toggle_list_item() - let cur_col_from_eol = col("$") - col("'^") +function! vimwiki#lst#toggle_list_item() abort + let cur_col_from_eol = col('$') - col("'^") let cur_item = s:get_item(line('.')) if cur_item.type == 0 @@ -1646,7 +1660,7 @@ function! vimwiki#lst#toggle_list_item() endif "set cursor position s.t. it's on the same char as before - let new_cur_col = col("$") - cur_col_from_eol + 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*$' @@ -1661,7 +1675,7 @@ endfunction " misc stuff " --------------------------------------------------------- -function! vimwiki#lst#TO_list_item(inner, visual) +function! vimwiki#lst#TO_list_item(inner, visual) abort let lnum = prevnonblank('.') let item = s:get_corresponding_item(lnum) if item.type == 0 @@ -1680,7 +1694,7 @@ function! vimwiki#lst#TO_list_item(inner, visual) endfunction -function! vimwiki#lst#fold_level(lnum) +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) @@ -1689,7 +1703,9 @@ function! vimwiki#lst#fold_level(lnum) if child_item.type != 0 return 'a1' elseif next_item.type == 0 - return 's1' + let c_indent = indent(a:lnum) / &shiftwidth + let n_indent = indent(a:lnum+1) / &shiftwidth + return 's' . (c_indent - n_indent) endif endif return '=' diff --git a/autoload/vimwiki/markdown_base.vim b/autoload/vimwiki/markdown_base.vim index f1ce091..bfbd140 100644 --- a/autoload/vimwiki/markdown_base.vim +++ b/autoload/vimwiki/markdown_base.vim @@ -4,14 +4,14 @@ " Home: https://github.com/vimwiki/vimwiki/ -function! s:safesubstitute(text, search, replace, mode) +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() +function! vimwiki#markdown_base#scan_reflinks() abort let mkd_refs = {} " construct list of references using vimgrep try @@ -25,7 +25,7 @@ function! vimwiki#markdown_base#scan_reflinks() 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 != '' + if descr !=? '' && url !=? '' let mkd_refs[descr] = url endif endfor @@ -35,7 +35,7 @@ endfunction " try markdown reference links -function! vimwiki#markdown_base#open_reflink(link) +function! vimwiki#markdown_base#open_reflink(link) abort " echom "vimwiki#markdown_base#open_reflink" let link = a:link let mkd_refs = vimwiki#vars#get_bufferlocal('markdown_refs') @@ -49,7 +49,7 @@ function! vimwiki#markdown_base#open_reflink(link) endfunction -function! s:normalize_link_syntax_n() +function! s:normalize_link_syntax_n() abort let lnum = line('.') " try WikiIncl @@ -97,9 +97,13 @@ function! s:normalize_link_syntax_n() " normalize_link_syntax_v let lnk = vimwiki#base#matchstr_at_cursor(vimwiki#vars#get_global('rxWord')) if !empty(lnk) - let sub = vimwiki#base#normalize_link_helper(lnk, - \ vimwiki#vars#get_global('rxWord'), '', - \ vimwiki#vars#get_syntaxlocal('Weblink1Template')) + 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('Weblink1Template')) + endif call vimwiki#base#replacestr_at_cursor('\V'.lnk, sub) return endif @@ -107,10 +111,10 @@ function! s:normalize_link_syntax_n() endfunction -function! s:normalize_link_syntax_v() +function! s:normalize_link_syntax_v() abort let lnum = line('.') let sel_save = &selection - let &selection = "old" + let &selection = 'old' let rv = @" let rt = getregtype('"') let done = 0 @@ -118,10 +122,18 @@ function! s:normalize_link_syntax_v() try norm! gvy let visual_selection = @" - let link = s:safesubstitute(vimwiki#vars#get_syntaxlocal('Weblink1Template'), - \ '__LinkUrl__', visual_selection, '') - let link = s:safesubstitute(link, '__LinkDescription__', visual_selection, '') + if vimwiki#base#is_diary_file(expand('%:p')) + let link = vimwiki#base#normalize_link_in_diary(visual_selection) + else + let link = s:safesubstitute(vimwiki#vars#get_syntaxlocal('Weblink1Template'), + \ '__LinkUrl__', visual_selection, '') + endif + + " replace spaces with new character if option is set + let link = substitute(link, '\s', vimwiki#vars#get_wikilocal('links_space_char'), 'g') + + let link = s:safesubstitute(link, '__LinkDescription__', visual_selection, '') call setreg('"', substitute(link, '\n', '', ''), visualmode()) " paste result @@ -135,7 +147,7 @@ function! s:normalize_link_syntax_v() endfunction -function! vimwiki#markdown_base#normalize_link(is_visual_mode) +function! vimwiki#markdown_base#normalize_link(is_visual_mode) abort if 0 " Syntax-specific links else diff --git a/autoload/vimwiki/path.vim b/autoload/vimwiki/path.vim index 367b1d7..c0ce8eb 100644 --- a/autoload/vimwiki/path.vim +++ b/autoload/vimwiki/path.vim @@ -4,28 +4,28 @@ " Home: https://github.com/vimwiki/vimwiki/ -function! vimwiki#path#chomp_slash(str) +function! vimwiki#path#chomp_slash(str) abort 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) + function! vimwiki#path#is_equal(p1, p2) abort return a:p1 ==? a:p2 endfunction else - function! vimwiki#path#is_equal(p1, p2) + function! vimwiki#path#is_equal(p1, p2) abort return a:p1 ==# a:p2 endfunction endif - -" collapse sections like /a/b/../c to /a/c -function! vimwiki#path#normalize(path) +" collapse sections like /a/b/../c to /a/c and /a/b/./c to /a/b/c +function! vimwiki#path#normalize(path) abort let path = a:path while 1 - let result = substitute(path, '/[^/]\+/\.\.', '', '') + let intermediateResult = substitute(path, '/[^/]\+/\.\.', '', '') + let result = substitute(intermediateResult, '/\./', '/', '') if result ==# path break endif @@ -35,7 +35,7 @@ function! vimwiki#path#normalize(path) endfunction -function! vimwiki#path#path_norm(path) +function! vimwiki#path#path_norm(path) abort " /-slashes if a:path !~# '^scp:' let path = substitute(a:path, '\', '/', 'g') @@ -49,21 +49,21 @@ function! vimwiki#path#path_norm(path) endfunction -function! vimwiki#path#is_link_to_dir(link) +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) - return vimwiki#path#normalize(expand("%:p:h").'/'.a:link) +function! vimwiki#path#abs_path_of_link(link) abort + return vimwiki#path#normalize(expand('%:p:h').'/'.a:link) endfunction " return longest common path prefix of 2 given paths. " '~/home/usrname/wiki', '~/home/usrname/wiki/shmiki' => '~/home/usrname/wiki' -function! vimwiki#path#path_common_pfx(path1, path2) +function! vimwiki#path#path_common_pfx(path1, path2) abort let p1 = split(a:path1, '[/\\]', 1) let p2 = split(a:path2, '[/\\]', 1) @@ -80,7 +80,7 @@ function! vimwiki#path#path_common_pfx(path1, path2) endfunction -function! vimwiki#path#wikify_path(path) +function! vimwiki#path#wikify_path(path) abort let result = resolve(fnamemodify(a:path, ':p')) if vimwiki#u#is_windows() let result = substitute(result, '\\', '/', 'g') @@ -90,22 +90,41 @@ function! vimwiki#path#wikify_path(path) endfunction -function! vimwiki#path#current_wiki_file() +function! vimwiki#path#current_wiki_file() abort return vimwiki#path#wikify_path(expand('%:p')) endfunction " Returns: the relative path from a:dir to a:file -function! vimwiki#path#relpath(dir, file) +function! vimwiki#path#relpath(dir, file) abort + " Check if dir here ('.') -> return file + if empty(a:dir) || a:dir =~# '^\.[/\\]\?$' + return a:file + endif let result = [] - let dir = split(a:dir, '/') - let file = split(a:file, '/') + if vimwiki#u#is_windows() + " TODO temporary fix see #478 + " not sure why paths get converted back to using forward slash + " when passed to the function in the form C:\path\to\file + let dir = substitute(a:dir, '/', '\', 'g') + let file = substitute(a:file, '/', '\', 'g') + let dir = split(dir, '\') + let file = split(file, '\') + else + let dir = split(a:dir, '/') + let file = split(a:file, '/') + endif while (len(dir) > 0 && len(file) > 0) && vimwiki#path#is_equal(dir[0], file[0]) call remove(dir, 0) call remove(file, 0) endwhile if empty(dir) && empty(file) - return './' + if vimwiki#u#is_windows() + " TODO temporary fix see #478 + return '.\' + else + return './' + endif endif for segment in dir let result += ['..'] @@ -113,9 +132,17 @@ function! vimwiki#path#relpath(dir, file) for segment in file let result += [segment] endfor - let result_path = join(result, '/') - if a:file =~ '\m/$' - let result_path .= '/' + if vimwiki#u#is_windows() + " TODO temporary fix see #478 + let result_path = join(result, '\') + if a:file =~? '\m\\$' + let result_path .= '\' + endif + else + let result_path = join(result, '/') + if a:file =~? '\m/$' + let result_path .= '/' + endif endif return result_path endfunction @@ -124,7 +151,7 @@ endfunction " If the optional argument provided and nonzero, " it will ask before creating a directory " Returns: 1 iff directory exists or successfully created -function! vimwiki#path#mkdir(path, ...) +function! vimwiki#path#mkdir(path, ...) abort let path = expand(a:path) if path =~# '^scp:' @@ -135,26 +162,26 @@ function! vimwiki#path#mkdir(path, ...) if isdirectory(path) return 1 else - if !exists("*mkdir") + if !exists('*mkdir') return 0 endif let path = vimwiki#path#chomp_slash(path) if vimwiki#u#is_windows() && !empty(vimwiki#vars#get_global('w32_dir_enc')) - let path = iconv(path, &enc, vimwiki#vars#get_global('w32_dir_enc')) + 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' + if a:0 && a:1 && input('Vimwiki: Make new directory: '.path."\n [y]es/[N]o? ") !~? '^y' return 0 endif - call mkdir(path, "p") + call mkdir(path, 'p') return 1 endif endfunction -function! vimwiki#path#is_absolute(path) +function! vimwiki#path#is_absolute(path) abort if vimwiki#u#is_windows() return a:path =~? '\m^\a:' else @@ -168,13 +195,13 @@ endfunction " is because on windows ~\vimwiki//.tags is invalid but ~\vimwiki/.tags is a " valid path. if vimwiki#u#is_windows() - function! vimwiki#path#join_path(directory, file) + 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) + function! vimwiki#path#join_path(directory, file) abort let directory = substitute(a:directory, '\m/\+$', '', '') let file = substitute(a:file, '\m^/\+', '', '') return directory . '/' . file diff --git a/autoload/vimwiki/style.css b/autoload/vimwiki/style.css index a5f11b9..43d6b57 100644 --- a/autoload/vimwiki/style.css +++ b/autoload/vimwiki/style.css @@ -1,83 +1,187 @@ -body {font-family: Tahoma, Geneva, sans-serif; margin: 1em 2em 1em 2em; font-size: 100%; line-height: 130%;} -h1, h2, h3, h4, h5, h6 {font-family: Trebuchet MS, Helvetica, sans-serif; font-weight: bold; line-height:100%; margin-top: 1.5em; margin-bottom: 0.5em;} -h1 {font-size: 2.6em; color: #000000;} -h2 {font-size: 2.2em; color: #404040;} -h3 {font-size: 1.8em; color: #707070;} +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.3em; color: #989898;} -h6 {font-size: 1.2em; color: #9c9c9c;} -p, pre, blockquote, table, ul, ol, dl {margin-top: 1em; margin-bottom: 1em;} -ul ul, ul ol, ol ol, ol ul {margin-top: 0.5em; margin-bottom: 0.5em;} -li {margin: 0.3em auto;} -ul {margin-left: 2em; padding-left: 0.5em;} -dt {font-weight: bold;} -img {border: none;} -pre {border-left: 1px solid #ccc; margin-left: 2em; padding-left: 0.5em;} -blockquote {padding: 0.4em; background-color: #f6f5eb;} -th, td {border: 1px solid #ccc; padding: 0.3em;} -th {background-color: #f0f0f0;} -hr {border: none; border-top: 1px solid #ccc; width: 100%;} -del {text-decoration: line-through; color: #777777;} -.toc li {list-style-type: none;} -.todo {font-weight: bold; background-color: #f0ece8; color: #a03020;} -.justleft {text-align: left;} -.justright {text-align: right;} -.justcenter {text-align: center;} -.center {margin-left: auto; margin-right: auto;} -.tag {background-color: #eeeeee; font-family: monospace; padding: 2px;} -.header a {text-decoration: none; color: inherit;} +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; + /* 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; + /* 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; + 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; + 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; + 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; + 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; + font-family: Monaco, "Courier New", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + padding: 0px 3px; + display: inline-block; + color: #52595d; + border: 1px solid #ccc; + background-color: #f9f9f9; } diff --git a/autoload/vimwiki/tags.vim b/autoload/vimwiki/tags.vim index e802bce..b3ac93f 100644 --- a/autoload/vimwiki/tags.vim +++ b/autoload/vimwiki/tags.vim @@ -2,7 +2,7 @@ " Vimwiki autoload plugin file -let s:TAGS_METADATA_FILE_NAME = '.tags' +let s:TAGS_METADATA_FILE_NAME = '.vimwiki_tags' @@ -27,8 +27,8 @@ let s:TAGS_METADATA_FILE_NAME = '.tags' " a:full_rebuild == 1: re-scan entire wiki " a:full_rebuild == 0: only re-scan current page " a:all_files == '': only if the file is newer than .tags -function! vimwiki#tags#update_tags(full_rebuild, all_files) - let all_files = a:all_files != '' +function! vimwiki#tags#update_tags(full_rebuild, all_files) abort + 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') @@ -61,8 +61,15 @@ function! vimwiki#tags#update_tags(full_rebuild, all_files) endfunction +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 + + " Scans the list of text lines (argument) and produces tags metadata as a list of tag entries. -function! s:scan_tags(lines, page_name) +function! s:scan_tags(lines, page_name) abort let entries = [] @@ -81,6 +88,11 @@ function! s:scan_tags(lines, page_name) 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 @@ -96,7 +108,7 @@ function! s:scan_tags(lines, page_name) else let current_complete_anchor = '' for l in range(level-1) - if anchor_level[l] != '' + if anchor_level[l] !=? '' let current_complete_anchor .= anchor_level[l].'#' endif endfor @@ -105,13 +117,11 @@ function! s:scan_tags(lines, page_name) continue " tags are not allowed in headers endif - " TODO ignore verbatim blocks - " Scan line for tags. There can be many of them. let str = line while 1 let tag_group = matchstr(str, rxtag) - if tag_group == '' + if tag_group ==? '' break endif let tagend = matchend(str, rxtag) @@ -155,11 +165,11 @@ function! s:load_tags_metadata() abort endif let metadata = {} for line in readfile(metadata_path) - if line =~ '^!_TAG_FILE_' + if line =~# '^!_TAG_.*$' continue endif let parts = matchlist(line, '^\(.\{-}\);"\(.*\)$') - if parts[0] == '' || parts[1] == '' || parts[2] == '' + if parts[0] ==? '' || parts[1] ==? '' || parts[2] ==? '' throw 'VimwikiTags1: Metadata file corrupted' endif let std_fields = split(parts[1], '\t') @@ -167,11 +177,11 @@ function! s:load_tags_metadata() abort throw 'VimwikiTags2: Metadata file corrupted' endif let vw_part = parts[2] - if vw_part[0] != "\t" + 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:' + if len(vw_fields) != 1 || vw_fields[0] !~# '^vimwiki:' throw 'VimwikiTags4: Metadata file corrupted' endif let vw_data = substitute(vw_fields[0], '^vimwiki:', '', '') @@ -200,7 +210,7 @@ endfunction " Removes all entries for given page from metadata in-place. Returns updated " metadata (just in case). -function! s:remove_page_from_tags(metadata, page_name) +function! s:remove_page_from_tags(metadata, page_name) abort if has_key(a:metadata, a:page_name) call remove(a:metadata, a:page_name) return a:metadata @@ -211,7 +221,7 @@ endfunction " Merges metadata of one file into a:metadata -function! s:merge_tags(metadata, pagename, file_metadata) +function! s:merge_tags(metadata, pagename, file_metadata) abort let metadata = a:metadata let metadata[a:pagename] = a:file_metadata return metadata @@ -227,7 +237,7 @@ endfunction " numbers as strings, not integers, and so, for example, tag at line 14 " preceeds the same tag on the same page at line 9. (Because string "14" is " alphabetically 'less than' string "9".) -function! s:tags_entry_cmp(i1, i2) +function! s:tags_entry_cmp(i1, i2) abort let items = [] for orig_item in [a:i1, a:i2] let fields = split(orig_item, "\t") @@ -251,7 +261,7 @@ endfunction " Saves metadata object into a file. Throws exceptions in case of problems. -function! s:write_tags_metadata(metadata) +function! s:write_tags_metadata(metadata) abort let metadata_path = vimwiki#tags#metadata_file_path() let tags = [] for pagename in keys(a:metadata) @@ -266,18 +276,29 @@ function! s:write_tags_metadata(metadata) \ . pagename . vimwiki#vars#get_wikilocal('ext') . "\t" \ . entry.lineno \ . ';"' - \ . "\t" . "vimwiki:" . entry_data + \ . "\t" . 'vimwiki:' . entry_data \) endfor endfor - call sort(tags, "s:tags_entry_cmp") - call insert(tags, "!_TAG_FILE_SORTED\t1\t") + call sort(tags, 's:tags_entry_cmp') + let tag_comments = [ + \ "!_TAG_PROGRAM_VERSION\t2.5", + \ "!_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 " Returns list of unique tags found in the .tags file -function! vimwiki#tags#get_tags() +function! vimwiki#tags#get_tags() abort let metadata = s:load_tags_metadata() let tags = {} for entries in values(metadata) @@ -292,44 +313,86 @@ endfunction " Similar to vimwiki#base#generate_links. In the current buffer, appends " tags and references to all their instances. If no arguments (tags) are " specified, outputs all tags. -function! vimwiki#tags#generate_tags(...) abort - let need_all_tags = (a:0 == 0) +function! vimwiki#tags#generate_tags(create, ...) abort let specific_tags = a:000 + let header_level = vimwiki#vars#get_global('tags_header_level') - let metadata = s:load_tags_metadata() + " 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 entries in values(metadata) - for entry in entries - if has_key(tags_entries, entry.tagname) - call add(tags_entries[entry.tagname], entry.link) - else - let tags_entries[entry.tagname] = [entry.link] + " make a dictionary { tag_name: [tag_links, ...] } + let tags_entries = {} + for entries in values(metadata) + for entry in entries + if has_key(tags_entries, entry.tagname) + call add(tags_entries[entry.tagname], entry.link) + else + let tags_entries[entry.tagname] = [entry.link] + endif + endfor + unlet entry " needed for older vims with sticky type checking since name is reused + endfor + + let lines = [] + let bullet = repeat(' ', vimwiki#lst#get_list_margin()).vimwiki#lst#default_symbol().' ' + for tagname in sort(keys(tags_entries)) + if need_all_tags || index(self.specific_tags, tagname) != -1 + 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 in sort(tags_entries[tagname]) + 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('Weblink1Template') + let entry = s:safesubstitute(link_tpl, '__LinkUrl__', taglink, '') + let entry = s:safesubstitute(entry, '__LinkDescription__', taglink, '') + else + let link_caption = split(link_infos.anchor, '#', 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, '') + endif + + call add(lines, bullet . entry) + else + let link_tpl = vimwiki#vars#get_global('WikiLinkTemplate1') + call add(lines, bullet . substitute(link_tpl, '__LinkUrl__', taglink, '')) + endif + endfor endif endfor - endfor - let lines = [] - let bullet = repeat(' ', vimwiki#lst#get_list_margin()).vimwiki#lst#default_symbol().' ' - for tagname in sort(keys(tags_entries)) - if need_all_tags || index(specific_tags, tagname) != -1 - call extend(lines, [ - \ '', - \ substitute(vimwiki#vars#get_syntaxlocal('rxH2_Template'), '__Header__', tagname, ''), - \ '' ]) - for taglink in sort(tags_entries[tagname]) - call add(lines, bullet . substitute(vimwiki#vars#get_global('WikiLinkTemplate1'), - \ '__LinkUrl__', taglink, '')) - endfor - endif - endfor + return lines + endfunction - let links_rx = '\m\%(^\s*$\)\|\%('.vimwiki#vars#get_syntaxlocal('rxH2').'\)\|\%(^\s*' - \ .vimwiki#u#escape(vimwiki#lst#default_symbol()).' ' - \ .vimwiki#vars#get_syntaxlocal('rxWikiLink').'$\)' + let tag_match = printf('rxH%d', header_level + 1) + let links_rx = '^\%('.vimwiki#vars#get_syntaxlocal(tag_match).'\)\|'. + \ '\%(^\s*$\)\|\%('.vimwiki#vars#get_syntaxlocal('rxListBullet').'\)' - call vimwiki#base#update_listing_in_buffer(lines, 'Generated Tags', links_rx, line('$')+1, 1) + call vimwiki#base#update_listing_in_buffer( + \ GeneratorTags, + \ vimwiki#vars#get_global('tags_header'), + \ links_rx, + \ line('$')+1, + \ header_level, + \ a:create) endfunction diff --git a/autoload/vimwiki/tbl.vim b/autoload/vimwiki/tbl.vim index 1c049ce..b26a89d 100644 --- a/autoload/vimwiki/tbl.vim +++ b/autoload/vimwiki/tbl.vim @@ -9,23 +9,23 @@ -if exists("g:loaded_vimwiki_tbl_auto") || &cp +if exists('g:loaded_vimwiki_tbl_auto') || &compatible finish endif let g:loaded_vimwiki_tbl_auto = 1 -let s:textwidth = &tw +let s:textwidth = &textwidth -function! s:rxSep() +function! s:rxSep() abort return vimwiki#vars#get_syntaxlocal('rxTableSep') endfunction -function! s:wide_len(str) +function! s:wide_len(str) abort " vim73 has new function that gives correct string width. - if exists("*strdisplaywidth") + if exists('*strdisplaywidth') return strdisplaywidth(a:str) endif @@ -36,8 +36,8 @@ function! s:wide_len(str) let savemodified = &modified let save_cursor = getpos('.') exe "norm! o\" - call setline(line("."), a:str) - let ret = virtcol("$") - 1 + call setline(line('.'), a:str) + let ret = virtcol('$') - 1 d call setpos('.', save_cursor) let &modified = savemodified @@ -46,46 +46,46 @@ function! s:wide_len(str) endfunction -function! s:cell_splitter() +function! s:cell_splitter() abort return '\s*'.s:rxSep().'\s*' endfunction -function! s:sep_splitter() +function! s:sep_splitter() abort return '-'.s:rxSep().'-' endfunction -function! s:is_table(line) +function! s:is_table(line) abort return s:is_separator(a:line) || \ (a:line !~# s:rxSep().s:rxSep() && a:line =~# '^\s*'.s:rxSep().'.\+'.s:rxSep().'\s*$') endfunction -function! s:is_separator(line) - return a:line =~# '^\s*'.s:rxSep().'\(--\+'.s:rxSep().'\)\+\s*$' +function! s:is_separator(line) abort + return a:line =~# '^\s*'.s:rxSep().'\(:\=--\+:\='.s:rxSep().'\)\+\s*$' endfunction -function! s:is_separator_tail(line) +function! s:is_separator_tail(line) abort return a:line =~# '^\{-1}\%(\s*\|-*\)\%('.s:rxSep().'-\+\)\+'.s:rxSep().'\s*$' endfunction -function! s:is_last_column(lnum, cnum) +function! s:is_last_column(lnum, cnum) abort let line = strpart(getline(a:lnum), a:cnum - 1) return line =~# s:rxSep().'\s*$' && line !~# s:rxSep().'.*'.s:rxSep().'\s*$' endfunction -function! s:is_first_column(lnum, cnum) +function! s:is_first_column(lnum, cnum) abort let line = strpart(getline(a:lnum), 0, a:cnum - 1) return line =~# '^\s*$' || \ (line =~# '^\s*'.s:rxSep() && line !~# '^\s*'.s:rxSep().'.*'.s:rxSep()) endfunction -function! s:count_separators_up(lnum) +function! s:count_separators_up(lnum) abort let lnum = a:lnum - 1 while lnum > 1 if !s:is_separator(getline(lnum)) @@ -98,7 +98,7 @@ function! s:count_separators_up(lnum) endfunction -function! s:count_separators_down(lnum) +function! s:count_separators_down(lnum) abort let lnum = a:lnum + 1 while lnum < line('$') if !s:is_separator(getline(lnum)) @@ -111,9 +111,9 @@ function! s:count_separators_down(lnum) endfunction -function! s:create_empty_row(cols) +function! s:create_empty_row(cols) abort let row = s:rxSep() - let cell = " ".s:rxSep() + let cell = ' '.s:rxSep() for c in range(a:cols) let row .= cell @@ -123,9 +123,9 @@ function! s:create_empty_row(cols) endfunction -function! s:create_row_sep(cols) +function! s:create_row_sep(cols) abort let row = s:rxSep() - let cell = "---".s:rxSep() + let cell = '---'.s:rxSep() for c in range(a:cols) let row .= cell @@ -135,66 +135,72 @@ function! s:create_row_sep(cols) endfunction -function! vimwiki#tbl#get_cells(line) +function! vimwiki#tbl#get_cells(line, ...) abort let result = [] - let cell = '' - let quote = '' let state = 'NONE' + let cell_start = 0 + let quote_start = 0 + let len = strlen(a:line) - 1 " 'Simple' FSM - for idx in range(strlen(a:line)) - " The only way I know Vim can do Unicode... - let ch = a:line[idx] - if state ==# 'NONE' - if ch == '|' - let state = 'CELL' - endif - elseif state ==# 'CELL' - if ch == '[' || ch == '{' - let state = 'BEFORE_QUOTE_START' - let quote = ch - elseif ch == '|' - call add(result, vimwiki#u#trim(cell)) - let cell = "" - else - let cell .= ch - endif - elseif state ==# 'BEFORE_QUOTE_START' - if ch == '[' || ch == '{' - let state = 'QUOTE' - let quote .= ch - else - let state = 'CELL' - let cell .= quote.ch - let quote = '' - endif - elseif state ==# 'QUOTE' - if ch == ']' || ch == '}' - let state = 'BEFORE_QUOTE_END' - endif - let quote .= ch - elseif state ==# 'BEFORE_QUOTE_END' - if ch == ']' || ch == '}' - let state = 'CELL' - endif - let cell .= quote.ch - let quote = '' + while state !=# 'CELL' + if quote_start != 0 && state !=# 'CELL' + let state = 'CELL' endif - endfor + for idx in range(quote_start, len) + " The only way I know Vim can do Unicode... + let ch = a:line[idx] + if state ==# 'NONE' + if ch ==# '|' + 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 ==# '|' + let cell = strpart(a:line, cell_start, idx - cell_start) + 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 - if cell.quote != '' - call add(result, vimwiki#u#trim(cell.quote, '|')) - endif return result endfunction -function! s:col_count(lnum) +function! s:col_count(lnum) abort return len(vimwiki#tbl#get_cells(getline(a:lnum))) endfunction -function! s:get_indent(lnum) +function! s:get_indent(lnum, depth) abort if !s:is_table(getline(a:lnum)) return endif @@ -209,50 +215,123 @@ function! s:get_indent(lnum) 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) +function! s:get_rows(lnum, ...) abort if !s:is_table(getline(a:lnum)) return endif - let upper_rows = [] - let lower_rows = [] + let rows = [] let lnum = a:lnum - 1 - while 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 add(upper_rows, [lnum, line]) + call insert(rows, [lnum, line]) else break endif let lnum -= 1 + let ldepth += 1 endwhile - call reverse(upper_rows) let lnum = a:lnum while lnum <= line('$') let line = getline(lnum) if s:is_table(line) - call add(lower_rows, [lnum, line]) + call add(rows, [lnum, line]) else break endif + if depth > 0 + break + endif let lnum += 1 endwhile - return upper_rows + lower_rows + return rows endfunction -function! s:get_cell_max_lens(lnum, ...) +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 = {} - for [lnum, row] in s:get_rows(a:lnum) + let rows = a:0 > 2 ? a:3 : s:get_rows(a:lnum) + for [lnum, row] in rows if s:is_separator(row) continue endif @@ -270,20 +349,67 @@ function! s:get_cell_max_lens(lnum, ...) endfunction -function! s:get_aligned_rows(lnum, col1, col2) - let rows = s:get_rows(a:lnum) - let startlnum = rows[0][0] +function! s:get_aligned_rows(lnum, col1, col2, depth) abort + let rows = [] + let aligns = {} + let startlnum = 0 let cells = [] - for [lnum, row] in rows - call add(cells, vimwiki#tbl#get_cells(row)) - endfor - let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum) + let max_lens = {} + let check_all = 1 + if a:depth > 0 + let rows = s:get_rows(a:lnum, a:depth) + let startlnum = rows[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 = rows[0][0] + let cells = [] + for [lnum, row] in rows + call add(cells, vimwiki#tbl#get_cells(row)) + endfor + let max_lens = s:get_cell_max_lens(a:lnum, cells, startlnum, 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, a:col1, a:col2) + 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, a:col1, a:col2) + let new_row = s:fmt_row(cells[lnum - startlnum], max_lens, aligns, a:col1, a:col2) endif call add(result, [lnum, new_row]) endfor @@ -292,7 +418,7 @@ endfunction " Number of the current column. Starts from 0. -function! s:cur_column() +function! s:cur_column() abort let line = getline('.') if !s:is_table(line) return -1 @@ -312,20 +438,25 @@ function! s:cur_column() endfunction -function! s:fmt_cell(cell, max_len) +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 - - let cell .= repeat(' ', diff) + 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, col1, col2) +function! s:fmt_row(cells, max_lens, aligns, col1, col2) abort let new_line = s:rxSep() for idx in range(len(a:cells)) if idx == a:col1 @@ -334,28 +465,36 @@ function! s:fmt_row(cells, max_lens, col1, col2) let idx = a:col1 endif let value = a:cells[idx] - let new_line .= s:fmt_cell(value, a:max_lens[idx]).s:rxSep() + let new_line .= s:fmt_cell(value, a:max_lens[idx], a:aligns[idx]).s:rxSep() endfor let idx = len(a:cells) while idx < len(a:max_lens) - let new_line .= s:fmt_cell('', a:max_lens[idx]).s:rxSep() + let new_line .= s:fmt_cell('', a:max_lens[idx], a:aligns[idx]).s:rxSep() let idx += 1 endwhile return new_line endfunction -function! s:fmt_cell_sep(max_len) +function! s:fmt_cell_sep(max_len, align) abort + let cell = '' if a:max_len == 0 - return repeat('-', 3) + let cell .= '-' else - return repeat('-', a:max_len+2) + 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, col1, col2) +function! s:fmt_sep(max_lens, aligns, col1, col2) abort let new_line = s:rxSep() for idx in range(len(a:max_lens)) if idx == a:col1 @@ -363,52 +502,59 @@ function! s:fmt_sep(max_lens, col1, col2) elseif idx == a:col2 let idx = a:col1 endif - let new_line .= s:fmt_cell_sep(a:max_lens[idx]).s:rxSep() + let new_line .= s:fmt_cell_sep(a:max_lens[idx], a:aligns[idx]).s:rxSep() endfor return new_line endfunction -function! s:kbd_create_new_row(cols, goto_first) +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('.'))\" + let cmd .= "\:call vimwiki#tbl#format(line('.'), 2)\" let cmd .= "\0" if a:goto_first let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'c', line('.'))\" else - let cmd .= (col('.')-1)."l" + let cmd .= (col('.')-1).'l' let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\" endif - let cmd .= "a" + let cmd .= 'a' return cmd endfunction -function! s:kbd_goto_next_row() +function! s:kbd_goto_next_row() abort let cmd = "\j" let cmd .= ":call search('.\\(".s:rxSep()."\\)', 'c', line('.'))\" let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\" - let cmd .= "a" + let cmd .= 'a' return cmd endfunction -function! s:kbd_goto_prev_row() +function! s:kbd_goto_prev_row() abort let cmd = "\k" let cmd .= ":call search('.\\(".s:rxSep()."\\)', 'c', line('.'))\" let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'bc', line('.'))\" - let cmd .= "a" + let cmd .= 'a' return cmd endfunction " Used in s:kbd_goto_next_col -function! vimwiki#tbl#goto_next_col() +function! vimwiki#tbl#goto_next_col() abort let curcol = virtcol('.') let lnum = line('.') - let newcol = s:get_indent(lnum) - let max_lens = s:get_cell_max_lens(lnum) + let depth = 2 + let newcol = s:get_indent(lnum, depth) + let rows = s:get_rows(lnum, depth) + let startlnum = rows[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 @@ -420,11 +566,11 @@ function! vimwiki#tbl#goto_next_col() endfunction -function! s:kbd_goto_next_col(jumpdown) +function! s:kbd_goto_next_col(jumpdown) abort let cmd = "\" if a:jumpdown let seps = s:count_separators_down(line('.')) - let cmd .= seps."j0" + let cmd .= seps.'j0' endif let cmd .= ":call vimwiki#tbl#goto_next_col()\a" return cmd @@ -432,11 +578,18 @@ endfunction " Used in s:kbd_goto_prev_col -function! vimwiki#tbl#goto_prev_col() +function! vimwiki#tbl#goto_prev_col() abort let curcol = virtcol('.') let lnum = line('.') - let newcol = s:get_indent(lnum) - let max_lens = s:get_cell_max_lens(lnum) + let depth = 2 + let newcol = s:get_indent(lnum, depth) + let rows = s:get_rows(lnum, depth) + let startlnum = rows[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 |... @@ -454,12 +607,12 @@ function! vimwiki#tbl#goto_prev_col() endfunction -function! s:kbd_goto_prev_col(jumpup) +function! s:kbd_goto_prev_col(jumpup) abort let cmd = "\" if a:jumpup let seps = s:count_separators_up(line('.')) - let cmd .= seps."k" - let cmd .= "$" + let cmd .= seps.'k' + let cmd .= '$' endif let cmd .= ":call vimwiki#tbl#goto_prev_col()\a" " let cmd .= ":call search('\\(".s:rxSep()."\\)\\zs', 'b', line('.'))\" @@ -469,10 +622,10 @@ function! s:kbd_goto_prev_col(jumpup) endfunction -function! vimwiki#tbl#kbd_cr() +function! vimwiki#tbl#kbd_cr() abort let lnum = line('.') if !s:is_table(getline(lnum)) - return "" + return '' endif if s:is_separator(getline(lnum+1)) || !s:is_table(getline(lnum+1)) @@ -484,7 +637,7 @@ function! vimwiki#tbl#kbd_cr() endfunction -function! vimwiki#tbl#kbd_tab() +function! vimwiki#tbl#kbd_tab() abort let lnum = line('.') if !s:is_table(getline(lnum)) return "\" @@ -501,7 +654,7 @@ function! vimwiki#tbl#kbd_tab() endfunction -function! vimwiki#tbl#kbd_shift_tab() +function! vimwiki#tbl#kbd_shift_tab() abort let lnum = line('.') if !s:is_table(getline(lnum)) return "\" @@ -511,14 +664,14 @@ function! vimwiki#tbl#kbd_shift_tab() let is_sep = s:is_separator_tail(getline(lnum)) "echomsg "DEBUG kbd_tab> ".first if (is_sep || first) && !s:is_table(getline(lnum-1)) - return "" + return '' endif return s:kbd_goto_prev_col(is_sep || first) endfunction -function! vimwiki#tbl#format(lnum, ...) - if !(&filetype ==? 'vimwiki') +function! vimwiki#tbl#format(lnum, ...) abort + if !vimwiki#u#ft_is_vw() return endif let line = getline(a:lnum) @@ -526,6 +679,8 @@ function! vimwiki#tbl#format(lnum, ...) return endif + let depth = a:0 == 1 ? a:1 : 0 + if a:0 == 2 let col1 = a:1 let col2 = a:2 @@ -534,23 +689,26 @@ function! vimwiki#tbl#format(lnum, ...) let col2 = 0 endif - let indent = s:get_indent(a:lnum) + let indent = s:get_indent(a:lnum, depth) if &expandtab let indentstring = repeat(' ', indent) else - let indentstring = repeat(' ', indent / &tabstop) . repeat(' ', indent % &tabstop) + execute "let indentstring = repeat('\', indent / &tabstop) . repeat(' ', indent % &tabstop)" endif - for [lnum, row] in s:get_aligned_rows(a:lnum, col1, col2) + " 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 - call setline(lnum, row) + if getline(lnum) != row + call setline(lnum, row) + endif endfor - let &tw = s:textwidth + let &textwidth = s:textwidth endfunction -function! vimwiki#tbl#create(...) +function! vimwiki#tbl#create(...) abort if a:0 > 1 let cols = a:1 let rows = a:2 @@ -586,17 +744,17 @@ function! vimwiki#tbl#create(...) endfunction -function! vimwiki#tbl#align_or_cmd(cmd) +function! vimwiki#tbl#align_or_cmd(cmd, ...) abort if s:is_table(getline('.')) - call vimwiki#tbl#format(line('.')) + call call('vimwiki#tbl#format', [line('.')] + a:000) else exe 'normal! '.a:cmd endif endfunction -function! vimwiki#tbl#reset_tw(lnum) - if !(&filetype ==? 'vimwiki') +function! vimwiki#tbl#reset_tw(lnum) abort + if !vimwiki#u#ft_is_vw() return endif let line = getline(a:lnum) @@ -604,13 +762,13 @@ function! vimwiki#tbl#reset_tw(lnum) return endif - let s:textwidth = &tw - let &tw = 0 + let s:textwidth = &textwidth + let &textwidth = 0 endfunction " TODO: move_column_left and move_column_right are good candidates to be refactored. -function! vimwiki#tbl#move_column_left() +function! vimwiki#tbl#move_column_left() abort "echomsg "DEBUG move_column_left: " @@ -645,7 +803,7 @@ function! vimwiki#tbl#move_column_left() endfunction -function! vimwiki#tbl#move_column_right() +function! vimwiki#tbl#move_column_right() abort let line = getline('.') @@ -677,27 +835,27 @@ function! vimwiki#tbl#move_column_right() endfunction -function! vimwiki#tbl#get_rows(lnum) +function! vimwiki#tbl#get_rows(lnum) abort return s:get_rows(a:lnum) endfunction -function! vimwiki#tbl#is_table(line) +function! vimwiki#tbl#is_table(line) abort return s:is_table(a:line) endfunction -function! vimwiki#tbl#is_separator(line) +function! vimwiki#tbl#is_separator(line) abort return s:is_separator(a:line) endfunction -function! vimwiki#tbl#cell_splitter() +function! vimwiki#tbl#cell_splitter() abort return s:cell_splitter() endfunction -function! vimwiki#tbl#sep_splitter() +function! vimwiki#tbl#sep_splitter() abort return s:sep_splitter() endfunction diff --git a/autoload/vimwiki/u.vim b/autoload/vimwiki/u.vim index c8f62ee..08bc896 100644 --- a/autoload/vimwiki/u.vim +++ b/autoload/vimwiki/u.vim @@ -3,7 +3,16 @@ " Description: Utility functions " Home: https://github.com/vimwiki/vimwiki/ -function! vimwiki#u#trim(string, ...) + +" Execute: string v:count times +function! vimwiki#u#count_exe(cmd) abort + for i in range( max([1, v:count]) ) + exe a:cmd + endfor +endfunction + + +function! vimwiki#u#trim(string, ...) abort let chars = '' if a:0 > 0 let chars = a:1 @@ -15,58 +24,134 @@ endfunction " Builtin cursor doesn't work right with unicode characters. -function! vimwiki#u#cursor(lnum, cnum) +function! vimwiki#u#cursor(lnum, cnum) abort exe a:lnum exe 'normal! 0'.a:cnum.'|' endfunction -function! vimwiki#u#is_windows() - return has("win32") || has("win64") || has("win95") || has("win16") +" Returns: OS name, human readable +function! vimwiki#u#os_name() abort + if vimwiki#u#is_windows() + return 'Windows' + elseif vimwiki#u#is_macos() + return 'Mac' + else + return 'Linux' + endif endfunction -function! vimwiki#u#is_macos() - if has("mac") || has("macunix") || has("gui_mac") +function! vimwiki#u#is_windows() abort + return has('win32') || has('win64') || has('win95') || has('win16') +endfunction + + +function! vimwiki#u#is_macos() abort + 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' + return os ==? 'Darwin' || os ==? 'Mac' endfunction -function! vimwiki#u#count_first_sym(line) +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) +function! vimwiki#u#escape(string) abort return escape(a:string, '~.*[]\^$') endfunction " Load concrete Wiki syntax: sets regexes and templates for headers and links -function vimwiki#u#reload_regexes() +function! vimwiki#u#reload_regexes() abort execute 'runtime! syntax/vimwiki_'.vimwiki#vars#get_wikilocal('syntax').'.vim' endfunction " Load syntax-specific functionality -function vimwiki#u#reload_regexes_custom() +function! vimwiki#u#reload_regexes_custom() abort execute 'runtime! syntax/vimwiki_'.vimwiki#vars#get_wikilocal('syntax').'_custom.vim' endfunction " Backward compatible version of the built-in function shiftwidth() if exists('*shiftwidth') - func vimwiki#u#sw() + function! vimwiki#u#sw() abort return shiftwidth() endfunc else - func vimwiki#u#sw() - return &sw + function! vimwiki#u#sw() abort + return &shiftwidth endfunc endif +" 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 +function! vimwiki#u#map_key(mode, key, plug, ...) abort + if a:0 && a:1 == 2 + " global mappings + if !hasmapto(a:plug) && 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) + exe a:mode . 'map ' . a:key . ' ' . a:plug + endif + endif +endfunction + + +" 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 +function! vimwiki#u#is_codeblock(lnum) abort + 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 + +" Sets the filetype to vimwiki +" If g:vimwiki_filetypes variable is set +" the filetype will be vimwiki.. etc. +function! vimwiki#u#ft_set() abort + let ftypelist = vimwiki#vars#get_global('filetypes') + let ftype = 'vimwiki' + for ftypeadd in ftypelist + let ftype = ftype . '.' . ftypeadd + endfor + let &filetype = ftype +endfunction + +" 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 +function! vimwiki#u#ft_is_vw() abort + " Clause: is filetype defined + if &filetype ==# '' | return 0 | endif + if split(&filetype, '\.')[0] ==? 'vimwiki' + return 1 + else + return 0 + endif +endfunction diff --git a/autoload/vimwiki/vars.vim b/autoload/vimwiki/vars.vim index d60a561..f98ddef 100644 --- a/autoload/vimwiki/vars.vim +++ b/autoload/vimwiki/vars.vim @@ -26,7 +26,7 @@ " ------------------------------------------------------------------------------------------------ -function! s:populate_global_variables() +function! s:populate_global_variables() abort let g:vimwiki_global_vars = {} @@ -86,6 +86,7 @@ function! s:populate_global_variables() " 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 . @@ -139,12 +140,16 @@ function! s:populate_global_variables() endfunction -function! s:read_global_settings_from_user() +function! s:read_global_settings_from_user() abort let global_settings = { \ 'CJK_length': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, \ 'auto_chdir': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ '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', @@ -153,24 +158,41 @@ function! s:read_global_settings_from_user() \ 10: 'October', 11: 'November', 12: 'December' \ }}, \ 'dir_link': {'type': type(''), 'default': ''}, - \ 'ext2syntax': {'type': type({}), 'default': {}}, + \ '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, 'links': 1, + \ 'html': 1, 'mouse': 0, + \ }}, \ 'list_ignore_newline': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, \ 'text_ignore_newline': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, + \ 'links_header': {'type': type(''), 'default': 'Generated Links', 'min_length': 1}, + \ 'links_header_level': {'type': type(0), 'default': 1, 'min': 1, 'max': 6}, \ '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}, + \ 'markdown_link_ext': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, \ 'menu': {'type': type(''), 'default': 'Vimwiki'}, \ '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}, \ 'toc_header': {'type': type(''), 'default': 'Contents', 'min_length': 1}, + \ 'toc_header_level': {'type': type(0), 'default': 1, 'min': 1, 'max': 6}, + \ 'toc_link_format': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, \ 'url_maxsave': {'type': type(0), 'default': 15, 'min': 0}, \ 'use_calendar': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, \ 'use_mouse': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, @@ -190,6 +212,8 @@ function! s:read_global_settings_from_user() call s:check_users_value(key, users_value, value_infos, 1) let g:vimwiki_global_vars[key] = users_value + " Remove users_value to prevent type mismatch (E706) errors in vim <7.4.1546 + unlet users_value else let g:vimwiki_global_vars[key] = global_settings[key].default endif @@ -221,27 +245,91 @@ function! s:read_global_settings_from_user() endfunction -function! s:normalize_global_settings() +function! s:normalize_global_settings() abort let keys = keys(g:vimwiki_global_vars.ext2syntax) for ext in keys - " ensure the file extensions in ext2syntax start with a dot - if ext[0] != '.' - let new_ext = '.' . ext - let g:vimwiki_global_vars.ext2syntax[new_ext] = g:vimwiki_global_vars.ext2syntax[ext] - call remove(g:vimwiki_global_vars.ext2syntax, ext) - endif " for convenience, we also allow the term 'mediawiki' if g:vimwiki_global_vars.ext2syntax[ext] ==# 'mediawiki' let g:vimwiki_global_vars.ext2syntax[ext] = 'media' endif + + " ensure the file extensions in ext2syntax start with a dot + " make sure this occurs after anything else that tries to access + " the entry using the index 'ext' since this removes that index + if ext[0] !=# '.' + let new_ext = '.' . ext + let g:vimwiki_global_vars.ext2syntax[new_ext] = g:vimwiki_global_vars.ext2syntax[ext] + call remove(g:vimwiki_global_vars.ext2syntax, ext) + endif endfor + + " ensure key_mappings dictionary has all required keys + if !has_key(g:vimwiki_global_vars.key_mappings, 'all_maps') + let g:vimwiki_global_vars.key_mappings.all_maps = 1 + endif + if !has_key(g:vimwiki_global_vars.key_mappings, 'global') + let g:vimwiki_global_vars.key_mappings.global = 1 + endif + if !has_key(g:vimwiki_global_vars.key_mappings, 'headers') + let g:vimwiki_global_vars.key_mappings.headers = 1 + endif + if !has_key(g:vimwiki_global_vars.key_mappings, 'text_objs') + let g:vimwiki_global_vars.key_mappings.text_objs = 1 + endif + if !has_key(g:vimwiki_global_vars.key_mappings, 'table_format') + let g:vimwiki_global_vars.key_mappings.table_format = 1 + endif + if !has_key(g:vimwiki_global_vars.key_mappings, 'table_mappings') + let g:vimwiki_global_vars.key_mappings.table_mappings = 1 + endif + if !has_key(g:vimwiki_global_vars.key_mappings, 'lists') + let g:vimwiki_global_vars.key_mappings.lists = 1 + endif + if !has_key(g:vimwiki_global_vars.key_mappings, 'links') + let g:vimwiki_global_vars.key_mappings.links = 1 + endif + if !has_key(g:vimwiki_global_vars.key_mappings, 'html') + let g:vimwiki_global_vars.key_mappings.html = 1 + endif + if !has_key(g:vimwiki_global_vars.key_mappings, 'mouse') + let g:vimwiki_global_vars.key_mappings.mouse = 0 + endif + + " disable all key mappings if all_maps == 0 + if !g:vimwiki_global_vars.key_mappings.all_maps + let g:vimwiki_global_vars.key_mappings.global = 0 + let g:vimwiki_global_vars.key_mappings.headers = 0 + let g:vimwiki_global_vars.key_mappings.text_objs = 0 + let g:vimwiki_global_vars.key_mappings.table_format = 0 + let g:vimwiki_global_vars.key_mappings.table_mappings = 0 + let g:vimwiki_global_vars.table_mappings = 0 " kept for backwards compatibility + let g:vimwiki_global_vars.key_mappings.lists = 0 + let g:vimwiki_global_vars.key_mappings.links = 0 + let g:vimwiki_global_vars.key_mappings.html = 0 + let g:vimwiki_global_vars.key_mappings.mouse = 0 + let g:vimwiki_global_vars.use_mouse = 0 " kept for backwards compatibility + endif + + " TODO remove these checks and the table_mappings and use_mouse variables + " backwards compatibility checks + " if the old option isn't its default value then overwrite the new option + if g:vimwiki_global_vars.table_mappings == 0 + let g:vimwiki_global_vars.key_mappings.table_mappings = 0 && g:vimwiki_global_vars.key_mappings.table_mappings == 1 + endif + if g:vimwiki_global_vars.use_mouse == 1 && g:vimwiki_global_vars.key_mappings.mouse == 0 + let g:vimwiki_global_vars.key_mappings.mouse = 1 + endif + endfunction -function! s:populate_wikilocal_options() +let s:margin_set_by_user = 0 +function! s:populate_wikilocal_options() abort let default_values = { \ 'auto_diary_index': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, \ 'auto_export': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'auto_generate_links': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'auto_generate_tags': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, \ 'auto_tags': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, \ 'auto_toc': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, \ 'automatic_nested_syntaxes': {'type': type(0), 'default': 1, 'min': 0, 'max': 1}, @@ -250,12 +338,16 @@ function! s:populate_wikilocal_options() \ 'custom_wiki2html_args': {'type': type(''), 'default': ''}, \ 'diary_header': {'type': type(''), 'default': 'Diary', 'min_length': 1}, \ 'diary_index': {'type': type(''), 'default': 'diary', 'min_length': 1}, - \ 'diary_rel_path': {'type': type(''), 'default': 'diary/', 'min_length': 1}, + \ 'diary_rel_path': {'type': type(''), 'default': 'diary/', 'min_length': 0}, + \ 'diary_caption_level': {'type': type(0), 'default': 0, 'min': -1, 'max': 6}, \ 'diary_sort': {'type': type(''), 'default': 'desc', 'possible_values': ['asc', 'desc']}, + \ 'exclude_files': {'type': type([]), 'default': []}, \ 'ext': {'type': type(''), 'default': '.wiki', 'min_length': 1}, \ 'index': {'type': type(''), 'default': 'index', 'min_length': 1}, + \ 'links_space_char': {'type': type(''), 'default': ' ', 'min_length': 1}, \ 'list_margin': {'type': type(0), 'default': -1, 'min': -1}, \ 'maxhi': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, + \ 'name': {'type': type(''), 'default': ''}, \ 'nested_syntaxes': {'type': type({}), 'default': {}}, \ 'path': {'type': type(''), 'default': $HOME . '/vimwiki/', 'min_length': 1}, \ 'path_html': {'type': type(''), 'default': ''}, @@ -264,6 +356,7 @@ function! s:populate_wikilocal_options() \ 'template_default': {'type': type(''), 'default': 'default', 'min_length': 1}, \ 'template_ext': {'type': type(''), 'default': '.tpl'}, \ 'template_path': {'type': type(''), 'default': $HOME . '/vimwiki/templates/'}, + \ 'html_filename_parameterization': {'type': type(0), 'default': 0, 'min': 0, 'max': 1}, \ } let g:vimwiki_wikilocal_vars = [] @@ -285,6 +378,9 @@ function! s:populate_wikilocal_options() for key in keys(default_values) if has_key(users_wiki_settings, key) call s:check_users_value(key, users_wiki_settings[key], default_values[key], 0) + if key ==# 'list_margin' + let s:margin_set_by_user = 1 + endif let new_wiki_settings[key] = users_wiki_settings[key] else let new_wiki_settings[key] = default_wiki_settings[key] @@ -325,7 +421,7 @@ function! s:populate_wikilocal_options() endfunction -function! s:check_users_value(key, users_value, value_infos, comes_from_global_variable) +function! s:check_users_value(key, users_value, value_infos, comes_from_global_variable) abort let type_code_to_name = { \ type(0): 'number', \ type(''): 'string', @@ -336,50 +432,54 @@ function! s:check_users_value(key, users_value, value_infos, comes_from_global_v \ 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 echom printf('Vimwiki Error: The provided value of the option %s is a %s, ' . - \ 'but expected is a %s. See '':h g:vimwiki_%s''.', setting_origin, + \ '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 echom printf('Vimwiki Error: The provided value ''%i'' of the option %s is' - \ . ' too small. The minimum value is %i. See '':h g:vimwiki_%s''.', a:users_value, + \ . ' 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 echom printf('Vimwiki Error: The provided value ''%i'' of the option %s is' - \ . ' too large. The maximum value is %i. See '':h g:vimwiki_%s''.', a:users_value, + \ . ' 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 echom printf('Vimwiki Error: The provided value ''%s'' of the option %s is' - \ . ' invalid. Allowed values are %s. See ''g:vimwiki_%s''.', a:users_value, + \ . ' 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 echom printf('Vimwiki Error: The provided value ''%s'' of the option %s must' - \ . ' contain exactly %i character(s) but has %i. See '':h g:vimwiki_%s''.', + \ . ' 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 echom printf('Vimwiki Error: The provided value ''%s'' of the option %s must' - \ . ' have at least %d character(s) but has %d. See '':h g:vimwiki_%s''.', a:users_value, + \ . ' 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:normalize_wikilocal_settings() +function! s:normalize_wikilocal_settings() abort for wiki_settings in g:vimwiki_wikilocal_vars let wiki_settings['path'] = s:normalize_path(wiki_settings['path']) @@ -395,7 +495,7 @@ function! s:normalize_wikilocal_settings() let wiki_settings['diary_rel_path'] = s:normalize_path(wiki_settings['diary_rel_path']) let ext = wiki_settings['ext'] - if !empty(ext) && ext[0] != '.' + if !empty(ext) && ext[0] !=# '.' let wiki_settings['ext'] = '.' . ext endif @@ -403,11 +503,17 @@ function! s:normalize_wikilocal_settings() if wiki_settings.syntax ==# 'mediawiki' let wiki_settings.syntax = 'media' endif + + if wiki_settings.syntax ==# 'markdown' && !s:margin_set_by_user + " default list margin to 0 + let wiki_settings.list_margin = 0 + endif + endfor endfunction -function! s:normalize_path(path) +function! s:normalize_path(path) abort " trim trailing / and \ because otherwise resolve() doesn't work quite right let path = substitute(a:path, '[/\\]\+$', '', '') if path !~# '^scp:' @@ -418,7 +524,7 @@ function! s:normalize_path(path) endfunction -function! vimwiki#vars#populate_syntax_vars(syntax) +function! vimwiki#vars#populate_syntax_vars(syntax) abort if !exists('g:vimwiki_syntax_variables') let g:vimwiki_syntax_variables = {} endif @@ -441,6 +547,9 @@ function! vimwiki#vars#populate_syntax_vars(syntax) let g:vimwiki_syntax_variables[a:syntax]['rxH'.i] = \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*[^'.header_symbol.']' \ .header_symbol.'\{'.i.'}\s*$' + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Text'] = + \ '^\s*'.header_symbol.'\{'.i.'}\zs[^'.header_symbol.'].*[^'.header_symbol.']\ze' + \ .header_symbol.'\{'.i.'}\s*$' let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Start'] = \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*[^'.header_symbol.']' \ .header_symbol.'\{'.i.'}\s*$' @@ -457,6 +566,8 @@ function! vimwiki#vars#populate_syntax_vars(syntax) \ repeat(header_symbol, i).' __Header__' let g:vimwiki_syntax_variables[a:syntax]['rxH'.i] = \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*$' + let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Text'] = + \ '^\s*'.header_symbol.'\{'.i.'}\zs[^'.header_symbol.'].*\ze$' let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_Start'] = \ '^\s*'.header_symbol.'\{'.i.'}[^'.header_symbol.'].*$' let g:vimwiki_syntax_variables[a:syntax]['rxH'.i.'_End'] = @@ -527,7 +638,7 @@ function! vimwiki#vars#populate_syntax_vars(syntax) if match(vimwiki#vars#get_global('listsyms'), vimwiki#vars#get_global('listsym_rejected')) != -1 echomsg 'Vimwiki Warning: the value of g:vimwiki_listsym_rejected (''' \ . vimwiki#vars#get_global('listsym_rejected') - \ . ''') must not be a part of g:vimwiki_listsyms (''' . + \ . ''') must not be a part of g:vimwiki_listsyms (''' \ . vimwiki#vars#get_global('listsyms') . ''')' endif let g:vimwiki_syntax_variables[a:syntax].rxListItemWithoutCB = @@ -555,7 +666,7 @@ function! vimwiki#vars#populate_syntax_vars(syntax) " let g:vimwiki_rxWeblink = '[\["(|]\@]*' " 0a) match URL within URL let g:vimwiki_syntax_variables[a:syntax].rxWeblinkMatchUrl = \ g:vimwiki_syntax_variables[a:syntax].rxWeblink @@ -599,7 +710,7 @@ function! vimwiki#vars#populate_syntax_vars(syntax) endfunction -function! s:populate_extra_markdown_vars() +function! s:populate_extra_markdown_vars() abort let mkd_syntax = g:vimwiki_syntax_variables['markdown'] " 0a) match [[URL|DESCRIPTION]] @@ -622,18 +733,6 @@ function! s:populate_extra_markdown_vars() " [DESCRIPTION][URL] let mkd_syntax.WikiLink1Template2 = wikilink_md_prefix. '__LinkDescription__'. \ wikilink_md_separator. '__LinkUrl__'. wikilink_md_suffix - let mkd_syntax.WikiLinkMatchUrlTemplate .= - \ '\|' . - \ mkd_syntax.rx_wikilink_md_prefix . - \ '.*' . - \ rx_wikilink_md_separator . - \ '\zs__LinkUrl__\ze\%(#.*\)\?' . - \ mkd_syntax.rx_wikilink_md_suffix . - \ '\|' . - \ mkd_syntax.rx_wikilink_md_prefix . - \ '\zs__LinkUrl__\ze\%(#.*\)\?' . - \ rx_wikilink_md_separator . - \ mkd_syntax.rx_wikilink_md_suffix let valid_chars = '[^\\\[\]]' let mkd_syntax.rxWikiLink1Url = valid_chars.'\{-}' @@ -686,41 +785,75 @@ function! s:populate_extra_markdown_vars() let mkd_syntax.rxWeblink1Prefix = '[' let mkd_syntax.rxWeblink1Suffix = ')' + let mkd_syntax.rxWeblink1EscapeCharsSuffix = '\(\\\)\@ + + + + + + + + + diff --git a/doc/splash.png b/doc/splash.png new file mode 100644 index 0000000..85c8533 Binary files /dev/null and b/doc/splash.png differ diff --git a/doc/todos.png b/doc/todos.png index 36a2fef..f895de2 100644 Binary files a/doc/todos.png and b/doc/todos.png differ diff --git a/doc/vimwiki.txt b/doc/vimwiki.txt index f9ce7d7..2b9f08a 100644 --- a/doc/vimwiki.txt +++ b/doc/vimwiki.txt @@ -9,7 +9,7 @@ |___| |___| |_| |_||__| |__||___| |___| |_||___| ~ - Version: 2.4.1 + Version: 2.5 ============================================================================== CONTENTS *vimwiki* @@ -57,40 +57,53 @@ CONTENTS *vimwiki* ============================================================================== 1. Intro *vimwiki-intro* -Vimwiki is a personal wiki for Vim -- a number of linked text files that have -their own syntax highlighting. +Vimwiki makes it very easy for you create a personal wiki using the Vim text +editor. A wiki is a collection of text documents linked together and formatted +with wiki or markdown syntax that can be highlighted for readability using +Vim's syntax highlighting feature. With Vimwiki you can: - organize notes and ideas - manage todo-lists - write documentation - maintain a diary - - export everything to HTML + - export your documents to HTML -To do a quick start press ww (this is usually \ww) to go to your index -wiki file. By default it is located in ~/vimwiki/index.wiki +Getting started with Vimwiki is easy. Once intalled, simply type `vim` into +your terminal to launch Vim and then type ww (the key is `\` +by default) to create or open the index wiki file, the "top" page in your +hierarchical collection of wiki pages. By default, this page will be located +at ~/vimwiki/index.wiki. -Feed it with the following example: +Now add the following example lines to the document: = My knowledge base = * Tasks -- things to be done _yesterday_!!! * Project Gutenberg -- good books are power. * Scratchpad -- various temporary stuff. -Place your cursor on 'Tasks' and press Enter to create a link. Once pressed, -'Tasks' will become '[[Tasks]]' -- a Vimwiki link. Press Enter again to -open it. Edit the file, save it, and then press Backspace to jump back to -your index. +Next, move your cursor to the word 'Tasks' and press `Enter`. This will create +a Vimwiki link by surrounding 'Tasks' with double square brackets: +'[[Tasks]]'. Pressing `Enter` a second time will generate a new blank buffer +in Vim where you can input your tasks. After you add some tasks and save the +new file, you can hit `Backspace` to jump back to the index document. -A Vimwiki link can be constructed from more than one word. Just visually -select the words to be linked and press Enter. Try it with 'Project -Gutenberg'. The result should look something like: +A Vimwiki link can contain multiple words by entering Vim's "visual" mode (the +"v" key, by default) and selecting the words to be linked. Once selected, +press `Enter`. + +Try this now by selecting 'Project Gutenberg' in visual mode and hitting +`Enter`. The sample text should now look something like this: = My knowledge base = * [[Tasks]] -- things to be done _yesterday_!!! * [[Project Gutenberg]] -- good books are power. * Scratchpad -- various temporary stuff. +By continuing this way and creating sub pages with links to even more sub +pages, you can create an unlimited number of neatly structured, interconnected +documents to help you organize your notes, documenation, and tasks. + ============================================================================== 2. Prerequisites *vimwiki-prerequisites* @@ -110,21 +123,50 @@ There are global and local mappings in Vimwiki. ------------------------------------------------------------------------------ 3.1. Global mappings *vimwiki-global-mappings* -[count]ww or VimwikiIndex +Below is a list of all default global key mappings provided by Vimwiki. As +global settings, they work in all vim sessions no matter what filetype you +have open. Vimwiki respects pre-existing global mappings created by you or +other plugins and will not overwrite them. + +If a conflict exists between Vimwiki and pre-existing maps or if you wish to +customize these default mappings, you can remap them with: > + + :nmap {map} {command} + +where + `{map}` is the new key sequence of your choosing + `{command}` is the Vimwiki command you are remapping + +So, for example, to remap the |:VimwikiIndex| mapping, you'd do something +like: > + :nmap wx VimwikiIndex + +Note that the recursive version of "map" command is needed to expand the right +hand side to retrieve the definition. "noremap" will not work. is +required and considered to be part of the command. + +You can also place remappings in your vimrc file, without the leading colon, of +course. + + + *vimwiki_ww* +[count]ww Open index file of the [count]'s wiki. - ww opens the first wiki from |g:vimwiki_list|. - 1ww as above, opens the first wiki from |g:vimwiki_list|. + ww opens the first wiki from |g:vimwiki_list| if no wiki is + open. Otherwise the index of the currently active wiki is opened. + 1ww opens the first wiki from |g:vimwiki_list|. 2ww opens the second wiki from |g:vimwiki_list|. 3ww opens the third wiki from |g:vimwiki_list|. etc. - To remap: > - :nmap w VimwikiIndex -< + + Remap command: `VimwikiIndex` + See also |:VimwikiIndex| -[count]wt or VimwikiTabIndex + *vimwiki_wt* +[count]wt Open index file of the [count]'s wiki in a new tab. wt tabopens the first wiki from |g:vimwiki_list|. @@ -132,413 +174,422 @@ See also |:VimwikiIndex| 2wt tabopens the second wiki from |g:vimwiki_list|. 3wt tabopens the third wiki from |g:vimwiki_list|. etc. - To remap: > - :nmap t VimwikiTabIndex -< + + Remap command: `VimwikiTabIndex` + See also |:VimwikiTabIndex| - -ws or VimwikiUISelect + *vimwiki_ws* +ws List and select available wikis. - To remap: > - :nmap wq VimwikiUISelect -< + + Remap command: `VimwikiUISelect` + See also |:VimwikiUISelect| - -[count]wi or VimwikiDiaryIndex + *vimwiki_wi* +[count]wi Open diary index file of the [count]'s wiki. - wi opens diary index file of the first wiki from + wi opens diary index file of the current wiki. + 1wi opens diary index file of the first wiki from |g:vimwiki_list|. - 1wi the same as above. 2wi opens diary index file of the second wiki from |g:vimwiki_list|. etc. - To remap: > - :nmap i VimwikiDiaryIndex + + Remap command: `VimwikiDiaryIndex` See also |:VimwikiDiaryIndex| - -[count]ww or VimwikiMakeDiaryNote + *vimwiki_ww* +[count]ww Open diary wiki-file for today of the [count]'s wiki. - ww opens diary wiki-file for today in the first wiki + ww opens diary wiki-file for today in the current wiki + 1ww opens diary wiki-file for today in the first wiki from |g:vimwiki_list|. - 1ww as above opens diary wiki-file for today in the - first wiki from |g:vimwiki_list|. 2ww opens diary wiki-file for today in the second wiki from |g:vimwiki_list|. 3ww opens diary wiki-file for today in the third wiki from |g:vimwiki_list|. etc. - To remap: > - :nmap d VimwikiMakeDiaryNote -< + + Remap command: `VimwikiMakeDiaryNote` + See also |:VimwikiMakeDiaryNote| -[count]wt or VimwikiTabMakeDiaryNote + *vimwiki_wt* +[count]wt Open diary wiki-file for today of the [count]'s wiki in a new tab. - wt tabopens diary wiki-file for today in the first - wiki from |g:vimwiki_list|. - 1wt as above tabopens diary wiki-file for today in the + wt tabopens diary wiki-file for today in the current + wiki + 1wt tabopens diary wiki-file for today in the first wiki from |g:vimwiki_list|. 2wt tabopens diary wiki-file for today in the second wiki from |g:vimwiki_list|. 3wt tabopens diary wiki-file for today in the third wiki from |g:vimwiki_list|. etc. - To remap: > - :nmap dt VimwikiTabMakeDiaryNote -< + + Remap command: `VimwikiTabMakeDiaryNote` + See also |:VimwikiTabMakeDiaryNote| -[count]wy or VimwikiMakeYesterdayDiaryNote + *vimwiki_wy* +[count]wy Open diary wiki-file for yesterday of the [count]'s wiki. - wy opens diary wiki-file for yesterday in the first + wy opens diary wiki-file for yesterday in the current + wiki + 1wy opens diary wiki-file for yesterday in the first wiki from |g:vimwiki_list|. - 1wy as above opens diary wiki-file for yesterday in - the first wiki from |g:vimwiki_list|. 2wy opens diary wiki-file for yesterday in the second wiki from |g:vimwiki_list|. 3wy opens diary wiki-file for yesterday in the third wiki from |g:vimwiki_list|. etc. - To remap: > - :nmap dy VimwikiMakeYesterdayDiaryNote -< + + Remap command: `VimwikiMakeYesterdayDiaryNote` + See also |:VimwikiMakeYesterdayDiaryNote| -[count]wm or VimwikiMakeTomorrowDiaryNote + *vimwiki_wm* +[count]wm Open diary wiki-file for tomorrow of the [count]'s wiki. - wm opens diary wiki-file for tomorrow in the first + wm opens diary wiki-file for tomorrow in the current + wiki + 1wm opens diary wiki-file for tomorrow in the first wiki from |g:vimwiki_list|. - 1wm as above opens diary wiki-file for tomorrow in - the first wiki from |g:vimwiki_list|. 2wm opens diary wiki-file for tomorrow in the second wiki from |g:vimwiki_list|. 3wm opens diary wiki-file for tomorrow in the third wiki from |g:vimwiki_list|. etc. - To remap: > - :nmap dm VimwikiMakeTomorrowDiaryNote -< + + Remap command: `VimwikiMakeTomorrowDiaryNote` + See also |:VimwikiMakeTomorrowDiaryNote| ------------------------------------------------------------------------------ -3.2. Local mappings +3.2. Local mappings *vimwiki-local-mappings* -To remap one of these keys, either put it in your .vimrc like this > - :nmap wc Vimwiki2HTML -or, the better way, put it in a file .vim/ftplugin/vimwiki.vim like this > - :nmap wc Vimwiki2HTML +Below is a listing of all local key mappings provided by Vimwiki. As local +settings, they are available when |FileType| is set to "vimwiki". These +mappings may overwrite pre-existing mappings, but they can be remapped or +disabled (see |g:vimwiki_key_mappings|). -The latter has the advantage that the mapping is local to Vimwiki buffers in -every case. +To remap commands that begin with , you should do the following: -Also note that some keys work in normal mode as well as in visual mode. If you -remap them using :map, they will also run in operator-pending mode. If you -don't want that, use > - :nmap tt VimwikiToggleListItem - :vmap tt VimwikiToggleListItem + :{mode}map {map} {command} +For commands that do not begin with , do: -NORMAL MODE *vimwiki-local-mappings* - *vimwiki_wh* -wh Convert current wiki page to HTML. + :{mode}noremap {map} {command} + +where + `{mode}` is set to `n` for "normal" mode, `v` for "visual", and `i` for "insert" + `{map}` is the new key sequence of your choosing + `{command}` is the Vimwiki command you are remapping + +Examples: > + :nmap tl VimwikiToggleListItem + :vmap tl VimwikiToggleListItem + :nnoremap glo :VimwikiChangeSymbolTo a) + +The first two lines remap "\tl" to the |:VimwikiToggleListItem| command in both +normal and visual modes. || is set to "\" by default. Use `:echo mapleader` +to determine if it is set to another value. The third map listed +above, which does not contain , maps directly to an |Ex| mode command. + +Note that |map| is needed for commands beginning with . This recursive +version of the "map" command is needed to expand the right hand side to retrieve +the definition. "noremap" will not work. is required and +considered to be part of the command. + +It is recommended that you place your local mappings into a file at +ftplugin/vimwiki.vim within your .vim configuration directory. Create this file +if it doesn't already exist. Or, if you prefer, you can set up a FileType +|autocmd| in your vimrc. + +Note: it may be desirable to add ` ` to mapped commands but +this should only be done if the mappings are placed in ftplugin or in +a Filetype based autocommand. See the Vim help for a description of these +options. + +MAP MODE + *vimwiki_wh* +wh n Convert current wiki page to HTML. Maps to |:Vimwiki2HTML| - To remap: > - :nmap wc Vimwiki2HTML -< - *vimwiki_whh* -whh Convert current wiki page to HTML and open it in the + Remap command: `Vimwiki2HTML` + + *vimwiki_whh* +whh n Convert current wiki page to HTML and open it in the webbrowser. Maps to |:Vimwiki2HTMLBrowse| - To remap: > - :nmap wcc Vimwiki2HTMLBrowse -< - *vimwiki_wi* -wi Update diary section (delete old, insert new) + Remap command: `Vimwiki2HTMLBrowse` + + *vimwiki_wi* +wi n Update diary section (delete old, insert new) Only works from the diary index. Maps to |:VimwikiDiaryGenerateLinks| - To remap: > - :nmap wcr VimwikiDiaryGenerateLinks -< - *vimwiki_* - Follow/create wiki link (create target wiki page if + Remap command: `VimwikiDiaryGenerateLinks` + + *vimwiki_* + n Follow/create wiki link (create target wiki page if needed). Maps to |:VimwikiFollowLink|. - To remap: > - :nmap wf VimwikiFollowLink -< - *vimwiki_* - Split and follow (create target wiki page if needed). + Remap command: `VimwikiFollowLink` + + *vimwiki_* + n Split and follow (create target wiki page if needed). May not work in some terminals. Remapping could help. Maps to |:VimwikiSplitLink|. - To remap: > - :nmap we VimwikiSplitLink -< - *vimwiki_* - Vertical split and follow (create target wiki page if - needed). - May not work in some terminals. Remapping could help. + Remap command: `VimwikiSplitLink` + + *vimwiki_* + n Vertical split and follow (create target wiki page if + needed). May not work in some terminals. Remapping + could help. Maps to |:VimwikiVSplitLink|. - To remap: > - :nmap wq VimwikiVSplitLink -< - *vimwiki_* *vimwiki_* -, Follow wiki link (create target wiki page if needed), + Remap command: `VimwikiVSplitLink` + + *vimwiki_* *vimwiki_* +, n Follow wiki link (create target wiki page if needed), opening in a new tab. May not work in some terminals. Remapping could help. Maps to |:VimwikiTabnewLink|. - To remap: > - :nmap wt VimwikiTabnewLink -< - *vimwiki_* - Go back to previously visited wiki page. + Remap command: `VimwikiTabnewLink` + + *vimwiki_* + n Go back to previously visited wiki page. Maps to |:VimwikiGoBackLink|. - To remap: > - :nmap wb VimwikiGoBackLink -< - *vimwiki_* - Find next link in the current page. + Remap command: `VimwikiGoBackLink` + + *vimwiki_* + n Find next link in the current page. Maps to |:VimwikiNextLink|. - To remap: > - :nmap wn VimwikiNextLink -< - *vimwiki_* - Find previous link in the current page. + Remap command: `VimwikiNextLink` + + *vimwiki_* + n Find previous link in the current page. Maps to |:VimwikiPrevLink|. - To remap: > - :nmap wp VimwikiPrevLink -< - *vimwiki_wd* -wd Delete wiki page you are in. - Maps to |:VimwikiDeleteLink|. - To remap: > - :nmap dd VimwikiDeleteLink -< - *vimwiki_wr* -wr Rename wiki page you are in. - Maps to |:VimwikiRenameLink|. - To remap: > - :nmap rr VimwikiRenameLink -< - *vimwiki_=* -= Add header level. Create if needed. + Remap command: `VimwikiPrevLink` + + *vimwiki_wn* +wn n Goto or create new wiki page. + Maps to |:VimwikiGoto|. + Remap command: `VimwikiGoto` + + *vimwiki_wd* +wd n Delete wiki page you are in. + Maps to |:VimwikiDeleteFile|. + Remap command: `VimwikiDeleteFile` + + *vimwiki_wr* +wr n Rename wiki page you are in. + Maps to |:VimwikiRenameFile|. + Remap command: `VimwikiRenameFile` + + *vimwiki_=* += n Add header level. Create if needed. There is nothing to indent with '==' command in Vimwiki, so it should be ok to use '=' here. - To remap: > - :nmap == VimwikiAddHeaderLevel -< - *vimwiki_-* -- Remove header level. - To remap: > - :nmap -- VimwikiRemoveHeaderLevel -< - *vimwiki_[[* -[[ Go to the previous header in the buffer. - To remap: > - :nmap <- VimwikiGoToPrevHeader -< - *vimwiki_]]* -]] Go to the next header in the buffer. - To remap: > - :nmap -> VimwikiGoToNextHeader -< - *vimwiki_[=* -[= Go to the previous header which has the same level as + Remap command: `VimwikiAddHeaderLevel` + + *vimwiki_-* +- n Remove header level. + Remap command: `VimwikiRemoveHeaderLevel` + + *vimwiki_[[* +[[ n Go to the previous header in the buffer. + Remap command: `VimwikiGoToPrevHeader` + + *vimwiki_]]* +]] n Go to the next header in the buffer. + Remap command: `VimwikiGoToNextHeader` + + *vimwiki_[=* +[= n Go to the previous header which has the same level as the header the cursor is currently under. - To remap: > - :nmap <= VimwikiGoToPrevSiblingHeader -< - *vimwiki_]=* -]= Go to the next header which has the same level as the + Remap command: `VimwikiGoToPrevSiblingHeader` + + *vimwiki_]=* +]= n Go to the next header which has the same level as the header the cursor is currently under. - To remap: > - :nmap => VimwikiGoToNextSiblingHeader -< - *vimwiki_]u* *vimwiki_[u* -]u [u Go one level up -- that is, to the parent header of + Remap command: `VimwikiGoToNextSiblingHeader` + + *vimwiki_]u* *vimwiki_[u* +]u [u n Go one level up -- that is, to the parent header of the header the cursor is currently under. - To remap: > - :nmap -^ VimwikiGoToParentHeader -< - *vimwiki_+* -+ Create and/or decorate links. Depending on the + Remap command: `VimwikiGoToParentHeader` + + *vimwiki_+* ++ n v Create and/or decorate links. Depending on the context, this command will: convert words into wikilinks; convert raw URLs into wikilinks; and add placeholder description text to wiki- or weblinks that are missing descriptions. Can be activated in normal mode with the cursor over a word or link, or in visual mode with the selected text. - To remap: > - :nmap ++ VimwikiNormalizeLink - :vmap ++ VimwikiNormalizeLinkVisual -< - *vimwiki_* - Toggle checkbox of a list item on/off. + Remap commands: + `VimwikiNormalizeLink` (normal mode) + `VimwikiNormalizeLinkVisual` (visual mode) + + *vimwiki_* + n Toggle checkbox of a list item on/off. Maps to |:VimwikiToggleListItem|. See |vimwiki-todo-lists|. - To remap: > - :map tt VimwikiToggleListItem -< - *vimwiki_gl* *vimwiki_gL* -gl Remove checkbox from list item. + Remap command: `VimwikiToggleListItem` + + *vimwiki_gnt* +gnt n Find next unfinished task in the current page. + Maps to |:VimwikiNextTask| + Remap command: `VimwikiNextTask` + + *vimwiki_gl* *vimwiki_gL* +gl n Remove checkbox from list item. + Remap command: `VimwikiRemoveSingleCB` gL Remove checkboxes from all sibling list items. - To remap: > - :map VimwikiRemoveSingleCB - :map VimwikiRemoveCBInList -< - *vimwiki_gln* *vimwiki_glp* -gln Increase the "done" status of a list checkbox, i.e. + Remap command: `VimwikiRemoveCBInList` + + *vimwiki_gln* *vimwiki_glp* +gln n v Increase the "done" status of a list checkbox, i.e. from [ ] to [.] to [o] etc. See |vimwiki-todo-lists|. glp Decrease the "done" status. - To remap: > - :nmap VimwikiIncrementListItem - :vmap VimwikiIncrementListItem - :nmap VimwikiDecrementListItem - :vmap VimwikiDecrementListItem + Remap command: `VimwikiIncrementListItem` - *vimwiki_gll* *vimwiki_gLl* -gll Increase the level of a list item. + *vimwiki_gll* *vimwiki_gLl* +gll n Increase the level of a list item. + Remap commnad: `VimwikiIncreaseLvlSingleItem` gLl Increase the level of a list item and all child items. - To remap: > - :map >> VimwikiIncreaseLvlSingleItem - :map >>> VimwikiIncreaseLvlWholeItem -< - *vimwiki_glh* *vimwiki_gLh* -glh Decrease the level of a list item. + Remap command: `VimwikiIncreaseLvlWholeItem` + + *vimwiki_glh* *vimwiki_gLh* +glh n Decrease the level of a list item. + Remap command: `VimwikiDecreaseLvlSingleItem` gLh Decrease the level of a list item and all child items. - To remap: > - :map << VimwikiDecreaseLvlSingleItem - :map <<< VimwikiDecreaseLvlWholeItem -< - *vimwiki_glr* *vimwiki_gLr* -glr Renumber list items if the cursor is on a numbered + Remap command: `VimwikiDecreaseLvlWholeItem` + + *vimwiki_glr* *vimwiki_gLr* +glr n Renumber list items if the cursor is on a numbered list item. + Remap command: `VimwikiRenumberList` gLr Renumber list items in all numbered lists in the whole - file. - Also readjust checkboxes. - To remap: > - :nmap VimwikiRenumberList - :nmap VimwikiRenumberAllLists -< - *vimwiki_glstar* *vimwiki_gLstar* -gl* Make a list item out of a normal line or change the + file. Also readjust checkboxes. + Remap command: `VimwikiRenumberAllLists` + + *vimwiki_glstar* *vimwiki_gLstar* +gl* n Make a list item out of a normal line or change the symbol of the current item to *. gL* Change the symbol of the current list to *. - To remap: > - noremap glo :VimwikiChangeSymbolTo * + Remap command: `:VimwikiChangeSymbolTo *` noremap glO :VimwikiChangeSymbolInListTo * -< - *vimwiki_gl#* *vimwiki_gL#* -gl# Make a list item out of a normal line or change the + + *vimwiki_gl#* *vimwiki_gL#* +gl# n Make a list item out of a normal line or change the symbol of the current item to #. gL# Change the symbol of the current list to #. - To remap: > - noremap glo :VimwikiChangeSymbolTo # - noremap glO :VimwikiChangeSymbolInListTo # -< - *vimwiki_gl-* *vimwiki_gL-* -gl- Make a list item out of a normal line or change the + Remap command: `:VimwikiChangeSymbolTo #` + Remap command: `:VimwikiChangeSymbolInListTo #` + + *vimwiki_gl-* *vimwiki_gL-* +gl- n Make a list item out of a normal line or change the symbol of the current item to -. + Remap command: `:VimwikiChangeSymbolTo -` gL- Change the symbol of the current list to -. - To remap: > - noremap glo :VimwikiChangeSymbolTo - - noremap glO :VimwikiChangeSymbolInListTo - -< - *vimwiki_gl1* *vimwiki_gL1* -gl1 Make a list item out of a normal line or change the + Remap command: `:VimwikiChangeSymbolInListTo -` + + *vimwiki_gl1* *vimwiki_gL1* +gl1 n Make a list item out of a normal line or change the symbol of the current item to 1., the numbering is adjusted according to the surrounding list items. + Remap command: `:VimwikiChangeSymbolTo 1.` gL1 Change the symbol of the current list to 1. 2. 3. ... - To remap: > - noremap glo :VimwikiChangeSymbolTo 1. - noremap glO :VimwikiChangeSymbolInListTo 1. -< - *vimwiki_gla* *vimwiki_gLa* -gla Make a list item out of a normal line or change the + Remap command: `:VimwikiChangeSymbolInListTo 1.` + + *vimwiki_gla* *vimwiki_gLa* +gla n Make a list item out of a normal line or change the symbol of the current item to a), the numbering is adjusted according to the surrounding list items. + Remap command: `:VimwikiChangeSymbolTo a)` gLa Change the symbol of the current list to a) b) c) ... - To remap: > - noremap glo :VimwikiChangeSymbolTo a) - noremap glO :VimwikiChangeSymbolInListTo a) -< - *vimwiki_glA* *vimwiki_gLA* -glA Make a list item out of a normal line or change the + Remap command: `:VimwikiChangeSymbolInListTo a)` + + *vimwiki_glA* *vimwiki_gLA* +glA n Make a list item out of a normal line or change the symbol of the current item to A), the numbering is adjusted according to the surrounding list items. + Remap command: `:VimwikiChangeSymbolTo A)` gLA Change the symbol of the current list to A) B) C) ... - To remap: > - noremap glo :VimwikiChangeSymbolTo A) - noremap glO :VimwikiChangeSymbolInListTo A) -< - *vimwiki_gli* *vimwiki_gLi* -gli Make a list item out of a normal line or change the + Remap command: `:VimwikiChangeSymbolInListTo A)` + + *vimwiki_gli* *vimwiki_gLi* +gli n Make a list item out of a normal line or change the symbol of the current item to i), the numbering is adjusted according to the surrounding list items. + Remap command: `:VimwikiChangeSymbolTo i)` gLi Change the symbol of the current list to i) ii) iii) ... - To remap: > - noremap glo :VimwikiChangeSymbolTo i) - noremap glO :VimwikiChangeSymbolInListTo i) -< - *vimwiki_glI* *vimwiki_gLI* -glI Make a list item out of a normal line or change the + Remap command: `:VimwikiChangeSymbolInListTo i)` + + *vimwiki_glI* *vimwiki_gLI* +glI n Make a list item out of a normal line or change the symbol of the current item to I), the numbering is adjusted according to the surrounding list items. + Remap command: `:VimwikiChangeSymbolTo I)` gLI Change the symbol of the current list to I) II) III) ... - To remap: > - noremap glo :VimwikiChangeSymbolTo I) - noremap glO :VimwikiChangeSymbolInListTo I) -< - *vimwiki_glx* -glx Toggle checkbox of a list item disabled/off. + Remap command: `:VimwikiChangeSymbolInListTo I)` + + *vimwiki_glx* +glx n Toggle checkbox of a list item disabled/off. Maps to |:VimwikiToggleRejectedListItem|. See |vimwiki-todo-lists|. - To remap: > - :map tx VimwikiToggleRejectedListItem -< - *vimwiki_gqq* *vimwiki_gww* -gqq Format table. If you made some changes to a table - or without swapping insert/normal modes this command -gww will reformat it. + Remap command: `VimwikiToggleRejectedListItem` - *vimwiki_* - Move current table column to the left. + *vimwiki_gqq* *vimwiki_gww* +gqq n Reformats table after making changes. + or Remap command: `VimwikiTableAlignQ` +gww Remap command: `VimwikiTableAlignW` + + *vimwiki_gq1* *vimwiki_gw1* +gq1 n Fast format table. The same as the previous, except + or that only a few lines above the current line are + tested. If the alignment of the current line differs, + then the whole table gets reformatted. + Remap command: `VimwikiTableAlignQ1` +gw1 Remap command:`VimwikiTableAlignW1` + + *vimwiki_* + n Move current table column to the left. See |:VimwikiTableMoveColumnLeft| - To remap: > - :nmap wtl VimwikiTableMoveColumnLeft -< - *vimwiki_* - Move current table column to the right. - See |:VimwikiTableMoveColumnRight| - To remap: > - :nmap wtr VimwikiTableMoveColumnRight -< - *vimwiki_* - Open the previous day's diary link if available. - See |:VimwikiDiaryPrevDay| - To remap: > - :nmap k VimwikiDiaryPrevDay -< - *vimwiki_* - Open the next day's diary link if available. - See |:VimwikiDiaryNextDay| - To remap: > - :nmap j VimwikiDiaryNextDay -< + Remap command: `VimwikiTableMoveColumnLeft` + + *vimwiki_* + n Move current table column to the right. + See |:VimwikiTableMoveColumnRight| + Remap command: `VimwikiTableMoveColumnRight` + + *vimwiki_* + n Open the previous day's diary link if available. + See |:VimwikiDiaryPrevDay| + Remap command: `VimwikiDiaryPrevDay` + + *vimwiki_* + n Open the next day's diary link if available. + See |:VimwikiDiaryNextDay| + Remap command: `VimwikiDiaryNextDay` + +Mouse mappings *vimwiki_mouse* + +These mappings are disabled by default. +See |g:vimwiki_key_mappings| to enable. -Works only if |g:vimwiki_use_mouse| is set to 1. <2-LeftMouse> Follow wiki link (create target wiki page if needed). Split and follow wiki link (create target wiki page if @@ -553,18 +604,17 @@ Note: <2-LeftMouse> is just left double click. -INSERT MODE *vimwiki-table-mappings* - *vimwiki_i__table* +TABLE MAPPINGS, INSERT MODE *vimwiki-table-mappings* + *vimwiki_i__table* Go to the table cell beneath the current one, create a new row if on the last one. - *vimwiki_i__table* + *vimwiki_i__table* Go to the next table cell, create a new row if on the last cell. -See |g:vimwiki_table_mappings| to turn them off. -INSERT MODE *vimwiki-list-mappings* - *vimwiki_i_* +LIST MAPPINGS, INSERT MODE *vimwiki-list-mappings* + *vimwiki_i_* In a list item, insert a new bullet or number in the next line, numbers are incremented. In an empty list item, delete the item symbol. This is @@ -572,39 +622,35 @@ INSERT MODE *vimwiki-list-mappings* See |vimwiki-lists| for details and for how to configure the behavior. - *vimwiki_i_* + *vimwiki_i_* Does not insert a new list item, useful to create - multilined list items. - See |vimwiki-lists| for details and for how to - configure the behavior. + multilined list items. See |vimwiki-lists| for + details and for how to configure the behavior. The + default map may not work in all terminals and may + need to be remapped. - *vimwiki_i_* + *vimwiki_i_* Increase the level of a list item. - To remap: > - :imap VimwikiIncreaseLvlSingleItem -< - *vimwiki_i_* + Remap command: `VimwikiIncreaseLvlSingleItem` + + *vimwiki_i_* Decrease the level of a list item. - To remap: > - :imap VimwikiDecreaseLvlSingleItem -< - *vimwiki_i__* + Remap command: `VimwikiDecreaseLvlSingleItem` + + *vimwiki_i__* Change the symbol of the current list item to the next available. From - to 1. to * to I) to a). - To remap: > - :imap VimwikiListNextSymbol -< - *vimwiki_i__* + Remap command: `VimwikiListNextSymbol` + + *vimwiki_i__* Change the symbol of the current list item to the prev available. From - to a) to I) to * to 1. - To remap: > - :imap VimwikiListPrevSymbol -< - *vimwiki_i__* + Remap command: `VimwikiListPrevSymbol` + + *vimwiki_i__* Create/remove a symbol from a list item. - To remap: > - :imap VimwikiListToggle -< + Remap command: `VimwikiListToggle` + ------------------------------------------------------------------------------ 3.3. Text objects *vimwiki-text-objects* @@ -634,6 +680,29 @@ ic An inner column in a table. al A list item plus its children. il A single list item. +These key mappings can be modified by replacing the default keys: > + + omap ah VimwikiTextObjHeader + vmap ah VimwikiTextObjHeaderV + omap ih VimwikiTextObjHeaderContent + vmap ih VimwikiTextObjHeaderContentV + omap aH VimwikiTextObjHeaderSub + vmap aH VimwikiTextObjHeaderSubV + omap iH VimwikiTextObjHeaderSubContent + vmap iH VimwikiTextObjHeaderSubContentV + omap a\ VimwikiTextObjTableCell + vmap a\ VimwikiTextObjTableCellV + omap i\ VimwikiTextObjTableCellInner + vmap i\ VimwikiTextObjTableCellInnerV + omap ac VimwikiTextObjColumn + vmap ac VimwikiTextObjColumnV + omap ic VimwikiTextObjColumnInner + vmap ic VimwikiTextObjColumnInnerV + omap al VimwikiTextObjListChildren + vmap al VimwikiTextObjListChildrenV + omap il VimwikiTextObjListSingle + vmap il VimwikiTextObjListSingleV + ============================================================================== 4. Commands *vimwiki-commands* @@ -641,29 +710,41 @@ il A single list item. ------------------------------------------------------------------------------ 4.1. Global Commands *vimwiki-global-commands* -*:VimwikiIndex* - Open index file of the current wiki. +*:VimwikiIndex* [count] + Open index file of the current wiki. If a [count] is given the + corresponding wiki from |g:vimwiki_list| is opened instead. -*:VimwikiTabIndex* - Open index file of the current wiki in a new tab. +*:VimwikiTabIndex* [count] + Open index file of the current wiki in a new tab. If a [count] is given + the corresponding wiki from |g:vimwiki_list| is opened instead. *:VimwikiUISelect* - Open index file of the selected wiki. + Displays a list of registered wikis and opens the index file of the + selected wiki. -*:VimwikiDiaryIndex* - Open diary index file of the current wiki. +*:VimwikiDiaryIndex* [count] + Open diary index file of the current wiki. If a [count] is given the + corresponding wiki from |g:vimwiki_list| is opened instead. -*:VimwikiMakeDiaryNote* - Open diary wiki-file for today of the current wiki. +*:VimwikiMakeDiaryNote* [count] + Open diary wiki-file for today of the current wiki. If a [count] is given + a diary wiki-file for the corresponding wiki from |g:vimwiki_list| is + opened instead. -*:VimwikiTabMakeDiaryNote* - Open diary wiki-file for today of the current wiki in a new tab. +*:VimwikiTabMakeDiaryNote* [count] + Open diary wiki-file for today of the current wiki in a new tab. If + a [count] is given a diary wiki-file for the corresponding wiki from + |g:vimwiki_list| is opened instead. -*:VimwikiMakeYesterdayDiaryNote* - Open diary wiki-file for yesterday of the current wiki. +*:VimwikiMakeYesterdayDiaryNote* [count] + Open diary wiki-file for yesterday of the current wiki. If a [count] is + given a diary wiki-file for the corresponding wiki from |g:vimwiki_list| + is opened instead. -*:VimwikiMakeTomorrowDiaryNote* - Open diary wiki-file for tomorrow of the current wiki. +*:VimwikiMakeTomorrowDiaryNote* [count] + Open diary wiki-file for tomorrow of the current wiki. If a [count] is + given a diary wiki-file for the corresponding wiki from |g:vimwiki_list| + is opened instead. ------------------------------------------------------------------------------ 4.2. Local commands *vimwiki-local-commands* @@ -709,14 +790,18 @@ Vimwiki file. :VimwikiGoto HelloWorld < opens/creates HelloWorld wiki page. - Supports |cmdline-completion| for link name. + Supports |cmdline-completion| for link name. If name is not specified, a + prompt will be shown. -*:VimwikiDeleteLink* +*:VimwikiDeleteFile* Delete the wiki page you are in. -*:VimwikiRenameLink* +*:VimwikiRenameFile* Rename the wiki page you are in. +*:VimwikiNextTask* + Jump to the next unfinished task in the current wiki page. + *:Vimwiki2HTML* Convert current wiki page to HTML using Vimwiki's own converter or a user-supplied script (see |vimwiki-option-custom_wiki2html|). @@ -724,10 +809,14 @@ Vimwiki file. *:Vimwiki2HTMLBrowse* Convert current wiki page to HTML and open it in the webbrowser. -*:VimwikiAll2HTML* +*:VimwikiAll2HTML[!]* Convert all wiki pages to HTML. Default CSS file (style.css) is created if there is no one. + By default, only converts wiki pages which have not already been + converted or have been modified since their last conversion. With !, + convert all pages, regardless of whether or not they are out-of-date. + *:VimwikiToggleListItem* Toggle checkbox of a list item on/off. See |vimwiki-todo-lists|. @@ -750,8 +839,8 @@ Vimwiki file. To display previous match use |:lprevious| command. Hint: this feature is simply a wrapper around |:lvimgrep|. For a - description of how the pattern can look like, see |:vimgrep|. For example, - to do a case insensitive search, use > + complete description of the search pattern format, see |:vimgrep|. + For example, to perform a case-insensitive search, use > :VWS /\cpattern/ *:VimwikiBacklinks* @@ -800,8 +889,10 @@ Vimwiki file. Commands are mapped to and respectively. -*:VimwikiGenerateLinks* - Insert the links of all available wiki files into the current buffer. +*:VimwikiGenerateLinks* [pattern] + Insert a list of links to all available wiki files into the current buffer. + If an optional 'pattern' is given as argument, the files will be searched + in the wiki root folder according to the 'pattern' as |globpath| *:VimwikiDiaryGenerateLinks* Delete old, insert new diary section into diary index file. @@ -835,7 +926,7 @@ Vimwiki file. Searches over the pages in current wiki and finds all locations of a given tag. Supports |cmdline-completion|. -*:VimwikiGenerateTags* tagname1 tagname2 ... +*:VimwikiGenerateTagLinks* tagname1 tagname2 ... Creates or updates an overview on all tags of the wiki with links to all their instances. Supports |cmdline-completion|. If no arguments (tags) are specified, outputs all tags. To make this command work properly, make @@ -872,14 +963,28 @@ is decorated: > *bold text* _italic text_ + _*bold italic text*_ + *_bold italic text _* ~~strikeout text~~ `code (no syntax) text` super^script^ sub,,script,, +For Markdown syntax these variations are used: > + + **bold text** or __bold text__ + *italic text* or _italic text_ + ***bold_italic text*** or ___italic_bold text___ + Furthermore, there are a number of words which are highlighted extra flashy: TODO, DONE, STARTED, FIXME, FIXED, XXX. +When rendered as HTML, code blocks containing only a hash prefixed 6 digit hex +number will be colored as themselves. For example > + `#ffe119` +Becomes > + #ffe119 + ------------------------------------------------------------------------------ 5.2. Links *vimwiki-syntax-links* @@ -926,6 +1031,13 @@ or: > The number behind "wiki" is in the range 0..N-1 and identifies the destination wiki in |g:vimwiki_list|. +Named interwiki links are also supported in the format "wn.name:link" > + [[wn.My Name:This is a link]] +or: > + [[wn.MyWiki:This is a link source|Description of the link]] + +See |vimwiki-option-name| to set a per wiki name. + Diary~ The "diary:" scheme is used to link to diary entries: > @@ -1027,9 +1139,6 @@ Inline link: > Image link: > ![Looks like this](URL) -The URL can be anything recognized by Vimwiki as a raw URL. - - Reference-style links: > a) [Link Name][Id] b) [Id][], using the "implicit link name" shortcut @@ -1291,7 +1400,7 @@ have two alternative options: Choose a folder on your hard drive and save MathJax in it. Then add to your HTML template the following line: - + where is the folder on your HD, as a relative path to the template folder. For instance, a sensible folder structure could be: @@ -1305,9 +1414,10 @@ template folder. For instance, a sensible folder structure could be: In this case, would be "../mathjax" (without quotes). 2. Loading MathJax from a CDN-server (needs internet connection). -Add to your HTML template the following line: +Add to your HTML template the following lines: - + + ------------------------------------------------------------------------------ @@ -1371,7 +1481,7 @@ the tags metadata will be auto-updated on each page save. Tags-related commands and options: * |:VimwikiRebuildTags| - * |:VimwikiGenerateTags| + * |:VimwikiGenerateTagLinks| * |:VimwikiSearchTags| * |vimwiki-option-auto_tags| @@ -1379,11 +1489,15 @@ Tags-related commands and options: ============================================================================== 6. Folding/Outline *vimwiki-folding* -Vimwiki can fold or outline sections using headers and preformatted blocks. -Alternatively, one can fold list subitems instead. Folding is not enabled -by default, and requires the |g:vimwiki_folding| variable to be set. +Vimwiki allows you to use Vim's folding methods and options so you can fold +your outline to make it less distracting and easier to navigate. You can use +Vimwiki's built-in folding methods or supply custom methods for folding. You +control how folds behave with by setting the |g:vimwiki_folding| variable to +the desired value in your configuration file: > -Example for list folding with |g:vimwiki_folding| set to 'list': + let g:vimwiki_folding = 'value' + +Here's an example of how folds work with |g:vimwiki_folding| set to 'list': = My current task = * [ ] Do stuff 1 @@ -1425,8 +1539,34 @@ Note: If you use the default Vimwiki syntax, folding on list items will work properly only if all of them are indented using the current 'shiftwidth'. For Markdown and MediaWiki syntax, * or # should be in the first column. -To turn folding on/off check |g:vimwiki_folding|. +For maximum control over folds, set |g:vimwiki_folding| to 'custom' so you can +allow other plugins or your vim configuration file to control how folding is +performed. For example, let's say you are using markdown syntax and prefer to +fold so that the last blank line before a header is not folded, you can add +this function to your configuration file: > + function! VimwikiFoldLevelCustom(lnum) + let pounds = strlen(matchstr(getline(a:lnum), '^#\+')) + if (pounds) + return '>' . pounds " start a fold level + endif + if getline(a:lnum) =~? '\v^\s*$' + if (strlen(matchstr(getline(a:lnum + 1), '^#\+'))) + return '-1' " don't fold last blank line before header + endif + endif + return '=' " return previous fold level + endfunction + +Note that you will also need to add the following vim options to your configuration: > + + augroup VimrcAuGroup + autocmd! + autocmd FileType vimwiki setlocal foldmethod=expr | + \ setlocal foldenable | set foldexpr=VimwikiFoldLevelCustom(v:lnum) + augroup END + +See the |g:vimwiki_folding| documentation for more details. ============================================================================== 7. Placeholders *vimwiki-placeholders* @@ -1481,16 +1621,26 @@ used. While writing lists, the keys , o and O insert new bullets or numbers as you would expect it. A new bullet/number is inserted if and only if the cursor -is in a list item. To make a list item with more than one line, press -or press and . +is in a list item. If you use hard line wraps within your lists then you will +need to remap `` to `VimwikiReturn 3 5`, use , or press and +. + Note that the mapping is not available in all terminals. Furthermore, and behave differently when the cursor is behind an empty list item. See the table below. -You can configure the behavior of and of like this: > - inoremap :VimwikiReturn 1 5 - inoremap :VimwikiReturn 2 2 +To customize the behavior you should use an autocmd or place the mappings in +`~/.vim/after/ftplugin/vimwiki.vim`. This is necessary to avoid an error that +the command `VimwikiReturn` doesn't exist when editing non Vimwiki files.: > + + autocmd FileType vimwiki inoremap + \ :VimwikiReturn 3 5 + autocmd FileType vimwiki inoremap + \ :VimwikiReturn 2 2 + +Note: Prefixing the mapping with `` expands iabbrev definitions and +requires Vim > 7.3.489. The first argument of the command :VimwikiReturn is a number that specifies when to insert a new bullet/number and when not, depending on whether the @@ -1600,11 +1750,11 @@ normal text followed by a parenthesis. Roman numerals go up to MMMM) and numbers up to 2147483647. or 9223372036854775807. depending if your Vim is 32 or 64 bit. -Also note that you can, of course, mix different list symbols in one list, but -if you have the strange idea of putting a list with Romanian numerals right -after a list using letters or vice versa, Vimwiki will get confused because -it cannot distinguish which is which (at least if the types are both upper -case or both lower case). +Also, note that you can, of course, mix different list symbols in one list, but +if you have the strange idea of putting a list with Roman numerals right after +a list using letters or vice versa, Vimwiki will get confused because it +cannot distinguish which is which (at least if the types are both upper case +or both lower case). See |vimwiki_glstar|, |vimwiki_gl#| |vimwiki_gl-|, |vimwiki_gl-|, |vimwiki_gl1|, |vimwiki_gla|, |vimwiki_glA|, |vimwiki_gli|, |vimwiki_glI| @@ -1625,7 +1775,7 @@ Consider the following example: > * [X] Simple toggling between [ ] and [X]. * [X] All list's subitems should be toggled on/off appropriately. * [X] Toggle child subitems only if current line is list item - * [X] Parent list item should be toggled depending on it's child items. + * [X] Parent list item should be toggled depending on its child items. * [X] Make numbered list items toggleable too * [X] Add highlighting to list item boxes * [X] Add [ ] to the next list item created with o, O and . @@ -1649,7 +1799,7 @@ parent items: > * [ ] Simple toggling between [ ] and [X]. * [X] All of a list's subitems should be toggled on/off appropriately. * [ ] Toggle child subitems only if current line is list item. - * [ ] Parent list item should be toggled depending on it's child items. + * [ ] Parent list item should be toggled depending on its child items. * [ ] Make numbered list items toggleable too. * [ ] Add highlighting to list item boxes. * [ ] Add [ ] to the next list item created using o, O or . @@ -1715,6 +1865,15 @@ values: > To indent table indent the first row. Then format it with 'gqq'. +You can specify the type of horizontal alignment for columns in the separator +using the ':' character. The default is left-align. > + + | Date | Item | Price | + |------------|:------:|--------:| + | yest | Coffee | $15.00 | + | 2017-02-13 | Tea | $2.10 | + | 2017-03-14 | Cake | $143.12 | +< ============================================================================== 10. Diary *vimwiki-diary* @@ -1753,6 +1912,16 @@ Get it from http://www.vim.org/scripts/script.php?script_id=52 See |g:vimwiki_use_calendar| option to turn it off/on. +------------------------------------------------------------------------------ +Markdown export + +If you use markdown as the syntax for your wiki, there is a rubygem available +at https://github.com/patrickdavey/vimwiki_markdown which you can use to +convert the wiki markdown files into html. + +Also, See |vimwiki-option-html_filename_parameterization| for supporting +functionality. + ============================================================================== 11. Anchors *vimwiki-anchors* @@ -1946,6 +2115,24 @@ If path_html is an empty string, the location is derived from path_html will be set to '~/okidoki_html/'. +*vimwiki-option-name* +------------------------------------------------------------------------------ +Key Default value~ +name '' + +Description~ +A name that can be used to create interwiki links: > + let g:vimwiki_list = [{'path': '~/my_site/', + \ 'name': 'My Wiki'}] + +Valid names can contain letters, numbers, spaces, underscores, and dashes. +If duplicate names are used the interwiki link will jump to the first wiki +with a matching name in |g:vimwiki_list|. + +The assigned wiki name will also be shown in the menu entries in GVim. +See the option |g:vimwiki_menu|. + + *vimwiki-option-auto_export* ------------------------------------------------------------------------------ Key Default value Values~ @@ -2006,6 +2193,21 @@ converted to HTML at the moment. To use Markdown's wiki markup: > let g:vimwiki_list = [{'path': '~/my_site/', \ 'syntax': 'markdown', 'ext': '.md'}] + +*vimwiki-option-links_space_char* +------------------------------------------------------------------------------ +Key Default value~ +links_space_char ' ' + +Description~ +Set the character (or string) used to replace spaces when creating a link. For +example, setting '_' would transform the string 'my link' into [[my_link]] and +the created file would be my_link.wiki. The default behavior does not replace +spaces. + +To set the space replacement character: > + let g:vimwiki_list = [{'path': '~/my_site/', + \ 'links_space_char': '_'}] < *vimwiki-option-template_path* @@ -2043,13 +2245,17 @@ Each template could look like: > where - %title% is replaced by a wiki page name or by a |vimwiki-title| - %date% is replaced with the current date or by |vimwiki-date| - %root_path% is replaced by a count of ../ for pages buried in subdirs: + `%title%` is replaced by a wiki page name or by a |vimwiki-title| + `%date%` is replaced with the current date or by |vimwiki-date| + `%root_path%` is replaced by a count of ../ for pages buried in subdirs: if you have wikilink [[dir1/dir2/dir3/my page in a subdir]] then - %root_path% is replaced by '../../../'. + `%root_path%` is replaced by '../../../'. + `%wiki_path%` Path to current wiki-file.` The file path to the current wiki + file. For example, if you are on page a/b.wiki %wiki-path% contains + "a/b.wiki". Mostly useful if you want to link the to raw wiki page from + the rendered version. - %content% is replaced by a wiki file content. + `%content%` is replaced by a wiki file content. The default template will be applied to all wiki pages unless a page specifies @@ -2213,13 +2419,33 @@ Description~ Sort links in a diary index page. +*vimwiki-option-diary_caption_level* +------------------------------------------------------------------------------ +Key Default value~ +diary_caption_level 0 + +Description~ +Controls the presence of captions in the diary index linking to headers within +the diary pages. + +Possible values: +-1: No headers are read from the diary page. + 0: The first header from the diary page is used as the caption. + There are no sub-captions. + 1: Captions are created for headers of level 1 in the diary page. + 2: Captions are created for headers up to level 2 in the diary page. + etc. + +When the value is >= 1, the primary caption of each diary page is set to the +first header read from that page if it is the unique lowest-level header. + *vimwiki-option-custom_wiki2html* ------------------------------------------------------------------------------ Key Default value~ custom_wiki2html '' Description~ -The full path to an user-provided script that converts a wiki page to HTML. +The full path to a user-provided script that converts a wiki page to HTML. Vimwiki calls the provided |vimwiki-option-custom_wiki2html| script from the command-line, using |:!| invocation. @@ -2269,7 +2495,7 @@ parameters can be passed using this option: > *vimwiki-option-list_margin* ------------------------------------------------------------------------------ Key Default value~ -list_margin -1 +list_margin -1 (0 for markdown) Description~ Width of left-hand margin for lists. When negative, the current 'shiftwidth' @@ -2306,6 +2532,54 @@ See |:VimwikiDiaryGenerateLinks|: > let g:vimwiki_list = [{'path': '~/my_site/', 'auto_diary_index': 1}] +*vimwiki-option-auto_generate_links* +------------------------------------------------------------------------------ +Key Default value Values~ +auto_generate_links 0 0, 1 + +Description~ +Set this option to 1 to automatically update generated links when the +current wiki page is saved: > + let g:vimwiki_list = [{'path': '~/my_site/', 'auto_generate_links': 1}] + + +*vimwiki-option-auto_generate_tags* +------------------------------------------------------------------------------ +Key Default value Values~ +auto_generate_tags 0 0, 1 + +Description~ +Set this option to 1 to automatically update generated tags when the +current wiki page is saved: > + let g:vimwiki_list = [{'path': '~/my_site/', 'auto_generate_tags': 1}] + + +*vimwiki-option-exclude_files* +------------------------------------------------------------------------------ +Key Default value Values~ +exclude_files [] list of file patterns to exclude + +Description~ +Set this option to a list of file patterns to exclude when checking or +generating links: > + let g:vimwiki_list = [{'path': '~/my_site/', 'exclude_files': ['**/README.md']}] + + +*vimwiki-option-html_filename_parameterization* +------------------------------------------------------------------------------ +Key Default value Values~ +html_filename_parameterization 0 0, 1 + +Description~ +This setting is for integration with the vimwiki_markdown gem. If this is set +to 1 it alters the check for generated html filenames to match what +vimwiki_markdown generates. This means that it prevents unnecessary +regeneration of HTML files. + +This setting also turns off the automatic deletion of files +in the site_html directory which don't match existing wiki files. + + ------------------------------------------------------------------------------ 12.4 Global Options *vimwiki-global-options* @@ -2385,18 +2659,27 @@ E.g.: > \ '.mkd': 'markdown', \ '.wiki': 'media'} -An extension that is registered with Vimwiki can trigger creation of a -|vimwiki-temporary-wiki| with the associated syntax. File extensions used in -|g:vimwiki_list| are automatically registered with Vimwiki using the default -syntax. +An extension that is registered with Vimwiki can trigger creation of +a |vimwiki-temporary-wiki|. File extensions used in |g:vimwiki_list| are +automatically registered with Vimwiki using the default syntax. Extensions +mapped with this option will instead use the mapped syntax. -Default: {} +Default: > + {'.md': 'markdown', '.mkdn': 'markdown', + \ '.mdwn': 'markdown', '.mdown': 'markdown', + \ '.markdown': 'markdown', '.mw': 'media'}}, +Note: setting this option will overwrite the default values so include them if +desired. ------------------------------------------------------------------------------ *g:vimwiki_menu* Create a menu in the menu bar of GVim, where you can open the available wikis. +If the wiki has an assigned name (see |vimwiki-option-name|), the menu entry +will match the name. Otherwise, the final folder of |vimwiki-option-path| will +be used for the name. If there are duplicate entries the index number from +|g:vimwiki_list| will be appended to the name. Value Description~ '' No menu @@ -2434,31 +2717,19 @@ You can set it to a more fancy symbol like this: let g:vimwiki_listsym_rejected = '✗' ------------------------------------------------------------------------------- -*g:vimwiki_use_mouse* - -Use local mouse mappings from |vimwiki-local-mappings|. - -Value Description~ -0 Do not use mouse mappings. -1 Use mouse mappings. - -Default: 0 - - ------------------------------------------------------------------------------ *g:vimwiki_folding* Enable/disable Vimwiki's folding (outline) functionality. Folding in Vimwiki -can uses either the 'expr' or the 'syntax' |foldmethod| of Vim. +can use either the 'expr' or the 'syntax' |foldmethod| of Vim. Value Description~ '' Disable folding 'expr' Folding based on expression (folds sections and code blocks) 'syntax' Folding based on syntax (folds sections; slower than 'expr') 'list' Folding based on expression (folds list subitems; much slower) -'custom' Leave the folding settings as they are (e.g. set by another - plugin) +'custom' Allow folding options to be set by another plugin or a vim + configuration file Default: '' @@ -2510,6 +2781,31 @@ Value Description~ Default: 1 +------------------------------------------------------------------------------ +*g:vimwiki_create_link* + +Create target wiki page if it does not exist. See |:VimwikiFollowLink|. + +Value Description~ +0 Do not create target wiki page. +1 Create target wiki page. + +Default: 1 + + +------------------------------------------------------------------------------ +*g:vimwiki_markdown_link_ext* + +Append wiki file extension to links in Markdown. This is needed for +compatibility with other Markdown tools. + +Value Description~ +0 Do not append wiki file extension. +1 Append wiki file extension. + +Default: 0 + + ------------------------------------------------------------------------------ *VimwikiLinkHandler* @@ -2619,18 +2915,6 @@ cannot otherwise convert the link. A customized handler might look like this: > endfunction < ------------------------------------------------------------------------------- -*g:vimwiki_table_mappings* - -Enable/disable table mappings for INSERT mode. - -Value Description~ -0 Disable table mappings. -1 Enable table mappings. - -Default: 1 - - ------------------------------------------------------------------------------ *g:vimwiki_table_auto_fmt* @@ -2643,6 +2927,21 @@ Value Description~ Default: 1 +------------------------------------------------------------------------------ +*g:vimwiki_table_reduce_last_col* + +If set, the last column separator will not be expanded to fill the cell. When +`:set wrap` this option improves how a table is displayed, particularly on +small screens. If |g:vimwiki_table_auto_fmt| is set to 0, this option has no +effect. + +Value Description~ +0 Enable table auto formating for all columns. +1 Disable table auto formating for the last column. + +Default: 0 + + ------------------------------------------------------------------------------ *g:vimwiki_w32_dir_enc* @@ -2796,11 +3095,42 @@ URLs and hides markers and URL for links that have a description. Default: 2 +------------------------------------------------------------------------------ +*g:vimwiki_conceal_onechar_markers* + +Control the concealment of one-character markers. + +Setting 'conceal_onechar_markers' to 0 will show the markers, overriding +whatever value is set in |g:vimwiki_conceallevel| + +Default: 1 + + +------------------------------------------------------------------------------ +*g:vimwiki_conceal_pre* + +Conceal preformatted text markers. For example, +> + {{{python + def say_hello(): + print("Hello, world!") + }}} +> +would appear as simply +> + def say_hello(): + print("Hello, world!") +> +in your wiki file. + +Default: 0 + + ------------------------------------------------------------------------------ *g:vimwiki_autowriteall* Automatically save a modified wiki buffer when switching wiki pages. Has the -same effect like setting the Vim option 'autowriteall', but it works for wiki +same effect as setting the Vim option 'autowriteall', but it works for wiki files only, while the Vim option is global. Hint: if you're just annoyed that you have to save files manually to switch wiki pages, consider setting the Vim option 'hidden' which makes that modified @@ -2818,7 +3148,8 @@ Default: 1 Setting the value of |g:vimwiki_url_maxsave| to 0 will prevent any link shortening: you will see the full URL in all types of links, with no parts -being concealed. Concealing of one-character markers is not affected. +being concealed. This option does not affect the concealing of wiki elements +such as bold, italic, wikilinks, etc. When positive, the value determines the maximum number of characters that are retained at the end after concealing the middle part of a long URL. @@ -2872,6 +3203,30 @@ appropriate word in your mother tongue like this: > The default is 'Contents'. +------------------------------------------------------------------------------ +*g:vimwiki_toc_header_level* + +The header level of the Table of Contents (see |vimwiki-toc|). Valid values +are from 1 to 6. + +The default is 1. + + +------------------------------------------------------------------------------ +*g:vimwiki_toc_link_format* + +The format of the links in the Table of Contents (see |vimwiki-toc|). + + +Value Description~ +0 Extended: The link contains the description and URL. URL + references all levels. +1 Brief: The link contains only the URL. URL references only + the immediate level. + +Default: 0 + + ------------------------------------------------------------------------------ *g:vimwiki_map_prefix* @@ -2886,16 +3241,165 @@ The default is 'w'. ------------------------------------------------------------------------------ *g:vimwiki_auto_chdir* -When set to 1, enables auto-cd feature. Whenever Vimwiki page is opened, -Vimwiki performs an |:lcd| to the Vimwiki folder to where the page belongs. +When set to 1, enables auto-cd feature. Whenever Vimwiki page is opened, +Vimwiki performs an |:lcd| to the root Vimwiki folder of the page's wiki. Value Description~ 0 Do not change directory. -1 Change directory to Vimwiki folder on opening page. +1 Change directory to root Vimwiki folder on opening page. Default: 0 + +------------------------------------------------------------------------------ +*g:vimwiki_links_header* + +A string with the magic header that tells Vimwiki where the generated links +are located in a file. You can change it to the appropriate word in your +mother tongue like this: > + let g:vimwiki_links_header = 'Generierte Links' + +The default is 'Generated Links'. + + +------------------------------------------------------------------------------ +*g:vimwiki_links_header_level* + +The header level of generated links. Valid values are from 1 to 6. + +The default is 1. + + +------------------------------------------------------------------------------ +*g:vimwiki_tags_header* + +A string with the magic header that tells Vimwiki where the generated tags +are located in a file. You can change it to the appropriate word in your +mother tongue like this: > + let g:vimwiki_tags_header = 'Generierte Stichworte' + +The default is 'Generated Tags'. + + +------------------------------------------------------------------------------ +*g:vimwiki_tags_header_level* + +The header level of generated tags. Valid values are from 1 to 5. + +The default is 1. + + +------------------------------------------------------------------------------ +*g:vimwiki_markdown_header_style* + +The number of newlines to be inserted after a header is generated. Valid +values are from 0 to 2. + +The default is 1. + + +------------------------------------------------------------------------------ +*g:vimwiki_auto_header* + +Set this option to 1 to automatically generate a level 1 header when creating +a new wiki page. This option is disabled for the wiki index and the diary +index. Spaces replaced with |vimwiki-option-links_space_char| are reverted +back to spaces in the generated header, which will match the filename +except for the characters that were reverted to spaces. + +For example, with `links_space_char` set to `'_'` creating a link from the text +`foo bar link` would result in `[[foo_bar_link]]` and the file +`foo_bar_link.wiki`. The generated header would be `= foo bar link =` + +The default is 0. + + +------------------------------------------------------------------------------ +*g:vimwiki_key_mappings* + +A dictionary that is used to enable/disable various key mapping groups. To +disable a specific group set the value for the associated key to 0. +For example: > + + let g:vimwiki_key_mappings = + \ { + \ 'headers': 0, + \ 'text_objs': 0, + \ } + +To disable ALL Vimwiki key mappings use: > + + let g:vimwiki_key_mappings = { 'all_maps': 0, } + +The valid key groups and their associated mappings are shown below. + +`all_maps`: + Used to disable all Vimwiki key mappings. +`global`: + |vimwiki-global-mappings| that are defined when Vim starts. +`headers`: + Mappings for header navigation and manipulation: + |vimwiki_=|, |vimwiki_-|, |vimwiki_[[|, |vimwiki_]]|, |vimwiki_[=| + |vimwiki_]=|, |vimwiki_]u| , |vimwiki_[u| +`text_objs`: + |vimwiki-text-objects| mappings. +`table_format`: + Mappings used for table formatting. + |vimwiki_gqq|, |vimwiki_gww|, |vimwiki_gq1|, |vimwiki_gw1| + |vimwiki_|, |vimwiki_| +`table_mappings`: + Table mappings for insert mode. + |vimwiki_|, |vimwiki_| +`lists`: + Mappings for list manipulation. + |vimwiki_|, |vimwiki_gl|, |vimwiki_gL| |vimwiki_gln|, |vimwiki_glp| + |vimwiki_gll|, |vimwiki_gLl|, |vimwiki_glh|, |vimwiki_gLh|, |vimwiki_glr|, |vimwiki_gLr| + |vimwiki_glsar|, |vimwiki_gLstar|, |vimwiki_gl#|, |vimwiki_gL#|, |vimwiki_gl-|, |vimwiki_gL-| + |vimwiki_gl1|, |vimwiki_gL1|, |vimwiki_gla|, |vimwiki_gLa|, |vimwiki_glA|, |vimwiki_gLA| + |vimwiki_gli|, |vimwiki_gLi|, |vimwiki_glI|, |vimwiki_gLI|, |vimwiki_glx| +`links`: + Mappings for link creation and navigation. + |vimwiki_wi|, |vimwiki_|, |vimwiki_|, |vimwiki_| + |vimwiki_|, |vimwiki_|, |vimwiki_|, |vimwiki_| + |vimwiki_|, |vimwiki_wd|, |vimwiki_wr|, |vimwiki_| + |vimwiki_|, |vimwiki_+|, |vimwiki_| +`html`: + Mappings for HTML generation. + |vimwiki_wh|, |vimwiki_whh| +`mouse`: + Mouse mappings, see |vimwiki_mouse|. This option is disabled by default. + +The default is to enable all key mappings except the mouse: > + let g:vimwiki_key_mappings = + \ { + \ 'all_maps': 1, + \ 'global': 1, + \ 'headers': 1, + \ 'text_objs': 1, + \ 'table_format': 1, + \ 'table_mappings': 1, + \ 'lists': 1, + \ 'links': 1, + \ 'html': 1, + \ 'mouse': 0, + \ } + + +------------------------------------------------------------------------------ +*g:vimwiki_filetypes* + +A list of additional fileypes that should be registered to vimwiki files: > + + let g:vimwiki_filetypes = ['markdown', 'pandoc'] + +Would result in the filetype being set to `vimwiki.markdown.pandoc`. This can +be used to enable third party plugins such as custom folding. WARNING: this +option can allow other plugins to overwrite vimwiki settings and operation so +take care when using it. Any plugin that uses a set filetype will be enabled. + +The default is `[ ]` + ============================================================================== 13. Getting help *vimwiki-help* @@ -2988,8 +3492,36 @@ Contributors and their Github usernames in roughly chronological order: - Stefan Huber (@shuber2) - Hugo Hörnquist (@HugoNikanor) - Rane Brown (@ranebrown) - - @monkinco - + - Patrik Willard (@padowi) + - Steve Dondley (@sdondley) + - Alexander Gude (@agude) + - Jonny Bylsma (@jbylsma) + - Shaedil (@Shaedil) + - Robin Lowe (@defau1t) + - Abhinav Gupta (@abhinav) + - Dave Gauer (@ratfactor) + - Martin Tourneboeuf (@tinmarino) + - Mauro Morales (@mauromorales) + - Valtteri Vallius (@kaphula) + - Patrick Stockwell (@patstockwell) + - Henry Qin (@hq6) + - Hugo Hörnquist + - Greg Anders + - Steven Schmeiser + - Monkin (@monkinco) + - @AresMegaGlobal + - Cesar Tessarin (@tessarin) + - Clément Bœsch (@ubitux) + - Dave Gauer + - Eric Langlois (@edlanglois) + - James Moriarty + - Lionel Flandrin (@simias) + - Michael Brauweiler (@rattletat) + - Michal Cizmazia (@cizmazia) + - Samir Benmendil (@Ram-Z) + - Stefan Lehmann (@stevesteve) + - @graywolf + - flex (@bratekarate) ============================================================================== 16. Changelog *vimwiki-changelog* @@ -3001,6 +3533,138 @@ http://code.google.com/p/vimwiki/issues/list. They may be accessible from https://github.com/vimwiki-backup/vimwiki/issues. +2.5 (2020-05-26)~ + +New:~ + * PR #787: |:VimwikiRenameFile| works for all directories: even + wiki_root/diary/2019-12-11.md if current file is wiki_root/dir1/file.md. + * Issue #764: fenced code blocks are properly supported for markdown + syntax i.e. more than 3 backticks, adds tilde support. + * PR #785: |:VimwikiGoto| completion works with part of filename and + nested directories + * Add test framework (vader, vint, vim-testbed) + * Issue #769: Set default values for |g:vimwiki_ext2syntax|. + * PR #735: Make list-toggling work properly even when code blocks are + embedded within the list in Markdown mode. + * PR #711: Allow forcing VimwikiAll2HTML with ! + * PR #702: Make remapping documentation more accessible to newer vim users + * PR #673: Add :VimwikiGoto key mapping. + * PR #689: Allow |vimwiki-option-diary_rel_path| to be an empty string. + * PR #683: Improve layout and format of key binding documentation in + README and include note about key bindings that may not work. + * PR #681: Prevent sticky type checking errors for old vim versions. + * PR #686: New option |g:vimwiki_key_mappings| that allow key mappings to + be enabled/disabled by groups. Key mappings are also no longer + overwritten if they are already defined. + * PR #675: Add option |vimwiki-option-name| to assign a per wiki name. + * PR #661: Add option |g:vimwiki_auto_header| to automatically generate + a level 1 header for new wiki pages. + * PR #665: Integration with vimwiki_markdown gem + https://github.com/patrickdavey/vimwiki_markdown + This provides the |vimwiki-option-html_filename_parameterization| + which alters the filenames vimiwiki checks against when running the + html conversion. It also disables the deleting of html files which + no longer match against a wiki file. + * PR #663: New option |g:vimwiki_conceal_onechar_markers| to control + whether to show or hide single-character format markers. + * PR #636: Wiki local option |vimwiki-option-exclude_files| which is + a list of patterns to exclude when checking or generating links. + * PR #644: Key mapping gnt to jump to the next open task. + * PR #643: Option |g:vimwiki_toc_link_format| to change how links are + formatted in the TOC. + * PR #641: Option |g:vimwiki_conceal_code_blocks| to conceal preformatted + text markers. + * PR #634: New options |g:vimwiki_links_header| and + |g:vimwiki_tags_header| to customize the title string of generated + sections. New option |g:vimwiki_links_header_level| and + |g:vimwiki_tags_header_level| which allow the header level (1-6) of the + generated links to be set. New option |g:vimwiki_markdown_header_style| + which specifies the nuber of newlines after the created header for + generated sections. + * PR #635: Wiki local options |vimwiki-option-auto_generate_links| and + |vimwiki-option-auto_generate_tags|. + * Wiki local option |vimwiki-option-links_space_char| to replace spaces + with a different character when creating a link. + * Allow increase/decrease header level to take a count. + * PR #637: Option |g:vimwiki_table_reduce_last_col| to not autoformat last + column of a table. + * PR #629: New option |g:vimwiki_toc_header_level| to set the desired + header level for the TOC. + * PR #616: Hex color codes are colored in HTML output. + * PR #573: Add HTML template variable %wiki_path% which outputs the path + of the current file being converted to HTML. + * PR #529: Option |g:vimwiki_markdown_link_ext| to include the extension + .md in generated links. + * PR #528: Add option |g:vimwiki_create_link| to prevent link creation + with . + * PR #498: Option |vimwiki-option-diary_caption_level| which adds captions + to the diary index based on headers. + * PR #377: Add horizontal alignment to tables. + * PR #202: Don't override or display errors for existing keymappings. + * PR #47: Optimize table formatting for large tables. + * PR #857: Make default template responsive + * PR #879: Generate links when diary & wiki dir are the same + +Changed:~ + * Issue #796: Rename |:VimwikiGenerateTags| to |:VimwikiGenerateTagLinks| + * Issue #638: Rename |:VimwikiDeleteLink| to |:VimwikiDeleteFile| + * Issue #638: Rename |:VimwikiRenameLink| to |:VimwikiRenameFile| + * For all three above the old commands still works but is deprecated and + * will be removed in later versions. + * Set default |vimwiki-option-list_margin| = 0 for markdown syntax. + * Modify horizontal rule (thematic-breaks) syntax for markdown. + +Removed:~ + * PR #698: Remove awa check triggering silent file edits. + * Options g:vimwiki_use_mouse and g:vimwiki_table_mappings. These are + still present in the code for backwards compatibility but have been + removed from the documentation and will be fully removed at a later + point. + +Fixed:~ + * Issue #90: |:VimwikiRenameFile| doesn't update links in diary. + * Issue #790: Allow tags before a header with markdown syntax. + * Issue #779: Vimwiki tags file meets ctags standard. + * Issue #781: Compatablity fixes for older versions of Vim. + * Issue #691: Allow |:VimwikiGoBackLink| to go back multiple times. + * Update MathJax CDN loading instructions. + * Issue #212: Don't treat comment characters within code blocks as + headers. + * Issue #420: Add error handling to |:VimwikiSearch| + * PR #744: Fix typo in vimwiki_list_manipulation + * Issue #715: s:clean_url is compatible with vim pre 7.4.1546 (sticky type + checking) + * Issue #729: Normalize links uses relative paths in diary pages for + Markdown syntax. This previously only worked for the default syntax. + * Disable spell check in code and math inline/blocks. + * Properly handle markdown image links `![]()` + * Issue #415: Expand iabbrev entries on . + * Issue #619: allow escaped characters in markdown links. + * Issue #240: Fix regex pattern for markdown '[]()' links + * Issue #685: Error message for invalid user options fixed. + * Issue #481: Allow surrounding URLs with '<' '>' + * Issue #237: |:VimwikiRenameFile| now works for Markdown syntax + * Issue #612: GVim menu displayed duplicate names. + * Issue #456: Omnicompletion of wikilinks under Windows. Note: this should + be considered a temporary fix until #478 is closed. + * Issue #654: Fix |:VimwikiShowVersion| command. + * PR #634: Removed extra newlines that were inserted before/after + generated links. + * Issue #543: Allow commands related to opening index files or diary pages + to take a count, modify keymapping behavior, and fix discrepancies in + the documentation. + * Issue #539: The option |g:vimwiki_url_maxsave| now only affects raw + URLs (wiki links are excluded). + * Issue #438: Fix creation of visually selected links on diary pages. + * Issue #404: Don't conceal strikethrough character in tables. + * Issue #318: Markdown syntax bold, italic, and italic/bold are now + rendered correctly. + * Issue #835: Pressing enter on the dash of a markdown list causes an error. + * Issue #876: E684: list index out of range: 0, when creating a link containing a `.`. + * Issue #803: |:VimwikiGenerateLinks| for subdirectory only + * Issue #776: Command [count]o can't repeat in vimwiki + + 2.4.1 (2019-02-20)~ Fixed: * Fix VimwikiShowVersion function. @@ -3087,7 +3751,7 @@ Removed:~ Fixed:~ * Issue #175: Don't do random things when the user has remapped the z key - * Don't ask for confirmation when following an URL in MacOS + * Don't ask for confirmation when following a URL in MacOS * Always jump to the first occurrence of a tag in a file * Don't move the cursor when updating the TOC * Fix some issues with the TOC when folding is enabled @@ -3245,7 +3909,7 @@ http://code.google.com/p/vimwiki/issues/list highlighted when open wiki files. * Issue 146: Filetype difficulty with ".txt" as a vimwiki extension. * Issue 148: There are no mailto links. - * Issue 151: Use location list instead of quickfix list for :VimwikiSearch + * Issue 151: Use location list instead of quickfix list for |:VimwikiSearch| command result. Use :lopen instead of :copen, :lnext instead of :cnext etc. * Issue 152: Add the list of HTML files that would not be deleted after diff --git a/doc/wiki.png b/doc/wiki.png index bbcc463..a8bac8d 100644 Binary files a/doc/wiki.png and b/doc/wiki.png differ diff --git a/ftplugin/vimwiki.vim b/ftplugin/vimwiki.vim index 2d3688b..d14201c 100644 --- a/ftplugin/vimwiki.vim +++ b/ftplugin/vimwiki.vim @@ -2,7 +2,7 @@ " Vimwiki filetype plugin file " Home: https://github.com/vimwiki/vimwiki/ -if exists("b:did_ftplugin") +if exists('b:did_ftplugin') finish endif let b:did_ftplugin = 1 " Don't load another plugin for this buffer @@ -11,7 +11,7 @@ let b:did_ftplugin = 1 " Don't load another plugin for this buffer setlocal commentstring=%%%s -if vimwiki#vars#get_global('conceallevel') && exists("+conceallevel") +if vimwiki#vars#get_global('conceallevel') && exists('+conceallevel') let &l:conceallevel = vimwiki#vars#get_global('conceallevel') endif @@ -19,11 +19,11 @@ endif execute 'setlocal suffixesadd='.vimwiki#vars#get_wikilocal('ext') setlocal isfname-=[,] -exe "setlocal tags+=" . escape(vimwiki#tags#metadata_file_path(), ' \|"') +exe 'setlocal tags+=' . escape(vimwiki#tags#metadata_file_path(), ' \|"') -function! Complete_wikifiles(findstart, base) +function! Complete_wikifiles(findstart, base) abort if a:findstart == 1 let column = col('.')-2 let line = getline('.')[:column] @@ -50,14 +50,14 @@ function! Complete_wikifiles(findstart, base) " Completion works for wikilinks/anchors, and for tags. s:line_content " tells us which string came before a:base. There seems to be no easier " solution, because calling col('.') here returns garbage. - if s:line_context == '' + if s:line_context ==? '' return [] - elseif s:line_context == ':' + elseif s:line_context ==# ':' " Tags completion let tags = vimwiki#tags#get_tags() - if a:base != '' + if a:base !=? '' call filter(tags, - \ "v:val[:" . (len(a:base)-1) . "] == '" . substitute(a:base, "'", "''", '') . "'" ) + \ 'v:val[:' . (len(a:base)-1) . "] == '" . substitute(a:base, "'", "''", '') . "'" ) endif return tags elseif a:base !~# '#' @@ -80,7 +80,7 @@ function! Complete_wikifiles(findstart, base) let scheme = '' endif - let links = vimwiki#base#get_wikilinks(wikinumber, 1) + let links = vimwiki#base#get_wikilinks(wikinumber, 1, '') let result = [] for wikifile in links if wikifile =~ '^'.vimwiki#u#escape(prefix) @@ -93,7 +93,7 @@ function! Complete_wikifiles(findstart, base) " we look for anchors in the given wikifile let segments = split(a:base, '#', 1) - let given_wikifile = segments[0] == '' ? expand('%:t:r') : segments[0] + let given_wikifile = segments[0] ==? '' ? expand('%:t:r') : segments[0] let link_infos = vimwiki#base#resolve_link(given_wikifile.'#') let wikifile = link_infos.filename let syntax = vimwiki#vars#get_wikilocal('syntax', link_infos.index) @@ -129,35 +129,21 @@ setlocal formatoptions+=n let &formatlistpat = vimwiki#vars#get_syntaxlocal('rxListItem') -if !empty(&langmap) - " Valid only if langmap is a comma separated pairs of chars - let s:l_o = matchstr(&langmap, '\C,\zs.\zeo,') - if s:l_o - exe 'nnoremap '.s:l_o.' :call vimwiki#lst#kbd_o()a' - endif - - let s:l_O = matchstr(&langmap, '\C,\zs.\zeO,') - if s:l_O - exe 'nnoremap '.s:l_O.' :call vimwiki#lst#kbd_O()a' - endif -endif - - " ------------------------------------------------ " Folding stuff " ------------------------------------------------ -function! VimwikiFoldListLevel(lnum) +function! VimwikiFoldListLevel(lnum) abort return vimwiki#lst#fold_level(a:lnum) endfunction -function! VimwikiFoldLevel(lnum) +function! VimwikiFoldLevel(lnum) abort let line = getline(a:lnum) " Header/section folding... - if line =~# vimwiki#vars#get_syntaxlocal('rxHeader') + if line =~# vimwiki#vars#get_syntaxlocal('rxHeader') && !vimwiki#u#is_codeblock(a:lnum) return '>'.vimwiki#u#count_first_sym(line) " Code block folding... elseif line =~# vimwiki#vars#get_syntaxlocal('rxPreStart') @@ -165,21 +151,21 @@ function! VimwikiFoldLevel(lnum) elseif line =~# vimwiki#vars#get_syntaxlocal('rxPreEnd') return 's1' else - return "=" + return '=' endif endfunction " Constants used by VimwikiFoldText " use \u2026 and \u21b2 (or \u2424) if enc=utf-8 to save screen space -let s:ellipsis = (&enc ==? 'utf-8') ? "\u2026" : "..." +let s:ellipsis = (&encoding ==? 'utf-8') ? "\u2026" : '...' let s:ell_len = strlen(s:ellipsis) -let s:newline = (&enc ==? 'utf-8') ? "\u21b2 " : " " +let s:newline = (&encoding ==? 'utf-8') ? "\u21b2 " : ' ' let s:tolerance = 5 " unused -function! s:shorten_text_simple(text, len) +function! s:shorten_text_simple(text, len) abort let spare_len = a:len - len(a:text) return (spare_len>=0) ? [a:text,spare_len] : [a:text[0:a:len].s:ellipsis, -1] endfunction @@ -188,7 +174,7 @@ endfunction " s:shorten_text(text, len) = [string, spare] with "spare" = len-strlen(string) " for long enough "text", the string's length is within s:tolerance of "len" " (so that -s:tolerance <= spare <= s:tolerance, "string" ends with s:ellipsis) -function! s:shorten_text(text, len) +function! s:shorten_text(text, len) abort " returns [string, spare] " strlen() returns lenght in bytes, not in characters, so we'll have to do a " trick here -- replace all non-spaces with dot, calculate lengths and @@ -206,7 +192,7 @@ function! s:shorten_text(text, len) endfunction -function! VimwikiFoldText() +function! VimwikiFoldText() abort let line = getline(v:foldstart) let main_text = substitute(line, '^\s*', repeat(' ',indent(v:foldstart)), '') let fold_len = v:foldend - v:foldstart + 1 @@ -248,15 +234,22 @@ command! -buffer Vimwiki2HTMLBrowse \ call vimwiki#base#system_open_link(vimwiki#html#Wiki2HTML( \ expand(vimwiki#vars#get_wikilocal('path_html')), \ expand('%'))) -command! -buffer VimwikiAll2HTML - \ call vimwiki#html#WikiAll2HTML(expand(vimwiki#vars#get_wikilocal('path_html'))) +command! -buffer -bang VimwikiAll2HTML + \ call vimwiki#html#WikiAll2HTML(expand(vimwiki#vars#get_wikilocal('path_html')), 0) command! -buffer VimwikiTOC call vimwiki#base#table_of_contents(1) +command! -buffer VimwikiNextTask call vimwiki#base#find_next_task() command! -buffer VimwikiNextLink call vimwiki#base#find_next_link() command! -buffer VimwikiPrevLink call vimwiki#base#find_prev_link() -command! -buffer VimwikiDeleteLink call vimwiki#base#delete_link() -command! -buffer VimwikiRenameLink call vimwiki#base#rename_link() +command! -buffer VimwikiDeleteFile call vimwiki#base#delete_link() +command! -buffer VimwikiDeleteLink + \ call vimwiki#base#deprecate("VimwikiDeleteLink", "VimwikiDeleteFile") | + \ call vimwiki#base#delete_link() +command! -buffer VimwikiRenameFile call vimwiki#base#rename_link() +command! -buffer VimwikiRenameLink + \ call vimwiki#base#deprecate("VimwikiRenameLink", "VimwikiRenameFile") | + \ call vimwiki#base#rename_link() command! -buffer VimwikiFollowLink call vimwiki#base#follow_link('nosplit', 0, 1) command! -buffer VimwikiGoBackLink call vimwiki#base#go_back_link() command! -buffer -nargs=* VimwikiSplitLink call vimwiki#base#follow_link('hsplit', ) @@ -266,18 +259,15 @@ command! -buffer -nargs=? VimwikiNormalizeLink call vimwiki#base#normalize_link( command! -buffer VimwikiTabnewLink call vimwiki#base#follow_link('tab', 0, 1) -command! -buffer VimwikiGenerateLinks call vimwiki#base#generate_links() +command! -buffer -nargs=? VimwikiGenerateLinks call vimwiki#base#generate_links(1, ) command! -buffer -nargs=0 VimwikiBacklinks call vimwiki#base#backlinks() command! -buffer -nargs=0 VWB call vimwiki#base#backlinks() -exe 'command! -buffer -nargs=* VimwikiSearch lvimgrep '. - \ escape(vimwiki#vars#get_wikilocal('path').'**/*'.vimwiki#vars#get_wikilocal('ext'), ' ') +command! -buffer -nargs=* VimwikiSearch call vimwiki#base#search() +command! -buffer -nargs=* VWS call vimwiki#base#search() -exe 'command! -buffer -nargs=* VWS lvimgrep '. - \ escape(vimwiki#vars#get_wikilocal('path').'**/*'.vimwiki#vars#get_wikilocal('ext'), ' ') - -command! -buffer -nargs=+ -complete=custom,vimwiki#base#complete_links_escaped +command! -buffer -nargs=* -complete=customlist,vimwiki#base#complete_links_escaped \ VimwikiGoto call vimwiki#base#goto() command! -buffer VimwikiCheckLinks call vimwiki#base#check_links() @@ -305,8 +295,8 @@ command! -buffer VimwikiListToggle call vimwiki#lst#toggle_list_item() " table commands command! -buffer -nargs=* VimwikiTable call vimwiki#tbl#create() -command! -buffer VimwikiTableAlignQ call vimwiki#tbl#align_or_cmd('gqq') -command! -buffer VimwikiTableAlignW call vimwiki#tbl#align_or_cmd('gww') +command! -buffer -nargs=? VimwikiTableAlignQ call vimwiki#tbl#align_or_cmd('gqq', ) +command! -buffer -nargs=? VimwikiTableAlignW call vimwiki#tbl#align_or_cmd('gww', ) command! -buffer VimwikiTableMoveColumnLeft call vimwiki#tbl#move_column_left() command! -buffer VimwikiTableMoveColumnRight call vimwiki#tbl#move_column_right() @@ -319,7 +309,11 @@ command! -buffer -bang VimwikiRebuildTags call vimwiki#tags#update_tags(1, ':/ command! -buffer -nargs=* -complete=custom,vimwiki#tags#complete_tags - \ VimwikiGenerateTags call vimwiki#tags#generate_tags() + \ VimwikiGenerateTagLinks call vimwiki#tags#generate_tags(1, ) +command! -buffer -nargs=* -complete=custom,vimwiki#tags#complete_tags + \ VimwikiGenerateTags + \ call vimwiki#base#deprecate("VimwikiGenerateTags", "VimwikiGenerateTagLinks") | + \ call vimwiki#tags#generate_tags(1, ) command! -buffer VimwikiPasteUrl call vimwiki#html#PasteUrl(expand('%:p')) command! -buffer VimwikiCatUrl call vimwiki#html#CatUrl(expand('%:p')) @@ -329,7 +323,8 @@ command! -buffer VimwikiCatUrl call vimwiki#html#CatUrl(expand('%:p')) " Keybindings " ------------------------------------------------ -if vimwiki#vars#get_global('use_mouse') +" mouse mappings +if str2nr(vimwiki#vars#get_global('key_mappings').mouse) nmap nmap nnoremap <2-LeftMouse> @@ -339,339 +334,333 @@ if vimwiki#vars#get_global('use_mouse') nnoremap :VimwikiGoBackLink endif - -if !hasmapto('Vimwiki2HTML') - exe 'nmap '.vimwiki#vars#get_global('map_prefix').'h Vimwiki2HTML' -endif +" HTML definitions nnoremap