diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim index 9b87cf9..0fbff78 100644 --- a/autoload/vimwiki/base.vim +++ b/autoload/vimwiki/base.vim @@ -270,16 +270,20 @@ function! vimwiki#base#resolve_link(link_text, ...) "{{{ \ 'scheme': '', \ 'filename': '', \ 'anchor': '', + \ 'relative': 0, \ } " extract scheme let link_infos.scheme = matchstr(link_text, g:vimwiki_rxSchemeUrlMatchScheme) - if !(link_infos.scheme =~# '\mwiki\d\+' || link_infos.scheme ==# 'diary' || - \ link_infos.scheme ==# 'local' || link_infos.scheme ==# 'file') + if link_infos.scheme == '' || link_text == '' let link_infos.filename = '' " malformed link return link_infos endif + if link_infos.scheme !~# '\mwiki\d\+\|diary\|local\|file' + let link_infos.filename = link_text " unknown scheme, may be a weblink + return link_infos + endif let link_text = matchstr(link_text, g:vimwiki_rxSchemeUrlMatchUrl) let is_wiki_link = link_infos.scheme =~# '\mwiki\d\+' || @@ -300,12 +304,11 @@ function! vimwiki#base#resolve_link(link_text, ...) "{{{ " check if absolute or relative path if is_wiki_link && link_text[0] == '/' let link_text = link_text[1:] - let is_relative = 0 - elseif !is_wiki_link && (link_text[0] == '/' || - \ (link_text =~? '\m^\a:' && vimwiki#u#is_windows())) - let is_relative = 0 + let link_infos.relative = 0 + elseif !is_wiki_link && vimwiki#path#is_absolute(link_text) + let link_infos.relative = 0 else - let is_relative = 1 + let link_infos.relative = 1 let root_dir = fnamemodify(source_file, ':p:h') . '/' endif @@ -318,7 +321,7 @@ function! vimwiki#base#resolve_link(link_text, ...) "{{{ return link_infos endif - if !is_relative || link_infos.index != source_wiki + if !link_infos.relative || link_infos.index != source_wiki let root_dir = VimwikiGet('path', link_infos.index) endif @@ -341,19 +344,15 @@ function! vimwiki#base#resolve_link(link_text, ...) "{{{ \ VimwikiGet('diary_rel_path', link_infos.index) . \ link_text . \ VimwikiGet('ext', link_infos.index) - elseif (link_infos.scheme ==# 'file' && is_relative) || - \ link_infos.scheme ==# 'local' - let link_infos.filename = root_dir . link_text + elseif (link_infos.scheme ==# 'file' || link_infos.scheme ==# 'local') + \ && link_infos.relative + let link_infos.filename = simplify(root_dir . link_text) else " absolute file link " collapse repeated leading "/"'s within a link - let link_text = substitute(link_text, '\m^/*', '/', '') - " convert "/~..." into "~..." for fnamemodify - let link_text = substitute(link_text, '\m^/\~', '\~', '') - " convert /C: to C: (or fnamemodify(...":p:h") interpret it as C:\C:) - if vimwiki#u#is_windows() - let link_text = substitute(link_text, '\m^/\ze[[:alpha:]]:', '', '') - endif - let link_infos.filename = link_text + let link_text = substitute(link_text, '\m^/\+', '/', '') + " expand ~/ + let link_text = fnamemodify(link_text, ':p') + let link_infos.filename = simplify(link_text) endif let link_infos.filename = vimwiki#path#normalize(link_infos.filename) @@ -361,146 +360,6 @@ function! vimwiki#base#resolve_link(link_text, ...) "{{{ endfunction "}}} -" vimwiki#base#resolve_scheme -function! vimwiki#base#resolve_scheme(lnk, as_html, ...) " {{{ Resolve scheme - let quiet = a:0 && a:1 ? 1 : 0 - let lnk = a:lnk - - " if link is schemeless add wikiN: scheme - let is_schemeless = lnk !~# g:vimwiki_rxSchemeUrl - let lnk = (is_schemeless ? 'wiki'.g:vimwiki_current_idx.':'.lnk : lnk) - - " Get scheme - let scheme = matchstr(lnk, g:vimwiki_rxSchemeUrlMatchScheme) - " Get link (without scheme) - let lnk = matchstr(lnk, g:vimwiki_rxSchemeUrlMatchUrl) - let path = '' - let subdir = '' - let ext = '' - let idx = -1 - let anchor = '' - - "extract anchor - if scheme =~# 'wiki' || scheme =~# 'diary' - let split_lnk = split(lnk, '#', 1) - let lnk = split_lnk[0] - if len(split_lnk) <= 1 || split_lnk[-1] == '' - let anchor = '' - else - let anchor = join(split_lnk[1:], '#') - endif - endif - - " do nothing if scheme is unknown to vimwiki - if !(scheme =~# 'wiki.*' || scheme =~# 'diary' || scheme =~# 'local' - \ || scheme =~# 'file') - return [idx, scheme, path, subdir, lnk, ext, scheme.':'.lnk, anchor] - endif - - " scheme behaviors - if scheme =~# 'wiki\d\+' - let idx = eval(matchstr(scheme, '\D\+\zs\d\+\ze')) - if idx < 0 || idx >= len(g:vimwiki_list) - if !quiet - echom 'Vimwiki Error: Numbered scheme refers to a non-existent wiki!' - endif - return [idx,'','','','','','', ''] - endif - - if a:as_html - if idx == g:vimwiki_current_idx - let path = VimwikiGet('path_html') - else - let path = VimwikiGet('path_html', idx) - endif - else - if idx == g:vimwiki_current_idx - let path = VimwikiGet('path') - else - let path = VimwikiGet('path', idx) - endif - endif - - " For Issue 310. Otherwise current subdir is used for another wiki. - if idx == g:vimwiki_current_idx - let subdir = VimwikiGet('subdir') - else - let subdir = "" - endif - - if a:as_html - let ext = '.html' - else - if idx == g:vimwiki_current_idx - let ext = VimwikiGet('ext') - else - let ext = VimwikiGet('ext', idx) - endif - endif - - " default link for directories - if vimwiki#path#is_link_to_dir(lnk) - let ext = (g:vimwiki_dir_link != '' ? g:vimwiki_dir_link . ext : '') - endif - elseif scheme =~# 'diary' - if a:as_html - " use cached value (save time when converting diary index!) - let path = VimwikiGet('invsubdir') - let ext = '.html' - else - let path = VimwikiGet('path') - let ext = VimwikiGet('ext') - endif - let idx = g:vimwiki_current_idx - let subdir = VimwikiGet('diary_rel_path') - elseif scheme =~# 'local' - " revisiting the 'lcd'-bug ... - let path = VimwikiGet('path') - let subdir = VimwikiGet('subdir') - if a:as_html - " prepend browser-specific file: scheme - let path = 'file://'.fnamemodify(path, ":p") - endif - elseif scheme =~# 'file' - " RM repeated leading "/"'s within a link - let lnk = substitute(lnk, '^/*', '/', '') - " convert "/~..." into "~..." for fnamemodify - let lnk = substitute(lnk, '^/\~', '\~', '') - " convert /C: to C: (or fnamemodify(...":p:h") interpret it as C:\C: - if vimwiki#u#is_windows() - let lnk = substitute(lnk, '^/\ze[[:alpha:]]:', '', '') - endif - if a:as_html - " prepend browser-specific file: scheme - let path = 'file://'.fnamemodify(lnk, ":p:h").'/' - else - let path = fnamemodify(lnk, ":p:h").'/' - endif - let lnk = fnamemodify(lnk, ":p:t") - let subdir = '' - endif - - - " construct url from parts - if is_schemeless && a:as_html - let scheme = '' - let url = lnk.ext - else - let url = path.subdir.lnk.ext - endif - - " lnk and url should be '' if the given wiki link has the form [[#anchor]]. - " We cannot do lnk = expand('%:t:r') or so, because this function is called - " from vimwiki#html#WikiAll2HTML() for many files, so expand('%:t:r') - " doesn't give the currently processed file - if lnk == '' - let url = '' - endif - - " result - return [idx, scheme, path, subdir, lnk, ext, url, anchor] -endfunction "}}} - " vimwiki#base#system_open_link function! vimwiki#base#system_open_link(url) "{{{ " handlers @@ -868,7 +727,8 @@ function! s:get_links(wikifile, idx) "{{{ endif let link_count += 1 let target = vimwiki#base#resolve_link(link_text, a:wikifile) - if target.filename != '' + if target.filename != '' && + \ target.scheme =~# '\mwiki\d\+\|diary\|file\|local' call add(links, [target.filename, target.anchor, lnum, col]) endif endwhile @@ -986,6 +846,12 @@ function! vimwiki#base#edit_file(command, filename, anchor, ...) "{{{ " getpos() directly after this command. Strange. if !(a:command ==# ':e ' && vimwiki#path#is_equal(a:filename, expand('%:p'))) execute a:command.' '.fname + " 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/$' + set filetype=vimwiki + endif endif if a:anchor != '' call s:jump_to_anchor(a:anchor) diff --git a/autoload/vimwiki/html.vim b/autoload/vimwiki/html.vim index 83aa5e5..bc35dfc 100644 --- a/autoload/vimwiki/html.vim +++ b/autoload/vimwiki/html.vim @@ -372,19 +372,20 @@ function! s:tag_wikiincl(value) "{{{ let url_0 = matchstr(str, g:vimwiki_rxWikiInclMatchUrl) let descr = matchstr(str, vimwiki#html#incl_match_arg(1)) let verbatim_str = matchstr(str, vimwiki#html#incl_match_arg(2)) - " resolve url - let [idx, scheme, path, subdir, lnk, ext, url, anchor] = - \ vimwiki#base#resolve_scheme(url_0, 1, 1) - " generate html output + + let link_infos = vimwiki#base#resolve_link(url_0) + " TODO: migrate non-essential debugging messages into g:VimwikiLog if g:vimwiki_debug > 1 - echom '{{idx='.idx.', scheme='.scheme.', path='.path.', subdir='.subdir.', lnk='.lnk.', ext='.ext.'}}' + echom string(link_infos) endif - " Issue 343: Image transclusions: schemeless links have .html appended. - " If link is schemeless pass it as it is - if scheme == '' - let url = lnk + let url = link_infos.filename + + " strip the .html extension when we have wiki links, so that the user can + " simply write {{image.png}} to include an image from the wiki directory + if link_infos.scheme =~# '\mwiki\d\+\|diary' + let url = fnamemodify(url, ':r') endif let url = escape(url, '#') @@ -406,20 +407,40 @@ function! s:tag_wikilink(value) "{{{ let descr = matchstr(str, g:vimwiki_rxWikiLinkMatchDescr) let descr = (substitute(descr,'^\s*\(.*\)\s*$','\1','') != '' ? descr : url) - " resolve url - let [idx, scheme, path, subdir, lnk, ext, url, anchor] = - \ vimwiki#base#resolve_scheme(url, 1, 1) + let line = VimwikiLinkConverter(url, s:current_wiki_file, + \ s:current_html_file) + if line == '' + let link_infos = vimwiki#base#resolve_link(url, s:current_wiki_file) - " generate html output - " TODO: migrate non-essential debugging messages into g:VimwikiLog - if g:vimwiki_debug > 1 - echom '[[idx='.idx.', scheme='.scheme.', path='.path.', subdir='.subdir.', lnk='.lnk.', ext='.ext.']]' + if link_infos.scheme ==# 'file' || link_infos.scheme ==# 'local' + " external file links are always absolute + let html_link = link_infos.filename + else + " wiki links are always relative to the current file + echom link_infos.filename fnamemodify(s:current_wiki_file, ':h') fnamemodify(link_infos.filename, ':r') + let html_link = vimwiki#path#relpath( + \ fnamemodify(s:current_wiki_file, ':h'), + \ fnamemodify(link_infos.filename, ':r')) + echom html_link + if html_link !~ '\m/$' + let html_link .= '.html' + endif + endif + + " generate html output + " TODO: migrate non-essential debugging messages into g:VimwikiLog + if g:vimwiki_debug > 1 + echom string(link_infos) + endif + + if link_infos.anchor != '' + let anchor = substitute(link_infos.anchor, '#', '-', 'g') + let html_link .= '#'.anchor + endif + let line = html_link endif - if anchor != '' - let anchor = substitute(anchor, '#', '-', 'g') - let url .= '#'.anchor - endif - let line = vimwiki#html#linkify_link(url, descr) + + let line =vimwiki#html#linkify_link(line, descr) return line endfunction "}}} "}}} @@ -1338,6 +1359,11 @@ function! vimwiki#html#Wiki2HTML(path_html, wikifile) "{{{ let path_html = expand(a:path_html).VimwikiGet('subdir') let htmlfile = fnamemodify(wikifile, ":t:r").'.html' + " the currently processed file name is needed when processing links + " yeah yeah, shame on me for using (quasi-) global variables + let s:current_wiki_file = wikifile + let s:current_html_file = path_html . htmlfile + if s:use_custom_wiki2html() let force = 1 call vimwiki#html#CustomWiki2HTML(path_html, wikifile, force) diff --git a/autoload/vimwiki/path.vim b/autoload/vimwiki/path.vim index dcadb38..5cca141 100644 --- a/autoload/vimwiki/path.vim +++ b/autoload/vimwiki/path.vim @@ -92,13 +92,20 @@ function! vimwiki#path#relpath(dir, file) "{{{ call remove(dir, 0) call remove(file, 0) endwhile + if empty(dir) && empty(file) + return './' + endif for segment in dir let result += ['..'] endfor for segment in file let result += [segment] endfor - return join(result, '/') + let result_path = join(result, '/') + if a:file =~ '\m/$' + let result_path .= '/' + endif + return result_path endfunction "}}} " If the optional argument provided and nonzero, @@ -133,3 +140,11 @@ function! vimwiki#path#mkdir(path, ...) "{{{ return 1 endif endfunction " }}} + +function! vimwiki#path#is_absolute(path) "{{{ + if vimwiki#u#is_windows() + return a:path =~? '\m^\a:' + else + return a:path =~# '\m^/\|\~/' + endif +endfunction "}}} diff --git a/doc/vimwiki.txt b/doc/vimwiki.txt index 2203998..d85c0f5 100644 --- a/doc/vimwiki.txt +++ b/doc/vimwiki.txt @@ -762,11 +762,27 @@ Link with spaces in it: > or: > [[This is a link source|Description of the link]] -Links to directories (ending with a "/") are also supported: > - [[/home/somebody/|Home Directory]] +Wiki files don't need to be in the root directory of your wiki, you can put +them in subdirectories as well: > + [[projects/Important Project 1]] +To jump from that file back to the index file, use this link: > + [[../index]] +or: > + [[/index]] +The latter works, because wiki links starting with "/" are considered to be +absolute to the wiki root directory, that is, the link [[/index]] always opens +the file /path/to/your/wiki/index.wiki, no matter in which subdirectory you +are currently in. +Links to directories (ending with a "/") are also supported: > + [[a subdirectory/|Other files]] Use |g:vimwiki_dir_link| to control the behavior when opening directories. +Typing wikilinks can be simplified by using Vim's omni completion (see +|compl-omni|) like so: > + [[ind +which opens up a popup menu with all the wiki files starting with "ind". + Raw URLs~ Raw URLs are also supported: >