From e45380e3d27c7fa361434f88a4654ae409cbfa3a Mon Sep 17 00:00:00 2001 From: EinfachToll Date: Tue, 15 May 2018 20:47:12 +0200 Subject: [PATCH] Unify path handling -- part 6 --- autoload/vimwiki/base.vim | 136 ++++++++++++++++---------------------- autoload/vimwiki/html.vim | 12 ++-- autoload/vimwiki/path.vim | 28 +++++--- autoload/vimwiki/vars.vim | 5 -- doc/vimwiki.txt | 9 +-- ftplugin/vimwiki.vim | 2 +- 6 files changed, 86 insertions(+), 106 deletions(-) diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim index 971bfae..b734963 100644 --- a/autoload/vimwiki/base.vim +++ b/autoload/vimwiki/base.vim @@ -43,53 +43,13 @@ function! vimwiki#base#file_pattern(files) endfunction -"FIXME TODO slow and faulty -function! vimwiki#base#subdir(path, filename) - 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? - if a:filename !~# '^scp:' - let filename = resolve(a:filename) - else - let filename = a:filename - endif - let idx = 0 - "FIXME this can terminate in the middle of a path component! - while path[idx] ==? filename[idx] - let idx = idx + 1 - endwhile - - let p = split(strpart(filename, idx), '[/\\]') - let res = join(p[:-2], '/') - if len(res) > 0 - let res = res.'/' - endif - return res -endfunction - - -function! vimwiki#base#current_subdir() - return vimwiki#base#subdir(vimwiki#vars#get_wikilocal('path'), expand('%:p')) -endfunction - - -function! vimwiki#base#invsubdir(subdir) - return substitute(a:subdir, '[^/\.]\+/', '../', 'g') -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) - let path = vimwiki#path#path_norm(vimwiki#path#chomp_slash(a:path)) +function! vimwiki#base#find_wiki(file) for idx in range(vimwiki#vars#number_of_wikis()) - let idx_path = expand(vimwiki#vars#get_wikilocal('path', idx)) - let idx_path = vimwiki#path#path_norm(vimwiki#path#chomp_slash(idx_path)) - if vimwiki#path#is_equal(vimwiki#path#path_common_pfx(idx_path, path), idx_path) + if vimwiki#path#is_file_in_dir(a:file, vimwiki#vars#get_wikilocal('path', idx)) return idx endif - let idx += 1 endfor " an orphan page has been detected @@ -97,10 +57,9 @@ function! vimwiki#base#find_wiki(path) 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. +" Extract infos about the target from a link. If the second parameter is present, which should be a +" file object, it is assumed that the link appears in that file. Without it, the current file is +" used. function! vimwiki#base#resolve_link(link_text, ...) if a:0 let source_wiki = vimwiki#base#find_wiki(a:1) @@ -121,7 +80,9 @@ function! vimwiki#base#resolve_link(link_text, ...) let link_infos = { \ 'index': -1, \ 'scheme': '', - \ 'filename': '', " XXX das sollte file heißen und ein file_obj ergeben. Was passiert bei http://bla.blubb? + \ 'is_file': 0, " 1 for a file, 0 for a URL (e.g. when the link was [[http://foo.bar]]), + \ " -1 if the whole link was malformed + \ 'target': '', " this is a file or dir object if is_file == 1, otherwise a string \ 'anchor': '', \ } @@ -129,13 +90,18 @@ function! vimwiki#base#resolve_link(link_text, ...) " extract scheme let link_infos.scheme = matchstr(link_text, vimwiki#vars#get_global('rxSchemeUrlMatchScheme')) if link_infos.scheme == '' || link_text == '' - let link_infos.filename = '' " malformed link + let link_infos.is_file = -1 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 + " unknown scheme, may be a weblink + let link_infos.is_file = 0 + let link_infos.target = link_text return link_infos endif + + let link_infos.is_file = 1 + let link_text = matchstr(link_text, vimwiki#vars#get_global('rxSchemeUrlMatchUrl')) let is_wiki_link = link_infos.scheme =~# '\mwiki\d\+' || link_infos.scheme ==# 'diary' @@ -148,10 +114,12 @@ function! vimwiki#base#resolve_link(link_text, ...) let link_infos.anchor = join(split_lnk[1:], '#') endif if link_text == '' " because the link was of the form '#anchor' - let link_text = fnamemodify(source_file, ':p:t:r') + let link_text = vimwiki#path#filename_without_extension(source_file) endif endif + let link_tail = vimwiki#path#file_segment(link_text) + " check if absolute or relative path if is_wiki_link && link_text[0] == '/' if link_text != '/' @@ -162,7 +130,7 @@ function! vimwiki#base#resolve_link(link_text, ...) let is_relative = 0 else let is_relative = 1 - let root_dir = fnamemodify(source_file, ':p:h') . '/' + let root_dir = vimwiki#path#directory_of_file(source_file) endif @@ -170,43 +138,51 @@ function! vimwiki#base#resolve_link(link_text, ...) 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.filename = '' + let link_infos.is_file = -1 return link_infos endif - if !is_relative || link_infos.index != source_wiki + if link_text[0] == '/' || link_infos.index != source_wiki let root_dir = vimwiki#vars#get_wikilocal('path', link_infos.index) - endif - - let link_infos.filename = root_dir . link_text - - if vimwiki#path#is_link_to_dir(link_text) - 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) + if link_text != '/' + let link_text = link_text[1:] endif else - let link_infos.filename .= vimwiki#vars#get_wikilocal('ext', link_infos.index) + let root_dir = vimwiki#path#directory_of_file(source_file) + endif + + if link_text =~# '\m[/\\]$' + if vimwiki#vars#get_global('dir_link') == '' + let target_dir = vimwiki#path#dir_segment(link_text) + let link_infos.target = vimwiki#path#join_dir(root_dir, target_dir) + else + let link_text .= vimwiki#vars#get_global('dir_link') . + \ vimwiki#vars#get_wikilocal('ext', link_infos.index) + let target_file = vimwiki#path#file_segment(link_text) + let link_infos.target = vimwiki#path#join(root_dir, target_file) + endif + else + let link_text .= vimwiki#vars#get_wikilocal('ext', link_infos.index) + let target_file = vimwiki#path#file_segment(link_text) + let link_infos.target = vimwiki#path#join(root_dir, target_file) endif elseif link_infos.scheme ==# 'diary' let link_infos.index = source_wiki - let link_infos.filename = - \ vimwiki#vars#get_wikilocal('diary_path', link_infos.index) . - \ link_text . - \ vimwiki#vars#get_wikilocal('ext', link_infos.index) - elseif (link_infos.scheme ==# 'file' || link_infos.scheme ==# 'local') && is_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^/\+', '/', '') - " expand ~/ - let link_text = fnamemodify(link_text, ':p') - let link_infos.filename = simplify(link_text) + let root_dir = vimwiki#vars#get_wikilocal('diary_path', link_infos.index) + let target_file = vimwiki#path#file_segment(link_text . + \ vimwiki#vars#get_wikilocal('ext', link_infos.index)) + let link_infos.target = vimwiki#path#join(root_dir, target_file) + elseif (link_infos.scheme ==# 'file' || link_infos.scheme ==# 'local') && + \ vimwiki#path#is_absolute(link_text) + let link_infos.target = vimwiki#path#file_obj(link_text) + else " relative file link + let root_dir = vimwiki#path#directory_of_file(source_file) + let target_file = vimwiki#path#file_segment(link_text) + let link_infos.target = vimwiki#path#join(root_dir, target_file) endif - let link_infos.filename = vimwiki#path#normalize(link_infos.filename) return link_infos endfunction @@ -262,7 +238,7 @@ function! vimwiki#base#open_link(cmd, link, ...) let link_infos = vimwiki#base#resolve_link(a:link) endif - if link_infos.filename == '' + if link_infos.is_file == -1 echomsg 'Vimwiki Error: Unable to resolve link!' return endif @@ -270,7 +246,7 @@ function! vimwiki#base#open_link(cmd, link, ...) 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()) + \ !vimwiki#path#is_equal(link_infos.target, vimwiki#path#current_wiki_file()) let vimwiki_prev_link = [] " update previous link for wiki pages @@ -284,10 +260,10 @@ 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, + call vimwiki#base#edit_file(a:cmd, link_infos.target, link_infos.anchor, \ vimwiki_prev_link, update_prev_link) else - call vimwiki#base#system_open_link(link_infos.filename) + call vimwiki#base#system_open_link(link_infos.target) endif endfunction @@ -593,7 +569,7 @@ function! s:get_links(wikifile, idx) 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.is_file != -1 && target.scheme =~# '\mwiki\d\+\|diary\|file\|local' call add(links, [target.filename, target.anchor, lnum, col]) endif endwhile diff --git a/autoload/vimwiki/html.vim b/autoload/vimwiki/html.vim index b4c3269..197ac11 100644 --- a/autoload/vimwiki/html.vim +++ b/autoload/vimwiki/html.vim @@ -391,14 +391,14 @@ function! s:tag_wikiincl(value) if link_infos.scheme =~# '\mlocal\|wiki\d\+\|diary' let url = vimwiki#path#relpath(vimwiki#path#directory_of_file(s:current_html_file), - \ link_infos.filename) + \ link_infos.target) " 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 = vimwiki#path#filename_without_extension(url) endif else - let url = link_infos.file + let url = link_infos.target endif let url = escape(vimwiki#path#to_string(url), '#') @@ -427,17 +427,17 @@ function! s:tag_wikilink(value) if link_infos.scheme ==# 'file' " external file links are always absolute - let html_link = vimwiki#path#to_string(link_infos.file) + let html_link = vimwiki#path#to_string(link_infos.target) elseif link_infos.scheme ==# 'local' let html_link = vimwiki#path#to_string(vimwiki#path#relpath( - \ vimwiki#path#directory_of_file(s:current_html_file), link_infos.file)) + \ vimwiki#path#directory_of_file(s:current_html_file), link_infos.target)) elseif link_infos.scheme =~# '\mwiki\d\+\|diary' " wiki links are always relative to the current file - let target_html_file = s:corresponding_html_file(link_infos.file) + let target_html_file = s:corresponding_html_file(link_infos.target) let html_link = vimwiki#path#to_string(vimwiki#path#relpath( \ vimwiki#path#directory_of_file(s:current_html_file), target_html_file)) else " other schemes, like http, are left untouched - let html_link = vimwiki#path#to_string(link_infos.file) + let html_link = link_infos.target endif if link_infos.anchor != '' diff --git a/autoload/vimwiki/path.vim b/autoload/vimwiki/path.vim index 3a68892..ec19d4f 100644 --- a/autoload/vimwiki/path.vim +++ b/autoload/vimwiki/path.vim @@ -49,13 +49,6 @@ function! vimwiki#path#path_norm(path) endfunction -function! vimwiki#path#is_link_to_dir(link) - " Check if link is to a directory. - " It should be ended with \ or /. - return a:link =~# '\m[/\\]$' -endfunction - - function! vimwiki#path#abs_path_of_link(link) return vimwiki#path#normalize(expand("%:p:h").'/'.a:link) endfunction @@ -153,11 +146,11 @@ function! vimwiki#path#mkdir(dir_obj, ...) endfunction -function! vimwiki#path#is_absolute(path) +function! vimwiki#path#is_absolute(path_string) if vimwiki#u#is_windows() - return a:path =~? '\m^\a:' + return a:path_string =~? '\m^\a:' else - return a:path =~# '\m^/\|\~/' + return a:path_string =~# '\m^/\|\~/' endif endfunction @@ -373,6 +366,21 @@ function! vimwiki#path#relpath(dir1_object, dir2_object) endfunction +function! vimwiki#path#is_file_in_dir(file, dir) + let file_path_segments = a:file[0].path + let dir_path_segments = a:dir.path + if len(dir_path_segments) > len(file_path_segments) + return 0 + endif + for i in range(len(a:dir.path)) + if !vimwiki#path#is_equal(a:dir.path[i], file_path_segments[i]) + return 0 + endif + endfor + return 1 +endfunction + + "----------------- " File manipulation, i.e. do stuff with actually existing files "----------------- diff --git a/autoload/vimwiki/vars.vim b/autoload/vimwiki/vars.vim index 455695e..d6f6480 100644 --- a/autoload/vimwiki/vars.vim +++ b/autoload/vimwiki/vars.vim @@ -668,11 +668,6 @@ function! vimwiki#vars#get_bufferlocal(key, ...) return value elseif a:key ==# 'wiki_nr' call setbufvar(buffer, 'vimwiki_wiki_nr', vimwiki#base#find_wiki(vimwiki#path#current_file())) - elseif a:key ==# 'subdir' - call setbufvar(buffer, 'vimwiki_subdir', vimwiki#base#current_subdir()) - elseif a:key ==# 'invsubdir' - let subdir = vimwiki#vars#get_bufferlocal('subdir') - call setbufvar(buffer, 'vimwiki_invsubdir', vimwiki#base#invsubdir(subdir)) elseif a:key ==# 'existing_wikifiles' call setbufvar(buffer, 'vimwiki_existing_wikifiles', \ vimwiki#base#get_wikilinks(vimwiki#vars#get_bufferlocal('wiki_nr'), 0, 1)) diff --git a/doc/vimwiki.txt b/doc/vimwiki.txt index 92ce907..0dac5e5 100644 --- a/doc/vimwiki.txt +++ b/doc/vimwiki.txt @@ -2540,11 +2540,11 @@ A second example handles a new scheme, "vfile:", which behaves similar to return 0 endif let link_infos = vimwiki#base#resolve_link(link) - if link_infos.filename == '' + if link_infos.is_file == -1 echomsg 'Vimwiki Error: Unable to resolve link!' return 0 else - exe 'tabnew ' . fnameescape(link_infos.filename) + exe 'tabnew ' . fnameescape(vimwiki#path#to_string(link_infos.target)) return 1 endif endfunction @@ -2569,11 +2569,12 @@ right place. > function! VimwikiLinkConverter(link, source_wiki_file, target_html_file) if a:link =~# '^local:' let link_infos = vimwiki#base#resolve_link(a:link) + let target_file = vimwiki#path#to_string(link_infos.target) let html_link = vimwiki#path#relpath( - \ fnamemodify(a:source_wiki_file, ':h'), link_infos.filename) + \ fnamemodify(a:source_wiki_file, ':h'), target_file) let relative_link = \ fnamemodify(a:target_html_file, ':h') . '/' . html_link - call system('cp ' . fnameescape(link_infos.filename) . + call system('cp ' . fnameescape(target_file) . \ ' ' . fnameescape(relative_link)) return html_link endif diff --git a/ftplugin/vimwiki.vim b/ftplugin/vimwiki.vim index fc3361d..df35e5c 100644 --- a/ftplugin/vimwiki.vim +++ b/ftplugin/vimwiki.vim @@ -100,7 +100,7 @@ function! Complete_wikifiles(findstart, base) \ vimwiki#path#filename_without_extension(vimwiki#path#current_file()) \ : segments[0] let link_infos = vimwiki#base#resolve_link(given_wikifile.'#') - let wikifile = link_infos.path + let wikifile = link_infos.target let syntax = vimwiki#vars#get_wikilocal('syntax', link_infos.index) let anchors = vimwiki#base#get_anchors(wikifile, syntax)