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
+
[中文](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"}} ->
@@ -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, "