From 630e266933bf50da79736c8d2d8d48be02d152b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Tue, 29 Jun 2021 22:58:16 +0200 Subject: [PATCH 01/10] fix: avoid sleep unless necessary --- autoload/wiki/fzf.vim | 1 + autoload/wiki/page.vim | 10 +--------- autoload/wiki/url/wiki.vim | 5 +++++ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/autoload/wiki/fzf.vim b/autoload/wiki/fzf.vim index 4e3271f9..7503b1c3 100644 --- a/autoload/wiki/fzf.vim +++ b/autoload/wiki/fzf.vim @@ -98,6 +98,7 @@ function! s:accept_page(lines) abort "{{{1 if len(a:lines) == 2 || !empty(a:lines[1]) call wiki#page#open(a:lines[0]) + sleep 1 else let l:file = split(a:lines[2], '#####')[0] execute 'edit ' . l:file diff --git a/autoload/wiki/page.vim b/autoload/wiki/page.vim index b2a08459..16601d89 100644 --- a/autoload/wiki/page.vim +++ b/autoload/wiki/page.vim @@ -9,15 +9,7 @@ function! wiki#page#open(page) abort "{{{1 \ !empty(g:wiki_map_create_page) && exists('*' . g:wiki_map_create_page) \ ? call(g:wiki_map_create_page, [a:page]) \ : a:page - let l:url = wiki#url#parse('wiki:/' . l:page) - - if !filereadable(l:url.path) - redraw! - call wiki#log#info('Opening new page "' . l:page . '"') - sleep 1 - end - - call l:url.follow() + call wiki#url#parse('wiki:/' . l:page).follow() endfunction "}}}1 diff --git a/autoload/wiki/url/wiki.vim b/autoload/wiki/url/wiki.vim index 484ae2b4..578988dd 100644 --- a/autoload/wiki/url/wiki.vim +++ b/autoload/wiki/url/wiki.vim @@ -85,6 +85,11 @@ function! s:handler.follow(...) abort dict " {{{1 execute l:cmd fnameescape(self.path) + if !filereadable(self.path) + redraw! + call wiki#log#info('Opened new page "' . self.stripped . '"') + end + if exists('l:old_position') let b:wiki = get(b:, 'wiki', {}) call wiki#nav#add_to_stack(l:old_position) From f6c26b4e2de364dd03ff4538f45c8e455220ecd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Tue, 29 Jun 2021 22:59:45 +0200 Subject: [PATCH 02/10] chore: minor refactor of templates --- autoload/wiki/buffer.vim | 18 +----------------- autoload/wiki/template.vim | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/autoload/wiki/buffer.vim b/autoload/wiki/buffer.vim index 4e16fab0..0d0805c0 100644 --- a/autoload/wiki/buffer.vim +++ b/autoload/wiki/buffer.vim @@ -25,7 +25,7 @@ function! wiki#buffer#init() abort " {{{1 call s:init_buffer_commands() call s:init_buffer_mappings() - call s:apply_template() + call wiki#template#init() if exists('#User#WikiBufferInitialized') doautocmd User WikiBufferInitialized @@ -173,19 +173,3 @@ function! s:init_buffer_mappings() abort " {{{1 endfunction " }}}1 - -function! s:apply_template() abort " {{{1 - if filereadable(expand('%')) | return | endif - - let l:match = matchlist(expand('%:t:r'), '^\(\d\d\d\d\)_\(\w\)\(\d\d\)$') - if empty(l:match) | return | endif - let [l:year, l:type, l:number] = l:match[1:3] - - if l:type ==# 'w' - call wiki#template#weekly_summary(l:year, l:number) - elseif l:type ==# 'm' - call wiki#template#monthly_summary(l:year, l:number) - endif -endfunction - -" }}}1 diff --git a/autoload/wiki/template.vim b/autoload/wiki/template.vim index acf9cf9e..ceec02ad 100644 --- a/autoload/wiki/template.vim +++ b/autoload/wiki/template.vim @@ -4,6 +4,22 @@ " Email: karl.yngve@gmail.com " +function! wiki#template#init() abort " {{{1 + if filereadable(expand('%')) | return | endif + + let l:match = matchlist(expand('%:t:r'), '^\(\d\d\d\d\)_\(\w\)\(\d\d\)$') + if empty(l:match) | return | endif + let [l:year, l:type, l:number] = l:match[1:3] + + if l:type ==# 'w' + call wiki#template#weekly_summary(l:year, l:number) + elseif l:type ==# 'm' + call wiki#template#monthly_summary(l:year, l:number) + endif +endfunction + +" }}}1 + function! wiki#template#weekly_summary(year, week) abort " {{{1 let l:parser = s:summary.new() From 29778389ad5cb5968c11c25d34093a9683e27a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Tue, 29 Jun 2021 23:02:19 +0200 Subject: [PATCH 03/10] feat: added nav#get_previous --- autoload/wiki/nav.vim | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/autoload/wiki/nav.vim b/autoload/wiki/nav.vim index 814f27bf..64704715 100644 --- a/autoload/wiki/nav.vim +++ b/autoload/wiki/nav.vim @@ -19,6 +19,22 @@ endfunction " }}}1 +function! wiki#nav#add_to_stack(link) abort " {{{1 + let s:position_stack += [a:link] +endfunction + +let s:position_stack = [] + +" }}}1 +function! wiki#nav#get_previous() abort "{{{1 + let l:previous = get(s:position_stack, -1, []) + if !empty(l:previous) | return l:previous | endif + + let l:file = expand('#:p') + if filereadable(l:file) | return [l:file, 1] | endif +endfunction + +" }}}1 function! wiki#nav#return() abort "{{{1 if g:wiki_write_on_nav | update | endif @@ -32,10 +48,3 @@ function! wiki#nav#return() abort "{{{1 endfunction " }}}1 -function! wiki#nav#add_to_stack(link) abort " {{{1 - let s:position_stack += [a:link] -endfunction - -let s:position_stack = [] - -" }}}1 From aee5aee9ff9a6142c550a4da72d99aed7f661baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Sun, 21 Jun 2020 23:15:20 +0200 Subject: [PATCH 04/10] doc: specify the template feature --- doc/wiki.txt | 162 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 136 insertions(+), 26 deletions(-) diff --git a/doc/wiki.txt b/doc/wiki.txt index cd144004..77a9416b 100644 --- a/doc/wiki.txt +++ b/doc/wiki.txt @@ -29,28 +29,31 @@ License: MIT license {{{ ============================================================================== CONTENTS *wiki-contents* - Introduction |wiki-intro| - Requirements |wiki-intro-requirements| - Features |wiki-intro-features| - Configuration |wiki-config| - Options |wiki-config-options| - Events |wiki-config-events| - Mappings |wiki-mappings| - Text objects |wiki-mappings-text-obj| - Journal mappings |wiki-mappings-default| - Commands |wiki-commands| - Links |wiki-link| - Link URLs |wiki-link-urls| - Wiki links |wiki-link-wiki| - Markdown links |wiki-link-markdown| - Markdown image links |wiki-link-image| - Reference links |wiki-link-reference| - Zotero shortlinks |wiki-link-zotero| - AsciiDoc cross references |wiki-link-adoc-xref| - AsciiDoc link macro |wiki-link-adoc-link| - Completion |wiki-completion| - Autocomplete |wiki-completion-auto| - Tags |wiki-tags| + Introduction |wiki-intro| + Requirements |wiki-intro-requirements| + Features |wiki-intro-features| + Configuration |wiki-config| + Options |wiki-config-options| + Events |wiki-config-events| + Mappings |wiki-mappings| + Text objects |wiki-mappings-text-obj| + Journal mappings |wiki-mappings-default| + Commands |wiki-commands| + Links |wiki-link| + Link URLs |wiki-link-urls| + Wiki links |wiki-link-wiki| + Markdown links |wiki-link-markdown| + Markdown image links |wiki-link-image| + Reference links |wiki-link-reference| + Zotero shortlinks |wiki-link-zotero| + AsciiDoc cross references |wiki-link-adoc-xref| + AsciiDoc link macro |wiki-link-adoc-link| + Completion |wiki-completion| + Autocomplete |wiki-completion-auto| + Tags |wiki-tags| + Templates |wiki-templates| + Template file format |wiki-templates-format| + Journal summaries |wiki-templates-journal-summaries| ============================================================================== INTRODUCTION *wiki-intro* @@ -106,6 +109,7 @@ FEATURES *wiki-intro-features* - Text objects - `iu au` Link URL - `it at` Link text + - New page templates - Support for journal entries - Navigating the journal back and forth with `(wiki-journal-next)` and `(wiki-journal-prev)`. @@ -500,6 +504,27 @@ OPTIONS *wiki-config-options* Default: > let g:wiki_tags_scan_num_lines = 15 +*g:wiki_template_files* + A list template files for new pages. Each file should be specified either as + an absolute path or as a path relative to the location of the new page. + The files are searched in order, and the first matching template file will + be used. The format of template files is specified in |wiki-templates-format|. + + If the template file path ends with `;`, then the file is searched upwards + similar to the description in the second type of search in |file-searching|. + For example: > + + let g:wiki_template_files = [ + \ '.mytemplate.md;', + \ '/home/user/templates/fallback.md', + \] +< + Here `.mytemplate.md` file is first searched for in the current directory of + the new page, then in the parent directory, and so on. If it is not found, + then the file `/home/user/templates/fallback.md` is used (if it exists). + + Default: `['.template.md']` + *g:wiki_template_title_month* A string that specifies the title of the month template. The following keys are interpolated: @@ -508,6 +533,8 @@ OPTIONS *wiki-config-options* `%(month-name)` Name of month (see |g:wiki_month_names|) `%(year)` Year (4 digits) + See |wiki-templates-journal-summaries| for more info. + Default: `'# Summary, %(year) %(month-name)'` *g:wiki_template_title_week* @@ -517,6 +544,8 @@ OPTIONS *wiki-config-options* `%(week)` Week number `%(year)` Year (4 digits) + See |wiki-templates-journal-summaries| for more info. + Default: `'# Summary, %(year) week %(week)'` *g:wiki_viewer* @@ -699,13 +728,14 @@ the commands are also available as mappings of the form `(wiki-[name])`. *(wiki-journal-toweek)* *WikiJournalToWeek* Go to week summary. If not existing, then parse the day entries to make - a first draft. The title is given by |g:wiki_template_title_week|. + a first draft. The title is given by |g:wiki_template_title_week|. For more + info, see |wiki-templates-journal-summaries|. *(wiki-journal-tomonth)* *WikiJournalToMonth* Go to month summary. If not existing, then parse the day entries and relevant week summaries to make a first draft. The title is given by - |g:wiki_template_title_month|. + |g:wiki_template_title_month|. See also |wiki-templates-journal-summaries|. *(wiki-export)* [range]*WikiExport* [options] [fname] @@ -1119,8 +1149,8 @@ TAGS *wiki-tags* Wiki pages may be tagged with keywords for organization. By default, tags use the syntax `:tag-name:`. Multiple tags may be specified both with `:tag1: :tag2:` and with the short form `:tag1:tag2:`. The tag name must consist of purely -non-space characters. By default, all tags added in the top 15 lines of a file will be -recognized. +non-space characters. By default, all tags added in the top 15 lines of a file +will be recognized. You may customize the format of tags by modifying the |g:wiki_tags_format_pattern| variable. @@ -1137,5 +1167,85 @@ Related commands: Related settings: - |g:wiki_tags| +============================================================================== +TEMPLATES *wiki-templates* + +New pages are empty by default. However, it is possible to define templates +for prefilling new pages. Template files are specified in the option +|g:wiki_template_files|, and if any of these files are found, then they are +used to prefill a new page. + +Template files are formatted as described in |wiki-templates-format|. + +There is also a special kind of journal summary template which is described in +|wiki-templates-journal-summaries|. + +Related settings: +- |g:wiki_template_files| + +------------------------------------------------------------------------------ +TEMPLATE FILE FORMAT *wiki-templates-format* + +A template file is essentially a simple text file to your liking. There are +two rules that allow dynamic templates: + + 1. Variable substitution with `{variable}` strings. The allowed variables + are restricted to a set of pre-defined variables, see below. + 2. Function substitution with `{{Function Arg1 Arg2 ...}}` strings. The + function is assumed to return either a string or a list of strings. + +The first rule is applied first, which allows the arguments in Rule 2 to be +variable substitutions. + +Pre-defined variables:~ + `{date}` + `{time}` + `{pagetitle}` + `{pagesection}` + `{last_pagetitle}` + `{last_pagesection}` + +Pre-defined functions:~ + `wiki#template#case_title(string)` + +An example of how these templates could be useful: If you keep a separate blog +directory in your wiki, you could add a `.template.md` file with the following +content to ensure that you follow the same structure: > + + # {{wiki#template#case_title {pagetitle}}} + Created: {date} {time} + + # Introduction + + # Conclusion + +------------------------------------------------------------------------------ +JOURNAL SUMMARIES *wiki-templates-journal-summaries* + +|wiki.vim| supports parsing the journal entries in order to make weekly and +monthly summaries. A summary is automatically created when a summary file is +opened; the format is given by `g:wiki_journal.date_format.weekly` and +`g:wiki_journal.date_format.monthly`. One may also move from a daily entry to +the corresponding week with |WikiJournalToWeek|, and similarly to the +corresponding month with |WikiJournalToMonth|. Again, if these entries do not +exist, they are automatically created and journal entries are parsed to fill +the contents. + +The parsed results typically need manual editing, and it currently only works +for a very specific format of journals. + +Related settings: +- |g:wiki_journal| + Note: The date format specifies the format for the weekly and monthly + entries. +- |g:wiki_template_title_week| + A string that specifies the title of the weekly summary. +- |g:wiki_template_title_month| + A string that specifies the title of the monthly summary. + +Related commands: +- |WikiJournalToWeek| +- |WikiJournalToMonth| + ============================================================================== vim:tw=78:ts=8:ft=help:norl:fdm=marker: From 33cee77bf731256aaafedb679a679873744a3ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Thu, 24 Jun 2021 22:58:31 +0200 Subject: [PATCH 05/10] doc: updated specification --- doc/wiki.txt | 110 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 32 deletions(-) diff --git a/doc/wiki.txt b/doc/wiki.txt index 77a9416b..97db7878 100644 --- a/doc/wiki.txt +++ b/doc/wiki.txt @@ -52,6 +52,7 @@ CONTENTS *wiki-contents* Autocomplete |wiki-completion-auto| Tags |wiki-tags| Templates |wiki-templates| + Template function context |wiki-templates-context| Template file format |wiki-templates-format| Journal summaries |wiki-templates-journal-summaries| @@ -246,7 +247,7 @@ OPTIONS *wiki-config-options* One of 'daily', 'weekly', or 'monthly'. date_format~ - Dictionary of file name formats for the 'daily', 'weekly', and 'monthly' + Dictionary of filename formats for the 'daily', 'weekly', and 'monthly' frequencies. The formats may contain the following keys: %y year (two digits) @@ -423,7 +424,7 @@ OPTIONS *wiki-config-options* The function takes two arguments: fname~ - The unresolved file name. This may be empty, which is typically the case + The unresolved filename. This may be empty, which is typically the case for inter-page links (e.g. `[[#SomeSection]]`). origin~ @@ -504,26 +505,60 @@ OPTIONS *wiki-config-options* Default: > let g:wiki_tags_scan_num_lines = 15 -*g:wiki_template_files* - A list template files for new pages. Each file should be specified either as - an absolute path or as a path relative to the location of the new page. - The files are searched in order, and the first matching template file will - be used. The format of template files is specified in |wiki-templates-format|. +*g:wiki_templates* + A list of templates for prefilling new pages. Each template should be + specified as a dictionary with a matcher and a source. Matching may be done + with regular expressions or with user functions. Similarly, sources can be + specified as a file source as specified in |wiki-templates-format|, or as + a user function with a single argument `context` as specified in + |wiki-templates-context|. + + The possible dictionary keys of a template are: + + match_re~ + |String| + A regular expression that will be matched against the new page name. + + match_func~ + |Funcref| + A function that should return |v:true| if the template should be applied + or |v:false| if it should not apply. + + source_filename~ + |String| + The name of a template file. If filename ends with `;`, then the file is + searched upwards similar to the description in the second type of search + in |file-searching|. Note: If the template file is not found, then the + template will not be applied and the next template in the list will be + tried. + + source_func~ + |Funcref| + A user function that can use e.g. |append()| to add lines to the file. - If the template file path ends with `;`, then the file is searched upwards - similar to the description in the second type of search in |file-searching|. For example: > - let g:wiki_template_files = [ - \ '.mytemplate.md;', - \ '/home/user/templates/fallback.md', + function! TemplateFallback(context) + call append(0, '# ' . a:context.name) + call append(1, '') + call append(2, 'Foobar') + endfunction + + let g:wiki_templates = [ + \ { 'match_re': 'index\.md', + \ 'source_filename': '/home/user/templates/index.md'}, + \ { 'match_re': 'foo\.md', + \ 'source_filename': '.footemplate.md;'}, + \ { 'match_func': {x -> v:true}, + \ 'source_func': function('TemplateFallback')}, \] < - Here `.mytemplate.md` file is first searched for in the current directory of - the new page, then in the parent directory, and so on. If it is not found, - then the file `/home/user/templates/fallback.md` is used (if it exists). + Notice that in the second template, the `;` is appended to the source + filename. This means the template file is first searched for in the current + directory of the new page, then in the parent directory, and so on. If the + template file is not found, then the next template will be tried. - Default: `['.template.md']` + Default: `[]` *g:wiki_template_title_month* A string that specifies the title of the month template. The following keys @@ -1171,17 +1206,36 @@ Related settings: TEMPLATES *wiki-templates* New pages are empty by default. However, it is possible to define templates -for prefilling new pages. Template files are specified in the option -|g:wiki_template_files|, and if any of these files are found, then they are -used to prefill a new page. +for prefilling new pages. Templates are specified with the option +|g:wiki_templates|, and if a template matches the new page it will be applied. +Only the first template that matches will be applied. -Template files are formatted as described in |wiki-templates-format|. +The templates can be specified as user functions or as template files. User +functions assume a single variable such as described in +|wiki-templates-context|. The template files should be formatted as described +in |wiki-templates-format|. There is also a special kind of journal summary template which is described in |wiki-templates-journal-summaries|. Related settings: -- |g:wiki_template_files| +- |g:wiki_templates| + +------------------------------------------------------------------------------ +TEMPLATE FUNCTION CONTEXT *wiki-templates-context* + +The functions in |g:wiki_templates| assume a single argument `context` which +is a dictionary with the following values: + + Key Description Example~ + === =========== ======= + `name` Filename (no extension) "New Page" + `path` Full path "/path/to/wiki/sub/New Page.md" + `path_wiki` Wiki path "/sub/New Page.md" + `origin_file` Previous file "/path/to/wiki/index.md" + `origin_lnum` Previous lnum 123 + `date` ISO date 2021-07-01 + `time` Time (24h format) 19:30 ------------------------------------------------------------------------------ TEMPLATE FILE FORMAT *wiki-templates-format* @@ -1190,21 +1244,13 @@ A template file is essentially a simple text file to your liking. There are two rules that allow dynamic templates: 1. Variable substitution with `{variable}` strings. The allowed variables - are restricted to a set of pre-defined variables, see below. + are the same as those available in |wiki-templates-context|. 2. Function substitution with `{{Function Arg1 Arg2 ...}}` strings. The function is assumed to return either a string or a list of strings. The first rule is applied first, which allows the arguments in Rule 2 to be variable substitutions. -Pre-defined variables:~ - `{date}` - `{time}` - `{pagetitle}` - `{pagesection}` - `{last_pagetitle}` - `{last_pagesection}` - Pre-defined functions:~ `wiki#template#case_title(string)` @@ -1212,7 +1258,7 @@ An example of how these templates could be useful: If you keep a separate blog directory in your wiki, you could add a `.template.md` file with the following content to ensure that you follow the same structure: > - # {{wiki#template#case_title {pagetitle}}} + # {{wiki#template#case_title {name}}} Created: {date} {time} # Introduction @@ -1248,4 +1294,4 @@ Related commands: - |WikiJournalToMonth| ============================================================================== - vim:tw=78:ts=8:ft=help:norl:fdm=marker: + vim:tw=78:ts=8:ft=help:norl:fdm=marker:cole=2: From 262d5dc0a8a7e1771fe7eee7be62bc75fae4318d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Tue, 29 Jun 2021 23:03:11 +0200 Subject: [PATCH 06/10] wip: minimal implementation --- autoload/wiki/template.vim | 37 +++++++++++++++++++++++++++++++++++++ plugin/wiki.vim | 1 + 2 files changed, 38 insertions(+) diff --git a/autoload/wiki/template.vim b/autoload/wiki/template.vim index ceec02ad..e5f9591d 100644 --- a/autoload/wiki/template.vim +++ b/autoload/wiki/template.vim @@ -7,6 +7,21 @@ function! wiki#template#init() abort " {{{1 if filereadable(expand('%')) | return | endif + let l:context = { + \ 'date': strftime("%F"), + \ 'name': expand('%:t:r'), + \ 'origin': wiki#nav#get_previous(), + \ 'path': expand('%:p'), + \ 'path_wiki': wiki#paths#shorten_relative(expand('%:p')), + \ 'time': strftime("%H:%M"), + \} + + for l:template in g:wiki_templates + if s:template_match(l:template, l:context) + return s:template_apply(l:template, l:context) + endif + endfor + let l:match = matchlist(expand('%:t:r'), '^\(\d\d\d\d\)_\(\w\)\(\d\d\)$') if empty(l:match) | return | endif let [l:year, l:type, l:number] = l:match[1:3] @@ -20,6 +35,28 @@ endfunction " }}}1 +function! s:template_match(t, ctx) abort " {{{1 + if has_key(a:t, 'match_re') + return a:ctx.name =~# a:t.match_re + elseif has_key(a:t, 'match_func') + return a:t.match_func(a:ctx) + endif +endfunction + +" }}}1 +function! s:template_apply(t, ctx) abort " {{{1 + if has_key(a:t, 'source_func') + return a:t.source_func(a:ctx) + endif + + let l:source = get(a:t, 'source_filename', '') + if !filereadable(l:source) | return | endif + + call append(0, readfile(l:source)) +endfunction + +" }}}1 + function! wiki#template#weekly_summary(year, week) abort " {{{1 let l:parser = s:summary.new() diff --git a/plugin/wiki.vim b/plugin/wiki.vim index dd25988f..89e5c5f0 100644 --- a/plugin/wiki.vim +++ b/plugin/wiki.vim @@ -58,6 +58,7 @@ call wiki#init#option('wiki_root', '') call wiki#init#option('wiki_tags', { 'output' : 'loclist' }) call wiki#init#option('wiki_tags_format_pattern', '\v%(^|\s):\zs[^: ]+\ze:') call wiki#init#option('wiki_tags_scan_num_lines', 15) +call wiki#init#option('wiki_templates', []) call wiki#init#option('wiki_template_title_month', \ '# Summary, %(year) %(month-name)') call wiki#init#option('wiki_template_title_week', From 4b4b3549f74a1c6b9a0370d74c72f5dac63a07f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Tue, 29 Jun 2021 23:03:29 +0200 Subject: [PATCH 07/10] test: for templates - wip --- test/test-templates/Makefile | 11 +++++++ test/test-templates/template-a.md | 1 + test/test-templates/test.vim | 55 +++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 test/test-templates/Makefile create mode 100644 test/test-templates/template-a.md create mode 100644 test/test-templates/test.vim diff --git a/test/test-templates/Makefile b/test/test-templates/Makefile new file mode 100644 index 00000000..7f520be0 --- /dev/null +++ b/test/test-templates/Makefile @@ -0,0 +1,11 @@ +MYVIM ?= nvim --headless +export QUIT = 1 + +tests := $(wildcard test*.vim) + +.PHONY: all $(tests) + +test: $(tests) + +$(tests): + @$(MYVIM) -u $@ diff --git a/test/test-templates/template-a.md b/test/test-templates/template-a.md new file mode 100644 index 00000000..557db03d --- /dev/null +++ b/test/test-templates/template-a.md @@ -0,0 +1 @@ +Hello World diff --git a/test/test-templates/test.vim b/test/test-templates/test.vim new file mode 100644 index 00000000..9126746a --- /dev/null +++ b/test/test-templates/test.vim @@ -0,0 +1,55 @@ +source ../init.vim + +function! TemplateB(context) abort " {{{1 + call append(0, [ + \ 'Hello from TemplateB function!', + \ string(a:context), + \]) +endfunction + +" }}}1 +let g:wiki_root = g:testroot . '/wiki-basic' +let g:wiki_templates = [ + \ { + \ 'match_re': '^Template A', + \ 'source_filename': g:testroot . '/test-templates/template-a.md' + \ }, + \ { + \ 'match_re': '^Template B', + \ 'source_func': function('TemplateB') + \ }, + \] + +runtime plugin/wiki.vim + +call wiki#page#open('Template B') +" call assert_true(b:wiki.in_journal) + +" bwipeout! +" let g:wiki_journal.date_format.daily = '%d.%m.%Y' +" let s:date = strftime(g:wiki_journal.date_format[g:wiki_journal.frequency]) +" silent call wiki#journal#make_note() +" call assert_equal(s:date, expand('%:t:r')) + +" let s:step = index(sort(['01.02.2019', s:date]), s:date) +" \ ? -1 : 1 +" silent call wiki#journal#go(s:step) +" call assert_equal('01.02.2019', expand('%:t:r')) + +" silent bwipeout! +" let g:wiki_journal.frequency = 'weekly' +" let s:date = strftime(g:wiki_journal.date_format[g:wiki_journal.frequency]) +" silent call wiki#journal#make_note() +" call assert_equal(expand('%:t:r'), s:date) +" silent call wiki#journal#go(-1) +" call assert_equal(expand('%:t:r'), '2019_w02') + +" silent bwipeout! +" let g:wiki_journal.frequency = 'monthly' +" let s:date = strftime(g:wiki_journal.date_format[g:wiki_journal.frequency]) +" silent call wiki#journal#make_note() +" call assert_equal(expand('%:t:r'), s:date) +" silent call wiki#journal#go(-1) +" call assert_equal(expand('%:t:r'), '2019_m02') + +" call wiki#test#finished() From e9e45388f552565c2be00c634b0b35bb450c7b55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Tue, 29 Jun 2021 23:16:46 +0200 Subject: [PATCH 08/10] test: improved test function --- test/test-templates/test.vim | 46 +++++++++++++----------------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/test/test-templates/test.vim b/test/test-templates/test.vim index 9126746a..f571c1b4 100644 --- a/test/test-templates/test.vim +++ b/test/test-templates/test.vim @@ -3,7 +3,8 @@ source ../init.vim function! TemplateB(context) abort " {{{1 call append(0, [ \ 'Hello from TemplateB function!', - \ string(a:context), + \ a:context.name, + \ a:context.path_wiki, \]) endfunction @@ -18,38 +19,23 @@ let g:wiki_templates = [ \ 'match_re': '^Template B', \ 'source_func': function('TemplateB') \ }, + \ { + \ 'match_func': {_ -> v:true}, + \ 'source_func': {_ -> append(0, ['Fallback'])} + \ }, \] runtime plugin/wiki.vim -call wiki#page#open('Template B') -" call assert_true(b:wiki.in_journal) - -" bwipeout! -" let g:wiki_journal.date_format.daily = '%d.%m.%Y' -" let s:date = strftime(g:wiki_journal.date_format[g:wiki_journal.frequency]) -" silent call wiki#journal#make_note() -" call assert_equal(s:date, expand('%:t:r')) - -" let s:step = index(sort(['01.02.2019', s:date]), s:date) -" \ ? -1 : 1 -" silent call wiki#journal#go(s:step) -" call assert_equal('01.02.2019', expand('%:t:r')) - -" silent bwipeout! -" let g:wiki_journal.frequency = 'weekly' -" let s:date = strftime(g:wiki_journal.date_format[g:wiki_journal.frequency]) -" silent call wiki#journal#make_note() -" call assert_equal(expand('%:t:r'), s:date) -" silent call wiki#journal#go(-1) -" call assert_equal(expand('%:t:r'), '2019_w02') +silent call wiki#page#open('Template B') +call assert_equal([ + \ 'Hello from TemplateB function!', + \ 'Template B', + \ 'Template B.wiki', + \], getline(1, line('$') - 1)) -" silent bwipeout! -" let g:wiki_journal.frequency = 'monthly' -" let s:date = strftime(g:wiki_journal.date_format[g:wiki_journal.frequency]) -" silent call wiki#journal#make_note() -" call assert_equal(expand('%:t:r'), s:date) -" silent call wiki#journal#go(-1) -" call assert_equal(expand('%:t:r'), '2019_m02') +bwipeout +silent call wiki#page#open('Template C') +call assert_equal('Fallback', getline(1)) -" call wiki#test#finished() +call wiki#test#finished() From 882fd8e0166fb231f61598cb90ee3c0d200055aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Fri, 2 Jul 2021 00:03:18 +0200 Subject: [PATCH 09/10] feat: template interpolation --- autoload/wiki/template.vim | 35 ++++++++++++++++++++++++++++++- doc/wiki.txt | 4 +++- test/test-templates/template-a.md | 3 ++- test/test-templates/template-d.md | 1 + test/test-templates/test.vim | 20 ++++++++++++++++++ 5 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 test/test-templates/template-d.md diff --git a/autoload/wiki/template.vim b/autoload/wiki/template.vim index e5f9591d..dcd721e0 100644 --- a/autoload/wiki/template.vim +++ b/autoload/wiki/template.vim @@ -35,6 +35,13 @@ endfunction " }}}1 +function! wiki#template#case_title(text, ...) abort " {{{1 + return join(map(split(a:text), {_, x -> toupper(x[0]) . strpart(x, 1)})) +endfunction + +" }}}1 + + function! s:template_match(t, ctx) abort " {{{1 if has_key(a:t, 'match_re') return a:ctx.name =~# a:t.match_re @@ -52,7 +59,33 @@ function! s:template_apply(t, ctx) abort " {{{1 let l:source = get(a:t, 'source_filename', '') if !filereadable(l:source) | return | endif - call append(0, readfile(l:source)) + " Interpolate the context "variables" + let l:lines = join(readfile(l:source), "\n") + for [l:key, l:value] in items(a:ctx) + let l:lines = substitute(l:lines, '{' . l:key . '}', l:value, 'g') + endfor + + " Interpolate user functions + let [l:match, l:c1, l:c2] = matchstrpos(l:lines, '{{[a-zA-Z#_]\+\s\+[^}]*}}') + while !empty(l:match) + let l:parts = matchlist(l:match, '{{\([a-zA-Z#_]\+\)\s\+\([^}]*\)}}') + let l:func = l:parts[1] + let l:arg = l:parts[2] + try + let l:value = call(l:func, [l:arg]) + catch /E117:/ + let l:value = '' + endtry + + let l:pre = l:lines[:l:c1-1] + let l:post = l:lines[l:c2:] + let l:lines = l:pre . l:value . l:post + + let [l:match, l:c1, l:c2] = matchstrpos( + \ l:lines, '{{[a-zA-Z#_]\+\s\+[^}]*}}', l:c2+1) + endwhile + + call append(0, split(l:lines, "\n")) endfunction " }}}1 diff --git a/doc/wiki.txt b/doc/wiki.txt index 97db7878..d54eddca 100644 --- a/doc/wiki.txt +++ b/doc/wiki.txt @@ -1245,7 +1245,9 @@ two rules that allow dynamic templates: 1. Variable substitution with `{variable}` strings. The allowed variables are the same as those available in |wiki-templates-context|. - 2. Function substitution with `{{Function Arg1 Arg2 ...}}` strings. The + 2. Function substitution with `{{Function Text String Here}}` strings. The + text string is passed as a single string argument. The context dictionary + (|wiki-templates-context|) is also passed as the second argument. The function is assumed to return either a string or a list of strings. The first rule is applied first, which allows the arguments in Rule 2 to be diff --git a/test/test-templates/template-a.md b/test/test-templates/template-a.md index 557db03d..24ae562d 100644 --- a/test/test-templates/template-a.md +++ b/test/test-templates/template-a.md @@ -1 +1,2 @@ -Hello World +# {{UserFunc {name}}} +Created: {date} {time} diff --git a/test/test-templates/template-d.md b/test/test-templates/template-d.md new file mode 100644 index 00000000..beef43e4 --- /dev/null +++ b/test/test-templates/template-d.md @@ -0,0 +1 @@ +# {{wiki#template#case_title {name}}} diff --git a/test/test-templates/test.vim b/test/test-templates/test.vim index f571c1b4..8fa1bdb3 100644 --- a/test/test-templates/test.vim +++ b/test/test-templates/test.vim @@ -1,5 +1,10 @@ source ../init.vim +function! UserFunc(string) abort " {{{1 + return toupper(a:string) +endfunction + +" }}}1 function! TemplateB(context) abort " {{{1 call append(0, [ \ 'Hello from TemplateB function!', @@ -20,6 +25,10 @@ let g:wiki_templates = [ \ 'source_func': function('TemplateB') \ }, \ { + \ 'match_re': '^case titled template', + \ 'source_filename': g:testroot . '/test-templates/template-d.md' + \ }, + \ { \ 'match_func': {_ -> v:true}, \ 'source_func': {_ -> append(0, ['Fallback'])} \ }, @@ -27,6 +36,13 @@ let g:wiki_templates = [ runtime plugin/wiki.vim +silent call wiki#page#open('Template A') +call assert_equal([ + \ '# TEMPLATE A', + \ 'Created: ' . strftime("%F") . ' ' . strftime("%H:%M"), + \], getline(1, line('$') - 1)) + +bwipeout silent call wiki#page#open('Template B') call assert_equal([ \ 'Hello from TemplateB function!', @@ -38,4 +54,8 @@ bwipeout silent call wiki#page#open('Template C') call assert_equal('Fallback', getline(1)) +bwipeout +silent call wiki#page#open('case titled template') +call assert_equal(['# Case Titled Template'], getline(1, line('$') - 1)) + call wiki#test#finished() From 002e10b17f9921829e42aadff0f8eb97ad2aa071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Fri, 2 Jul 2021 00:05:30 +0200 Subject: [PATCH 10/10] doc: updated filename description --- doc/wiki.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/wiki.txt b/doc/wiki.txt index d54eddca..5043b539 100644 --- a/doc/wiki.txt +++ b/doc/wiki.txt @@ -526,9 +526,9 @@ OPTIONS *wiki-config-options* source_filename~ |String| - The name of a template file. If filename ends with `;`, then the file is - searched upwards similar to the description in the second type of search - in |file-searching|. Note: If the template file is not found, then the + The path to a template file. If this is a relative path, then it will be + relative to whichever path Vim or neovim is currently at when the + template is executed. If the template file is not found, then the template will not be applied and the next template in the list will be tried. @@ -548,7 +548,7 @@ OPTIONS *wiki-config-options* \ { 'match_re': 'index\.md', \ 'source_filename': '/home/user/templates/index.md'}, \ { 'match_re': 'foo\.md', - \ 'source_filename': '.footemplate.md;'}, + \ 'source_filename': '.footemplate.md'}, \ { 'match_func': {x -> v:true}, \ 'source_func': function('TemplateFallback')}, \]