dotfiles/plugin/utl.vim

1847 lines
66 KiB
VimL
Raw Normal View History

2021-10-01 00:04:18 +02:00
" ------------------------------------------------------------------------------
" File: plugin/utl.vim - Universal Text Linking -
" URL based Hyperlinking for plain text
" Author: Stefan Bittner <stb@bf-consulting.de>
" Maintainer: Stefan Bittner <stb@bf-consulting.de>
"
" Licence: This program is free software; you can redistribute it and/or
" modify it under the terms of the GNU General Public License.
" See http://www.gnu.org/copyleft/gpl.txt
" This program is distributed in the hope that it will be
" useful, but WITHOUT ANY WARRANTY; without even the implied
" warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"
" Version: 3.0a ALPHA
"
" Docs: for online help type: :help utl-plugin
"
" Files: The Utl plugin consists of the following files:
" plugin/{utl.vim,utl_scm.vim,utl_uri.vim,utl_rc.vim}
" doc/utl_usr.txt
"
" History:
" 1.0 2001-04-26
" First release for vim5 under the name thlnk.vim
" 1.1 2002-05-07
" As plugin for vim6 with heavily revised documentation and homepage
" 1.2 2002-06-14
" Two bug fixes, better error messages, largely enhanced documentation
" 1.2.1 2002-06-15
" Bug fix. Better 'ff' setting for distribution files
" --- Renamed plugin from Thlnk to Utl ---
" 2.0 2005-03-22
" Configurable scheme and media type handlers, syntax
" highlighting, naked URL support, #tn as default, heuristic
" support and other new features. See ../doc/utl_usr.txt#utl-changes
" 3.0a ALPHA 2008-07-31
" New : Generic media type handler, Mail protocol, Copy Link/
" Filename support, Foot-References [], Transparent editing of
" share files, Tracing, Enhanced scheme handler interface,
" Changed : User Interface with command :Utl, variable naming.
" Bug fixes.
" ------------------------------------------------------------------------------
if exists("loaded_utl") || &cp
finish
endif
let loaded_utl = "3.0a"
if v:version < 700
echohl ErrorMsg
echo "Error: You need Vim version 7.0 or later for utl.vim version ".g:loaded_utl
echohl None
finish
endif
let s:save_cpo = &cpo
set cpo&vim
let g:utl__file = expand("<sfile>")
"--- Utl User Interface [
" (:Utl not as "command! to not override a possible user command of this name.
" Fails with an error in this case.)
command -complete=custom,s:completeArgs -range -nargs=* Utl call Utl(<f-args>)
"-------------------------------------------------------------------------------
" Intended as command line completion function called back by command :Utl.
" See vimhelp:command-completion-custom.
" Based on the command line provided by user input so far it returns a \n
" separated line of items, which Vim then uses for presenting completion
" suggestions to the user.
" Also works if abbreviations ( see #r=cmd_abbreviations ) appear in cmdLine
fu! s:completeArgs(dummy_argLead, cmdLine, dummy_cursorPos)
" Split cmdLine to figure out how many arguments have been provided by user
" so far. If Using argument keepempty=1 for split will provide empty last
" arg in case of a new arg is about to begin or an non empty last argument
" in case of an incomplete last argument. So can just remove the last arg.
let utlArgs=split(a:cmdLine, '\s\+', 1)
call remove(utlArgs, -1)
" 1st arg to complete
if len(utlArgs)==1
return "openLink\ncopyFileName\ncopyLink\nhelp"
endif
let utlArgs[1] = s:abbr2longArg(utlArgs[1])
" 2nd arg to complete
if len(utlArgs)==2
if utlArgs[1]=='openLink' || utlArgs[1]=='copyFileName' || utlArgs[1]=='copyLink'
if len(utlArgs)==2
return "underCursor\nvisual\ncurrentFile\n_your_URL_here"
endif
elseif utlArgs[1]=='help'
if len(utlArgs)==2
return "manual\ncommands"
endif
endif
" config
return ''
endif
" 3rd argument to complete
if len(utlArgs)==3
if utlArgs[1]=='openLink'
return "edit\nsplit\nvsplit\ntabedit\nview\nread"
elseif utlArgs[1]=='copyFileName'
return "native\nslash\nbackSlash"
endif
return ''
endif
return ''
endfun
" [id=cmd_reference]
"-------------------------------------------------------------------------------
" Table of :Utl commands/arguments. The [xxx] are default values and can
" be omitted. ( The table is implemented at #r=Utl )
"
" arg# 1 2 3
"
" :Utl [openLink] [underCursor] [edit]
" :Utl visual split
" :Utl currentFile vsplit
" :Utl <my_url> tabedit
" :Utl view
" :Utl read
"
" :Utl copyLink [underCursor]
" :Utl visual
" :Utl currentFile
" :Utl <my_url>
"
" :Utl copyFileName [underCursor] [native]
" :Utl currentFile backSlash
" :Utl Visual slash
" :Utl <my_url>
"
" :Utl help [manual]
" :Utl commands
" [id=cmd_abbreviations]
"-------------------------------------------------------------------------------
" Supported abbreviations of arguments to :Utl command.
" Abbreviation conventions are:
" - More than one abbreviation per argument is possible
" - All uppercase letter of a camel word as lower letters (copyFileName -> cfn)
" - Fewer and fewer uppercase letters as long as still unique
" (cfn -> cf. But not c since else clash with copyLink)
" - The shortest (camel sub-)word beginning until unique
" (view and vsplit -> vi and vs resp.)
"
" (More keys (=abbreviations) can be added to the dictionaries without further
" change as long as the values are valid long arguments.)
"
let s:d1= { 'o': 'openLink', 'ol': 'openLink', 'cl': 'copyLink', 'cf': 'copyFileName', 'cfn': 'copyFileName', 'h': 'help' }
let s:d21={ 'u': 'underCursor', 'uc': 'underCursor', 'v': 'visual', 'c': 'currentFile', 'cf': 'currentFile' }
let s:d22={ 'm': 'manual', 'c': 'commands' }
let s:d31={ 'e': 'edit', 's': 'split', 'vs': 'vsplit', 't': 'tabedit', 'te': 'tabedit', 'vi': 'view', 'r': 'read' }
let s:d32={ 'n': 'native', 'b': 'backSlash', 'bs': 'backSlash', 's': 'slash' }
"-------------------------------------------------------------------------------
" Convert possible :Utl arg abbreviation for last arg into long arg. The args
" before are the :Utl args provided so far in long form.
"
" Args: Utl command arguments according #r=cmd_reference, where the last
" can be abbreviated.
" Returns: Last arg converted into long arg
"
" Collaboration:
"
" Example: s:abbr2longArg('copyFileName', 'underCursor', 's')
" returns 'slash'
"
fu! s:abbr2longArg(...)
if ! exists('a:2')
return s:utilLookup(s:d1, a:1)
elseif ! exists('a:3')
if a:1=='openLink'|| a:1=='copyLink'|| a:1=='copyFileName'
return s:utilLookup(s:d21, a:2)
elseif a:1=='help'
return s:utilLookup(s:d22, a:2)
endif
else
if a:1=='openLink'
return s:utilLookup(s:d31, a:3)
elseif a:1 == 'copyFileName'
return s:utilLookup(s:d32, a:3)
endif
endif
endfu
"-------------------------------------------------------------------------------
" Lookup 'key' in 'dict'. If defined return its value else return the 'key'
" itself
fu! s:utilLookup(dict,key)
if has_key(a:dict, a:key)
return a:dict[a:key]
endif
return a:key
endfu
"----------------------------------------------------------id=Utl---------------
" Central Utl.vim function. Normally invoked by :Utl command
" args: Same as command :Utl (but quoted), see #r=cmd_reference
"
" Example: call Utl('openLink','http://www.vim.org','split')
"
fu! Utl(...)
call Utl_trace("- start function Utl()",1,1)
if exists('a:1') | let cmd=s:abbr2longArg(a:1) | else | let cmd='openLink' | endif
call Utl_trace("- arg1 (cmd) provided or by default = `".cmd."'")
if cmd == 'openLink'
if exists('a:2') | let operand=s:abbr2longArg(cmd,a:2) | else | let operand='underCursor' | endif
call Utl_trace("- arg2 (operand) provided or by default = `".operand."'")
if exists('a:3') | let dispMode=s:abbr2longArg(cmd,operand,a:3) | else | let dispMode='edit' | endif
call Utl_trace("- arg3 (dispMode) provided or by default = `".dispMode."'")
if operand=='underCursor'
call s:Utl_goUrl(dispMode)
elseif operand=='visual'
let url = @*
call s:Utl_processUrl(url, dispMode)
elseif operand=='currentFile'
let url = 'file://'.Utl_utilBack2FwdSlashes( expand("%:p") )
call s:Utl_processUrl(url, dispMode)
else " the operand is the URL
call s:Utl_processUrl(operand, dispMode)
endif
elseif cmd=='copyFileName' || cmd=='copyLink'
if exists('a:2') | let operand=s:abbr2longArg(cmd,a:2) | else | let operand='underCursor' | endif
call Utl_trace("- arg2 (operand) provided or by default = `".operand."'")
let suffix=''
if cmd == 'copyFileName'
if exists('a:3') | let modifier=s:abbr2longArg(cmd,operand,a:3) | else | let modifier='native' | endif
call Utl_trace("- arg3 (modifier) provided or by default = `".modifier."'")
let suffix='_'.modifier
endif
if operand=='underCursor'
call s:Utl_goUrl(cmd.suffix)
elseif operand=='visual'
let url = @*
call s:Utl_processUrl(url, cmd.suffix)
elseif operand=='currentFile'
let url = 'file://'.Utl_utilBack2FwdSlashes( expand("%:p") )
call s:Utl_processUrl(url, cmd.suffix)
else " the operand is the URL
call Utl_trace("- `".operand."' (arg2) is not a keyword. So is directly taken as an URL")
call s:Utl_processUrl(operand, cmd.suffix)
endif
elseif cmd == 'help'
if exists('a:2') | let operand=s:abbr2longArg(cmd,a:2) | else | let operand='manual' | endif
call Utl_trace("- arg2 (operand) provided or by default = `".operand."'\n") " CR054_extra_nl
if operand=='manual'
help utl_usr.txt
elseif operand=='commands'
call Utl('openLink', 'file://'.Utl_utilBack2FwdSlashes(expand(g:utl__file)).'#r=cmd_reference', 'sview')
else
echohl ErrorMsg | echo "invalid argument: `".operand."'" | echohl None
endif
else
echohl ErrorMsg | echo "invalid argument: `".cmd."'" | echohl None
endif
call Utl_trace("- end function Utl()",1,-1)
endfu
"]
"--- Set unset Utl options to defaults (id=options) [
if ! exists("utl_opt_verbose")
let utl_opt_verbose=0
endif
if ! exists("utl_opt_highlight_urls")
let utl_opt_highlight_urls='yes'
endif
"]
"--- Suggested mappings for most frequent commands [id=suggested_mappings] [
"
" nmap <unique> <Leader>ge :Utl openLink underCursor edit<CR>
" nmap <unique> <Leader>gu :Utl openLink underCursor edit<CR>
" nmap <unique> <Leader>gE :Utl openLink underCursor split<CR>
" nmap <unique> <Leader>gS :Utl openLink underCursor vsplit<CR>
" nmap <unique> <Leader>gt :Utl openLink underCursor tabedit<CR>
" nmap <unique> <Leader>gv :Utl openLink underCursor view<CR>
" nmap <unique> <Leader>gr :Utl openLink underCursor read<CR>
"
" [id=suggested_mappings_visual]
" vmap <unique> <Leader>ge "*y:Utl openLink visual edit<CR>
" vmap <unique> <Leader>gu "*y:Utl openLink visual edit<CR>
" vmap <unique> <Leader>gE "*y:Utl openLink visual split<CR>
" vmap <unique> <Leader>gS "*y:Utl openLink visual vsplit<CR>
" vmap <unique> <Leader>gt "*y:Utl openLink visual tabedit<CR>
" vmap <unique> <Leader>gv "*y:Utl openLink visual view<CR>
" vmap <unique> <Leader>gr "*y:Utl openLink visual read<CR>
"
"
" nmap <unique> <Leader>cfn :Utl copyFileName underCursor native<CR>
" nmap <unique> <Leader>cfs :Utl copyFileName underCursor slash<CR>
" nmap <unique> <Leader>cfb :Utl copyFileName underCursor backSlash<CR>
"
" vmap <unique> <Leader>cfn "*y:Utl copyFileName visual native<CR>
" vmap <unique> <Leader>cfs "*y:Utl copyFileName visual slash<CR>
" vmap <unique> <Leader>cfb "*y:Utl copyFileName visual backSlash<CR>
"
"
" nmap <unique> <Leader>cl :Utl copyLink underCursor<CR>
"
" vmap <unique> <Leader>cl "*y:Utl copyLink visual<CR>
"
"]
let s:utl_esccmdspecial = '%#' " keep equal to utl_scm.vim#__esc
" isfname adapted to URI Reference characters
let s:isuriref="@,48-57,#,;,/,?,:,@-@,&,=,+,$,,,-,_,.,!,~,*,',(,),%"
"----------------------------------------------------------id=thl_gourl---------
" Process URL (or read: URI, if you like---Utl isn't exact there) under
" cursor: searches for something like <URL:myUrl> or <A HREF="myUrl"> (depending
" on the context), extracts myUrl, an processes that Url (e.g. retrieves the
" document and displays it).
"
" - Arg dispMode -> see <URL:#r=dispMode>
"
fu! s:Utl_goUrl(dispMode)
call Utl_trace("- start processing (dispMode=".a:dispMode.")",1,1)
let url = Utl_getUrlUnderCursor()
if url == ''
let v:errmsg = "No URL under Cursor"
echohl ErrorMsg | echo v:errmsg | echohl None
else
call s:Utl_processUrl(url, a:dispMode)
endif
call Utl_trace("- end processing.",1,-1)
endfu
"-------------------------------------------------------------------------------
" Tries to extract an URL in current buffer at current cursor position.
"
" Returns: URL under cursor if any, else ''
"
fu! Utl_getUrlUnderCursor()
call Utl_trace("- start getting URL under cursor",1,1)
let line = getline('.')
let icurs = col('.') - 1 " `Index-Cursor'
call Utl_trace("- first try: checking for URL with embedding like <url:xxx> in current line...",1,1)
let url = s:Utl_extractUrlByPattern(line, icurs, '')
if url=='<undef>'
call Utl_trace("- ...no",1,-1)
call Utl_trace("- retry: checking for embedded URL spanning over range of max 5 lines...",1,1)
let lineno = line('.')
" (lineno-1/2 can be negative -> getline gives empty string -> ok)
let line = getline(lineno-2) . "\n" . getline(lineno-1) . "\n" .
\ getline(lineno) . "\n" .
\ getline(lineno+1) . "\n" . getline(lineno+2)
" `Index of Cursor'
" (icurs off by +2 because of 2 \n's, plus -1 because col() starts at 1 = +1)
let icurs = strlen(getline(lineno-2)) + strlen(getline(lineno-1)) + col('.') +1
let url = s:Utl_extractUrlByPattern(line, icurs, '')
endif
if url=='<undef>'
call Utl_trace("- ...no", 1, -1)
call Utl_trace("- retry: checking if [ ] style reference...", 1, 1)
if stridx(line, '[') != -1
let isfname_save = &isfname | let &isfname = s:isuriref " ([)
let pat = '\(\(\[[A-Z0-9_]\{-}\]\)\(#\f*\)*\)' " &isfname here in \f
let url = s:Utl_extractUrlByPattern(line, icurs, pat)
let &isfname = isfname_save " (])
" remove trailing punctuation characters if any
if url!='<undef>'
call Utl_trace("- removing trailing punctuation chars from URL if any")
let url = substitute(url, '[.,:;!?]$', '', '')
endif
endif
endif
if url=='<undef>'
call Utl_trace("- ...no", 1,-1)
call Utl_trace("- retry: checking for unembedded URL under cursor...", 1,1)
" Take <cfile> as URL. But adapt isfname to match all allowed URI Reference characters
let isfname_save = &isfname | let &isfname = s:isuriref " ([)
let url = expand("<cfile>")
let &isfname = isfname_save " (])
endif
if url!=''
call Utl_trace("- ...yes, URL found: `".url."'", 1,-1)
else
call Utl_trace("- ...no", 1,-1)
endif
call Utl_trace("- end getting URL under cursor.",1,-1)
return url
endfu
"--------------------------------------------------------id=thl_curl------------
" `Utl_extractUrlByPattern' - Extracts embedded URLs from 'linestr':
" Extracts URL from given string 'linestr' (if any) at position 'icurs' (first
" character in linestr is 0). When there is no URL or icurs does not hit the
" URL (i.e. 'URL is not under cursor') returns '<undef>'. Note, that there can
" be more than one URL in linestr. Linestr may contain newlines (i.e. supports
" multiline URLs).
"
" 'pat' argument:
" Embedded URL means, that the URL is surrounded by some tag or characters
" to allow for safe parsing, for instance '<url:'...'>'. This regexp pattern
" has to specify a group \(...\) by which defines the URL.
" Example : '<url:\([^<]\{-}\)>'. If an empty pattern '' is given, default
" patterns apply (see code below).
"
" Examples:
" :echo s:Utl_extractUrlByPattern('Two Urls <URL:/foo/bar> in this <URL:/f/b> line', 35, '')
" returns `/f/b'
"
" :echo s:Utl_extractUrlByPattern('Two Urls <URL:/foo/bar> in this <URL:/f/b> line', 28, '')
" returns `<undef>'
"
" :echo s:Utl_extractUrlByPattern('Another embedding here <foo bar>', 27, '')
" returns `foo bar'
"
" Details:
" - The URL embedding (or if embedding at all) depends on the context: HTML
" has different embedding than a txt file.
" - Non HTML embeddings are of the following form: <URL:...>, <LNK:...> or
" <...>
" - Returns `<undef>' if `no link under cursor'. (Note that cannot cause
" problems because `<' is not a valid URI character)
" - Empty Urls are legal, e.g. <URL:>
" - `Under cursor' is like with vim's gf-command: icurs may also point to
" whitespace before the cursor. (Also pointing to the embedding characters
" is valid.)
"
fu! s:Utl_extractUrlByPattern(linestr, icurs, pat)
let pat = a:pat
call Utl_trace("- start extracting URL by pattern `".pat."'",1,1)
if pat == ''
call Utl_trace("- pattern is <undef>, determine based on file type")
if &ft == 'html'
let embedType = 'html'
else
let embedType = 'txt'
endif
" (pat has to have the Url in first \(...\) because ({) )
if embedType == 'html'
call Utl_trace("- file type is 'html'")
" Html-Pattern:
" - can have other attributes in <A>, like
" <A TITLE="foo" HREF="#bar"> (before and/or behind HREF)
" - can have Whitespace embedding the `=' like
" <A HREF = "#bar">
" Note: Url must be surrounded by `"'. But that should not be mandatory...
" Regexp-Guru please help!
let pat = '<A.\{-}HREF\s*=\s*"\(.\{-}\)".\{-}>'
else
call Utl_trace("- file type is not 'html', so use generic pattern")
" Allow different embeddings: <URL:myUrl>, <myUrl>.
" Plus <LNK:myUrl> for backward compatibility utl-1.0 and future
" extension.
" ( % in pattern means that this group doesn't count as \1 )
let pat = '<\%(URL:\|LNK:\|\)\([^<]\{-}\)>'
endif
call Utl_trace("- will use pattern `".pat."'")
endif
let linestr = a:linestr
let icurs = a:icurs
" do match() and matchend() ic (i.e. allow url: urL: Url: lnk: lnk: LnK:
" <a href= <A HREF= ...)
let saveIgnorecase = &ignorecase | set ignorecase " ([)
call Utl_trace("- now try to extract URL from given string using this pattern")
while 1
" (A so called literal \n here (and elsewhere), see
" <URL:vimhelp:expr-==#^since a string>.
" \_s* can't be used because a string is considered a single line.)
let ibeg = match(linestr, "[ \\t \n]*".pat)
if ibeg == -1 || ibeg > icurs
let curl = '<undef>'
break
else
" matchstart before cursor or same col as cursor,
" look if matchend is ok (i.e. after or equal cursor)
let iend = matchend(linestr, "[ \\t \n]*".pat) -1
if iend >= icurs
" extract the URL itself from embedding
let curl = substitute(linestr, '^.\{-}'.pat.'.*', '\1', '') " (})
break
else
" match was before cursor. Check for a second URL in linestr;
" redo with linestr = `subline' behind the match
let linestr = strpart(linestr, iend+1, 9999)
let icurs = icurs-iend-1
continue
endif
endif
endwhile
let &ignorecase = saveIgnorecase " (])
call Utl_trace("- end extracting URL by pattern, returning URL=`".curl."'",1,-1)
return curl
endfu
"-------------------------------------------------------------------------------
" Switch syntax highlighting for URLs on or off. Depending on the config
" variable g:utl_opt_highlight_urls
fu! s:Utl_setHighl()
if g:utl_opt_highlight_urls ==? 'yes'
augroup utl_highl
au!
au BufWinEnter * syn case ignore
" [id=highl_custom]
" Highlighting of URL surrounding `<url' and `>' " [id=highl_surround]
"au BufWinEnter * hi link UtlTag Identifier " as of Utl v2.0
"au BufWinEnter * hi link UtlTag Ignore " `<url:' and '>' invisible like | | in Vim help
"au BufWinEnter * hi link UtlTag PreProc
" Highlighting of URL itself (what is inside `<url' and '>' " [id=highl_inside]
" Some fixed colors ( not changing with :colorscheme, but all underlined )
"au BufWinEnter * hi UtlUrl ctermfg=LightBlue guifg=LightBlue cterm=underline gui=underline term=reverse
"au BufWinEnter * hi UtlUrl ctermfg=Blue guifg=Blue cterm=underline gui=underline term=reverse
"au BufWinEnter * hi UtlUrl ctermfg=Cyan guifg=Cyan cterm=underline gui=underline term=reverse
" Some Standard group names (see <url:vimhelp:group-name>)
"au BufWinEnter * hi link UtlUrl Tag
"au BufWinEnter * hi link UtlUrl Constant
au BufWinEnter * hi link UtlUrl Underlined
au BufWinEnter * syn region UtlUrl matchgroup=UtlTag start="<URL:" end=">" containedin=ALL
au BufWinEnter * syn region UtlUrl matchgroup=UtlTag start="<LNK:" end=">" containedin=ALL
au BufWinEnter utl*.vim hi link UtlTrace Comment
au BufWinEnter utl*.vim syn region UtlTrace matchgroup=UtlTrace start="call Utl_trace" end=")" containedin=ALL
au BufWinEnter * syn case match
augroup END
else
augroup utl_highl
au!
augroup END
augroup! utl_highl
" Clear for current buffer to make turn-off instantaneously visible.
" ... but does not seem to work everywhere.
if hlexists('UtlTag')
syntax clear UtlTag
endif
if hlexists('UtlUrl')
syntax clear UtlTag
endif
if hlexists('UtlTrace')
syntax clear UtlTrace
endif
endif
endfu
call s:Utl_setHighl()
"-------------------------------------------------------------------------------
" Process given Url.
"
" Processing means: retrieve or address or load or switch-to or query or
" whatever the resource given by `url'.
" When succesful, then a local file will (not necessarly) exist, and
" is displayed by vim. Or is displayed by a helper application (e.g.
" when the Url identifies an image). Often the local file is cache
" file created ad hoc (e.g. in case of network retrieve).
"
" - The uriref argument can contain line breaks. \s*\n\s* Sequences are
" collapsed. Other Whitespace is left as is (CR019, CR052).
" See also <URL:http://www.ietf.org/rfc/rfc2396.txt> under
" chapter E, Recommendations.
"
" Examples:
" call s:Utl_processUrl('file:///path/to/file.txt', 'edit')
"
" call s:Utl_processUrl('file:///usr/local/share/vim/', 'vie')
" " may call Vim's explorer
"
" call s:Utl_processUrl('http://www.vim.org', 'edit')
" " call browser on URL
"
" call s:Utl_processUrl('mailto:stb@bf-consulting.de', 'vie')
" " the local file may be the return receipt in this case
"
fu! s:Utl_processUrl(uriref, dispMode)
call Utl_trace("- start processing URL `".a:uriref."' in processing mode `".a:dispMode."'",1,1)
let urirefpu = a:uriref " uriref with newline whitespace sequences purged
" check if newline contained. Collapse \s*\n\s
if match(a:uriref, "\n") != -1
let urirefpu = substitute(a:uriref, "\\s*\n\\s*", "", "g")
call Utl_trace("- URL contains new line characters. Remove them.")
call Utl_trace(" now URL= `".urirefpu."'")
endif
let uri = UriRef_getUri(urirefpu)
let fragment = UriRef_getFragment(urirefpu)
call Utl_trace("- fragment `".fragment."' stripped from URL")
"--- Handle Same Document Reference (sdreference)
" processed as separate case, because:
" 1. No additional 'retrieval' should happen (see
" <URL:http://www.ietf.org/rfc/rfc2396.txt#4.2. Same-document>).
" 2. UtlUri_abs() does not lead to a valid absolute Url (since the base-path-
" file-component will always be discarded).
"
if uri == ''
call Utl_trace("- is a same document reference. Go directly to fragment processing (in mode 'rel')")
" m=go
normal m'
call s:Utl_processFragmentText( fragment, 'rel' )
call Utl_trace("- end processing URL",1,-1)
return
endif
call Utl_trace("- start normalize URL to an absolute URL",1,1)
let scheme = UtlUri_scheme(uri)
if scheme != '<undef>'
call Utl_trace("- scheme defined (".scheme.") - so is an absolute URL")
let absuri = uri
else " `uri' is formally no absolute URI but look for some
" heuristic, e.g. prepend 'http://' to 'www.vim.org'
call Utl_trace("- scheme undefined - so is a relative URL or a heuristic URL")
call Utl_trace("- check for some heuristics like www.foo.com -> http://www.foo.com... ",0)
let absuri = s:Utl_checkHeuristicAbsUrl(uri)
if absuri != ''
let scheme = UtlUri_scheme(absuri)
call Utl_trace("yes,") | call Utl_trace(" absolute URL constructed by heuristic is `".absuri."'")
else
call Utl_trace("no")
endif
endif
if scheme == '<undef>'
let curPath = Utl_utilBack2FwdSlashes( expand("%:p") )
if stridx(curPath, '://') != -1 " id=url_buffer (e.g. by netrw)
call Utl_trace("- buffer's name looks like an absolute URL (has substring ://)")
call Utl_trace(" so take it as base URL.")
let base = curPath
else
call Utl_trace("- try to construct a `file://' base URL from current buffer... ",0)
" No corresponding resource to curPath known. (id=nobase)
" i.e. curPath was not retrieved through Utl.
" Now just make the usual heuristic of `file://localhost/'-Url;
" assume, that the curPath is the resource itsself. If then the
" retrieve with the so generated Url is not possible, nothing
" severe happens.
if curPath == ''
call Utl_trace("not possible, give up")
let v:errmsg = "Cannot make a base URL from unnamed buffer. Edit a file and try again"
echohl ErrorMsg | echo v:errmsg | echohl None
call Utl_trace("- end normalize URL to an absolute URL",1,-1)
call Utl_trace("- end processing URL",1,-1)
return
endif
let base = 'file://' . curPath
call Utl_trace("done,")
endif
call Utl_trace(" base URL is `".base."'")
let scheme = UtlUri_scheme(base)
call Utl_trace("- construct absolute URL from combining base URL and relative URL")
let absuri = UtlUri_abs(uri,base)
endif
call Utl_trace("- assertion: now have absolute URL `".absuri."' with scheme `".scheme."'")
call Utl_trace("- end normalize URL to an absolute URL",1,-1)
if a:dispMode==? 'copyLink'
call Utl_trace("processing mode is `copyLink'. Copy link to clipboard")
call setreg('*', absuri)
echo "Copied `".@*."' to clipboard"
call Utl_trace("- end processing URL",1,-1)
return
endif
"--- Call the appropriate retriever (see <URL:utl_scm.vim>)
call Utl_trace("- start scheme handler processing",1,1)
" Always set a jump mark to allow get back to cursor position before
" jump (see also CR051).
" m=go id=_setj
normal m'
let cbfunc = 'Utl_AddressScheme_' . scheme
call Utl_trace("- constructing call back function name from scheme: `".cbfunc."'")
if !exists('*'.cbfunc)
let v:errmsg = "Sorry, scheme `".scheme.":' not implemented"
echohl ErrorMsg | echo v:errmsg | echohl None
call Utl_trace("- end scheme handler processing",1,-1)
call Utl_trace("- end processing URL",1,-1)
return
endif
call Utl_trace("- calling call back function with arguments:")
call Utl_trace(" arg 1 - absolute URL=`".absuri."'")
call Utl_trace(" arg 2 - fragment =`".fragment."'")
call Utl_trace(" arg 3 - display Mode=`".a:dispMode."'")
exe 'let ret = ' cbfunc . '("'.absuri.'", "'.fragment.'", "'.a:dispMode.'")'
call Utl_trace("- call back function `".cbfunc."' returned list:`". join(ret,',') ."'")
exe "normal \<C-L>" | " Redraw seems necessary for non GUI Vim under Unix'es
if !len(ret)
call Utl_trace("- empty list -> no further processing")
call Utl_trace("- end scheme handler processing",1,-1)
call Utl_trace("- end processing URL",1,-1)
return
endif
let localPath = ret[0]
let fragMode = get(ret, 1, 'abs')
call Utl_trace("- first list element (local path): `".localPath."'")
call Utl_trace("- second list element (fragment mode) or default: `".fragMode."'")
" Assertion
if stridx(localPath, '\') != -1
echohl ErrorMsg
call input("Internal Error: localPath `".localPath."' contains backslashes <RETURN>")
echohl None
endif
call Utl_trace("- assertion: a local path corresponds to URL")
call Utl_trace("- end scheme handler processing",1,-1)
let dispMode = a:dispMode
if a:dispMode == 'copyFileName_native'
if has("win32") || has("win16") || has("win64") || has("dos32") || has("dos16")
call Utl_trace("- changing dispMode `copyFileName_native' to 'copyFileName_backSlash' since under Windows")
let dispMode = 'copyFileName_backSlash'
else
call Utl_trace("- changing dispMode `copyFileName_native' to 'copyFileName_slash' since not under Windows")
let dispMode = 'copyFileName_slash'
endif
endif
if dispMode == 'copyFileName_slash'
call Utl_trace("- processing mode is `copyFileName_slash': copy file name, which corresponds to link")
call Utl_trace(" (with forward slashes) to clipboard")
call setreg('*', localPath )
echo "Copied `".@*."' to clipboard"
call Utl_trace("- end processing URL",1,-1)
return
elseif dispMode == 'copyFileName_backSlash'
call Utl_trace("- processing mode is `copyFileName_backSlash': copy file name, which corresponds to link")
call Utl_trace(" (with backslashes) to clipboard")
call setreg('*', Utl_utilFwd2BackSlashes(localPath) )
echo "Copied `".@*."' to clipboard"
call Utl_trace("- end processing URL",1,-1)
return
endif
" See if media type is defined for localPath, and if yes, whether a
" handler is defined for this media type (if not the Setup is called to
" define one). Everything else handle with the default handler
" Utl_displayFile(), which displays the document in a Vim window.
" The pseudo handler named 'VIM' is supported: Allows bypassing the media
" type handling and call default vim handling (Utl_displayFile)
" although there is a media type defined.
call Utl_trace("- start media type handler processing",1,1)
call Utl_trace("- check if there is a file-name to media-type mapping for local path")
call Utl_trace(" (hardcoded in Utl)... ",0)
let contentType = s:Utl_checkMediaType(localPath)
if contentType == ''
call Utl_trace("no. Display local path in this Vim.")
else
call Utl_trace("yes, media type is `".contentType."'.")
let slashPos = stridx(contentType, '/')
let var_s = 'g:utl_cfg_hdl_mt_' . substitute(contentType, '[-/+.]', '_', 'g')
call Utl_trace("- constructing Vim variable for specific media type handler:")
call Utl_trace(" `".var_s."'. Now check if it exists...")
if exists(var_s)
call Utl_trace(" ...exists, and will be used")
let var = var_s
else
call Utl_trace(" ...does not exist. Now check generic media type handler variable")
let var_g = 'g:utl_cfg_hdl_mt_generic'
if exists(var_g)
call Utl_trace("- Vim variable `".var_g."' does exist and will be used")
else
call Utl_trace(" Vim variable `".var_g."' does not exist either")
endif
let var = var_g
endif
if ! exists(var) " Entering setup
echohl WarningMsg
call input('No handler for media type '.contentType.' defined yet. Entering Setup now. <RETURN>')
echohl None
call s:Utl_processUrl('config:#r=utl_cfg_hdl_mt_generic', 'split') " (recursion, setup)
call Utl_trace("- end media type handler processing",1,-1)
call Utl_trace("- end processing URL",1,-1)
return
endif
exe 'let varVal =' . var
call Utl_trace("- Variable has value `".varVal."'")
if varVal ==? 'VIM'
call Utl_trace("- value of variable is 'VIM': display in this Vim")
else
call Utl_trace("- construct command by expanding any % conversion specifiers.")
let convSpecDict= { 'p': localPath, 'P': Utl_utilFwd2BackSlashes(localPath),
\ 'f': (fragment=="<undef>" ? "" : fragment) } " '<undef>' -> '' for external handler
exe 'let [errmsg,cmd] = Utl_utilExpandConvSpec('.var.', convSpecDict)'
if errmsg != ""
echohl ErrorMsg
echo "The content of the Utl-setup variable `".var."' is invalid and has to be fixed! Reason: `".errmsg."'"
echohl None
call Utl_trace("- end media type handler processing",1,-1)
call Utl_trace("- end processing URL",1,-1)
return
endif
call Utl_trace("- constructed command is: `".cmd."'")
" Escape string to be executed as a ex command (i.e. escape some
" characters from special treatment <URL:vimhelp:cmdline-special>)
" and execute the command
let escCmd = escape(cmd, s:utl_esccmdspecial)
if escCmd != cmd
call Utl_trace("- escape characters, command changes to: `".escCmd."'")
endif
call Utl_trace("- execute command with :exe")
exe escCmd
call Utl_trace("- end media type handler processing",1,-1)
call Utl_trace("- end processing URL",1,-1)
return
endif
endif
call Utl_trace("- end media type handler processing",1,-1)
if s:Utl_displayFile(localPath, dispMode)
call s:Utl_processFragmentText(fragment, fragMode)
endif
call Utl_trace("- end processing URL",1,-1)
endfu
"id=Utl_checkHeuristicAbsUrl--------------------------------------------------
"
" This function is called for every URL which is not an absolute URL.
" It should check if the URL is meant to be an absolute URL and return
" the absolute URL. E.g. www.host.domain -> http://www.host.domain.
"
" You might want to extend this function for your own special URLs
" and schemes, see #r=heur_example below
"
fu! s:Utl_checkHeuristicAbsUrl(uri)
"--- [1] -> foot:1
if match(a:uri, '^\[.\{-}\]') != -1
return substitute(a:uri, '^\[\(.\{-}\)\]', 'foot:\1', '')
"--- www.host.domain -> http://www.host.domain
elseif match(a:uri, '^www\.') != -1
return 'http://' . a:uri
"--- user@host.domain -> mailto:user@host.domain
elseif match(a:uri, '@') != -1
return 'mailto:' . a:uri
"--- :xxx -> vimscript::xxx
elseif match(a:uri, '^:') != -1
return 'vimscript:' . a:uri
" BT12084 -> BT:12084 #id=heur_example
" This is an example of a custom heuristics which I use myself. I have a
" text file which contains entries like 'BT12084' which refer to that id
" 12084 in a bug tracking database.
elseif match(a:uri, '^[PB]T\d\{4,}') != -1
return substitute(a:uri, '^\([PB]T\)\(\d\+\)', 'BT:\2', '')
endif
return ''
endfu
"------------------------------------------------------------------------------
" Escape some special characters in fileName which have special meaning
" in Vim's command line but what is not desired in URLs.
" Example: In file 'a%b.txt' the % must not be expanded to the current file.
"
" - returns: Escaped fileName
"
fu! s:Utl_escapeCmdLineSpecialChars(fileName)
" - Escape characters '#' and '%' with special meaning for Vim
" cmd-line (see <URL:vimhelp:cmdline-special> because they must have no special
" meaning in URLs.
let escFileName = escape(a:fileName, s:utl_esccmdspecial)
" - Also escape '$': Will otherwise tried to be expanded by Vim as Envvar (CR030).
" But only escape if there is an identifier character after the $ (CR053).
let escFileName = substitute(escFileName, '\$\(\I\)', '\\$\1', 'g')
" - Also escape blanks because single word needed, e.g. `:e foo bar'.
" Escape spaces only if on unix (no problem on Windows) (CR033)
if has("unix")
let escFileName = escape(escFileName, ' ')
endif
return escFileName
endfu
"-------------------------------------------------------------------------------
" Description:
" Display file `localPath' in a Vim window as determined by `dispMode'
" There is special treatment if `localPath' already loaded in a buffer and
" there is special treatment if current buffer cannot be abandoned.
" Escapes characters in localPath which have special meaning for Vim but
" which must not have special meaning in URL paths.
"
" - `dispMode' specification: (id=dispMode)
" Resembles XML-XLink's `show' attribut. Value is taken directly as Vim
" command. Examples: 'view', 'edit', 'sview', 'split', 'read', 'tabe'
"
" - localPath specification:
" . May contain any characters that the OS allows (# % $ ' ')
" Note: No percent escaping here, localPath is a file name not an URL.
" For instance %20.txt is taken as literal file name.
"
" - returns: 1 on success (a:localPath loaded), else 0
"
" - collaboration:
" . Does not explicitly set the cursor
" . Does not explicitly set the ' mark
"
" Example: :call s:Utl_displayFile('t.txt', 'split')
"
fu! s:Utl_displayFile(localPath, dispMode)
call Utl_trace("- start display file `".a:localPath."' in mode `".a:dispMode."'",1,1)
let bwnrlp = bufwinnr(a:localPath)
if bwnrlp != -1 && winnr() == bwnrlp
call Utl_trace("- file already displayed in current window")
call Utl_trace("- end display file",1,-1)
return 1
endif
if bwnrlp != -1
" localPath already displayed, but not in current window
" Just make this buffer the current window.
call Utl_trace("- file already displayed, but not in other window. Move to that window")
exe bwnrlp . "wincmd w"
else " Open file
call Utl_trace("- file not yet displayed in any window")
" Possibly alter dispMode to avoid E37 error (id=_altersa)
" If buffer cannot be <URL:vimhelp:abandon>ned, for given dispMode,
" silently change the dispMode to a corresponding split-dispMode. Want
" to avoid annoying E37 message when executing URL on modified buffer (CR024)
let dispMode = a:dispMode
if getbufvar(winbufnr(0),"&mod") && ! getbufvar(winbufnr(0),"&awa") && ! getbufvar(winbufnr(0),"&hid")
if dispMode == 'edit'
let dispMode = 'split'
call Utl_trace("- current window can probably not be quit, so silently change mode to `split'")
elseif dispMode == 'view'
let dispMode = 'sview'
call Utl_trace("- current window can probably not be quit, so silently change mode to `sview'")
endif
endif
let escLocalPath = s:Utl_escapeCmdLineSpecialChars(a:localPath)
if escLocalPath != a:localPath
call Utl_trace("- Escaped one or more characters out of #,%,$ (under Unix also blank)")
call Utl_trace(" because these would else be expanded in Vim's command line")
call Utl_trace(" File name changed to: `".escLocalPath."'")
endif
"--- Try load file or create new buffer. Then check if buffer actually
" loaded - might fail for if E325 (swap file exists) and user abort
"
let cmd = dispMode.' '.escLocalPath
call Utl_trace("- trying to load/display file with command: `".cmd."'\n") " CR054_extra_nl
exe cmd
exe "normal \<C-L>" | " Redraw seems necessary for non GUI Vim under Unix'es
if bufwinnr(escLocalPath) != winnr() " not loaded
call Utl_trace("- not loaded.")
call Utl_trace("- end display file (not successful)",1,-1)
return 0
endif
endif
call Utl_trace("- end display file (successful)",1,-1)
return 1
endfu
"----------------------------------------------------------id=utl_checkmtype----
" Possibly determines the media type (= mime type) for arg `path', e.g.
" pic.jpeg -> 'image/jpeg' and returns it. Returns an empty string if media
" type cannot be determined or is uninteresting to be determined. Uninteresting
" means: Only those media types are defined here which are of potential
" interest for being handled by some external helper program (e.g. MS Word for
" application/msword or xnview for application/jpeg).
"
" When this function returns a non empty string Utl checks if a specific media
" type handler is defined. If not Utl's setup utility is called to define one.
"
" - You may add other mediatypes. See
" <URL:ftp://ftp.iana.org/assignments/media-types/> or
" <URL:http://www.iana.org/assignments/media-types/> for the registry of
" media types. On Linux try <URL:/etc/mime.types> In general this makes only
" sense when you also supply a handler for every media type you define, see
" <URL:./utl_rc.vim#r=mediaTypeHandlers>.
"
fu! s:Utl_checkMediaType(path)
if isdirectory(a:path)
return "text/directory"
endif
let ext = fnamemodify(a:path, ":e")
let mt = ''
" MS windows oriented
if ext==?'doc' || ext==?'dot' || ext==?'wrd'
let mt = 'application/msword'
elseif ext==?'xls'
let mt = 'application/excel'
elseif ext==?'ppt'
let mt = 'application/powerpoint'
elseif ext==?'wav'
let mt = 'audio/wav'
elseif ext==?'msg'
let mt = 'application/msmsg'
elseif ext==?'avi'
let mt = 'video/x-msvideo'
" universal
elseif ext==?'dvi'
let mt = 'application/x-dvi'
elseif ext==?'pdf'
let mt = 'application/pdf'
elseif ext==?'rtf'
let mt = 'application/rtf'
elseif ext==?'ai' || ext==?'eps' || ext==?'ps'
let mt = 'application/postscript'
elseif ext==?'rtf'
let mt = 'application/rtf'
elseif ext==?'zip'
let mt = 'application/zip'
elseif ext==?'mp3' || ext==?'mp2' || ext==?'mpga'
let mt = 'audio/mpeg'
elseif ext==?'png'
let mt = 'image/png'
elseif ext==?'jpeg' || ext==?'jpg' || ext==?'jpe' || ext==?'jfif'
let mt = 'image/jpeg'
elseif ext==?'tiff' || ext==?'tif'
let mt = 'image/tiff'
elseif ext==?'gif' || ext==?'gif'
let mt = 'image/gif'
elseif ext==?'mp2' || ext==?'mpe' || ext==?'mpeg' || ext==?'mpg'
let mt = 'video/mpeg'
" id=texthtml
elseif ext==?'html' || ext==?'htm'
let mt = 'text/html'
" unix/linux oriented
elseif ext==?'fig'
let mt = 'image/x-fig'
endif
return mt
endfu
"id=Utl_processFragmentText-----------------------------------------------------
" Description:
" Position cursor in current buffer according `fragment', modified by
" `fragMode' which can have values 'abs' or 'rel'.
"
" - arg `fragment' can be:
" tn=string - searches string beginning at start position forward.
" The naked fragment (without a `xx=' as prefix defaults
" to tn=).
" tp=string - searches string beginning at start position backward.
" line=number - move cursor number lines from start position. Number
" can be positive or negative. If `fragMode' is 'abs'
" -1 denotes the last line, -2 the before last line etc.
" r=identifier - (IdReference) search for id=identifier\> starting from
" begin of buffer. `fragMode' is ignored.
"
" - arg `fragMode' modifies the start position. Can have the values:
" 'abs' = absolute: Cursor is set to begin or end of document, depending on
" fragment, then position starting from there.
" Start position for tn=, line=nnn, line=+nnn r= is begin of buffer.
" Start position for tp=, line=-nnn is end of buffer.
" 'rel' = relative: Start positioning the cursor from current position.
"
" Details:
" - `fragment' will be URI-Unescaped before processing (e.g. 'tn=A%3aB' ->
" 'tn=A:B')
" - Interpretation of `fragment' depends on the filetype. But currently,
" the only non generic treatment is for HTML references.
" - `Fragment' can be '<undef>' or '' (empty).
" - If `rel' position the cursor to begin or end of line prior to actual
" search: a target string in the same line will not be found.
" (Remark: Intent is to support Same-Document references: avoid that
" the search finds the fragment definition itself. Should not be a
" problem in other cases, e.g. vimhelp scheme)
"
" Known Bugs:
" - For 'abs' search does not find pattern starting at begin of file
"
fu! s:Utl_processFragmentText(fragment, fragMode)
call Utl_trace("- start processing fragment `".a:fragment."' in mode `".a:fragMode."'",1,1)
if a:fragment == '<undef>' || a:fragment == ''
call Utl_trace("- have no or empty fragment")
if a:fragMode=='abs'
call Utl_trace("- since mode is `abs' position cursor to begin of buffer")
call cursor(1,1)
else
call Utl_trace("- since mode is `rel' do nothing")
endif
call Utl_trace("- end processing fragment",1,-1)
return
endif
let ufrag = UtlUri_unescape(a:fragment)
if ufrag != a:fragment
call Utl_trace("- unescaped URL to: `".ufrag."'")
endif
if ufrag =~ '^line=[-+]\=[0-9]*$'
call Utl_trace("- is a `line=' fragment")
let sign = substitute(ufrag, '^line=\([-+]\)\=\([0-9]*\)$', '\1', '')
let num = substitute(ufrag, '^line=\([-+]\)\=\([0-9]*\)$', '\2', '')
if a:fragMode=='abs'
if sign == '-'
call Utl_trace("- negative sign in mode 'abs': position cursor up ".num." lines from end of buffer")
call cursor( line('$') - num + 1, 1 )
else
call Utl_trace("- positive sign in mode 'abs': position cursor to line ".num)
call cursor(num,1)
endif
else
if sign == '-'
call Utl_trace("- negative sign in mode 'rel': position cursor up ".num." lines from current position")
call cursor( line('.') - num , 1 )
else
call Utl_trace("- positive sign in mode 'rel': position cursor down ".num." lines from current position")
call cursor( line('.') + num , 1 )
endif
endif
call Utl_trace("- end processing fragment",1,-1)
return
endif
" (the rest is positioning by search)
" Note: \r is necessary for executing cmd with :normal.
" Note: \M is used in patterns to do search nomagic (e.g. pattern a.c to find a.c
" and not abc).
let fragMode = a:fragMode
let sfwd=1
if ufrag =~ '^r='
call Utl_trace("- is an ID reference. Construct file type dependent search pattern")
" ( \w\@! is normally the same as \> , i.e. match end of word,
" but is not the same in help windows, where 'iskeyword' is
" set to include non word characters. \w\@! is independent of
" settings )
let val = substitute(ufrag, '^r=\(.*\)$', '\1', '')
if &ft == 'html'
call Utl_trace("- file type is 'html' - search for NAME=")
let cmd = '/\c\MNAME=\.\=' . val . '\w\@!' . "\r"
else
call Utl_trace("- file type is not 'html' - search for id=")
let cmd = '/\c\Mid=' . val . '\w\@!' . "\r"
endif
if fragMode=='rel'
call Utl_trace("- search will be with 'wrapscan' (since ID reference anywhere in text)")
let opt_wrapscan='wrapscan'
endif
elseif ufrag =~ '^tp=' " text previous
call Utl_trace("- is a `tp=' (Text Previous) fragment: search backwards")
let cmd = substitute(ufrag, '^tp=\(.*\)$', '?\\c\\M\1\r', '')
let sfwd=0
elseif ufrag =~ '^tn=' " tn= or naked. text next
call Utl_trace("- is a `tn=' (Text Next) fragment: search forward")
let cmd = substitute(ufrag, '^tn=\(.*\)$', '/\\c\\M\1\r', '')
else
call Utl_trace("- is a naked fragment. Is treated like `tn=' (Text Next) fragment: search forward")
let cmd = '/\c\M' . ufrag . "\r" " Note: \c\M vs \\c\\M at <#tp=substitute>
endif
" Initialize Cursor before actual search (CR051)
if fragMode=='abs'
if sfwd==1
call Utl_trace("- forward search in mode 'abs': starting search at begin of buffer")
call cursor(1,1)
else
call Utl_trace("- backward search in mode 'abs': starting search at end of buffer")
call cursor( line('$'), col('$') )
endif
else
if sfwd==1
call Utl_trace("- forward search in mode 'rel': starting search at end of current line")
call cursor( line('.'), col('$') )
else
call Utl_trace("- forward search in mode 'rel': starting search at begin of current line")
call cursor( line('.'), 1)
endif
endif
if ! exists('opt_wrapscan')
let opt_wrapscan = 'nowrapscan'
call Utl_trace("- search will be with 'nowrapscan' (avoid false hit if mode='rel')")
endif
" Do text search (id=fragTextSearch)
" (Should better use search() instead normal / - there is also a w flag)
let saveWrapscan = &wrapscan | exe 'set '.opt_wrapscan | "---[
" (keepjumps because before jump mark is set before link execution (s. #r=_setj ).
" Call cursor() for line= fragments do not change jumps either.)
call Utl_trace("- execute search command: `".cmd."'")
let v:errmsg = ""
silent! exe "keepjumps normal " . cmd
if v:errmsg != ""
let v:errmsg = "fragment address #" . a:fragment . " not found in target"
echohl ErrorMsg | echo v:errmsg | echohl None
endif
let &wrapscan = saveWrapscan "---]
call Utl_trace("- restored previous value for 'wrapscan'")
call Utl_trace("- end processing fragment",1,-1)
endfu
" Utility functions [
"id=Utl_utilExpandConvSpec--------------------------------------------------------
" Expands conversion specifiers like %p in a:str by replacing
" them by there replacement value. Conversion specifier - replacement pairs
" as provided in convSpecDict dictionary.
" Details :
" All occurrences of conversion specifier in a:str will be replaced.
" Specifiers not defined in convSpecDict lead to an error.
" The case of conversion specifier matters, e.g. %p and '%P' are different.
"
" Args:
" str - string to be expanded
" convSpecDict - dictionary containing specifier - replacement entries,
" e.g. 'p' - 'c:/path/to/file'
"
" Returns: List [errormessage, converted string],
" where either or the other is an empty string
"
fu! Utl_utilExpandConvSpec(str, convSpecDict)
let rest = a:str
let out = ''
while 1
let percentPos = stridx(rest, '%')
if percentPos != -1
let left = strpart(rest, 0, percentPos)
let specifier = strpart(rest, percentPos+1, 1)
let rest = strpart(rest, percentPos+2)
else
let out = out . rest
break
endif
if strpart(left, percentPos-1, 1) == '\' " escaped \%
let left = strpart(left, 0, percentPos-1)
let repl = '%' . specifier
else " not escaped
if specifier == ''
return ["Unescaped % character at end of string >".a:str."<", ""]
elseif has_key(a:convSpecDict, specifier)
let repl = a:convSpecDict[specifier]
else
return ["Invalid conversion specifier `%".specifier."' in `".a:str.
\ "'. Valid specifiers are: `". join(map(keys(a:convSpecDict), '"%".v:val')), ""]
endif
endif
let out = out . left . repl
endwhile
return ["",out]
endfu
"-------------------------------------------------------------------------------
" Print tracing messages (with :echo) to see what's going on.
" Only prints if global variable utl_opt_verbose is not 0.
" Currently works only in on/off-manner. Might be extended to distinguish
" trace levels (as Vim's 'verbose' option does, see <url:vimhelp:'verbose'>)
"
" - args
" msg,
" [flush,] boolean, default=1 -> print msg directly
" [incrLevel] number, values= -1 (reduce indent), 0 (unchanged), +1 (augment indent)
" default ist 0 (unchanged)
"
let s:utl_trace_buffer = ''
let s:utl_trace_level = 0
fu! Utl_trace(msg, ...)
if g:utl_opt_verbose == 0
return
endif
"echo " DBG msg=`".a:msg."'"
let flush=1
if exists('a:1')
let flush = a:1
endif
let incrLevel = 0
if exists('a:2')
let incrLevel = a:2
endif
" If negative, do it before printing
if incrLevel < 0
let s:utl_trace_level += incrLevel
" Assertion
if s:utl_trace_level < 0
echohl ErrorMsg
call input("Internal Error: Utl_trace: negative indent. Setting to zero <RETURN>")
echohl None
let s:utl_trace_level = 0
endif
"echo " DBG (changed,before) utl_trace_level=`".s:utl_trace_level."'"
endif
" echohl ErrorMsg
" echo "Error: internal error: s:utl_trace_level < 0: `".s:utl_trace_level."'"
" echohl None
let s:utl_trace_buffer = s:utl_trace_buffer . a:msg
if flush=='1'
" construct indenting corresponding to level
let indentNum = s:utl_trace_level
let indent = ''
while indentNum
"echo " DBG indentNum=`".indentNum."'"
let indent = indent . ' ' " indent depth is two blanks
let indentNum -= 1
endwhile
"echo " DBG indent=`".indent."'"
echo indent . s:utl_trace_buffer
let s:utl_trace_buffer = ''
endif
" If positive, do it after printing
if incrLevel > 0
let s:utl_trace_level += incrLevel
"echo " DBG (changed,after) utl_trace_level=`".s:utl_trace_level."'"
endif
endfu
"-------------------------------------------------------------------------------
" Descr: Creates a file named a:outFile as a copy of file a:srcFile, where
" only the lines between the first and the second occurrence of a:mark are kept.
" Details :
" - a:outFile gets some additional header lines.
" - a:mark is anchored at the beginning of the line (^ search)
" - a:mark is taken literally (search with \M - nomagic for it)
"
" Collaboration:
" - Shows result to user by prompting hit-any-key
" - Except for use of utl_trace function pure utility function.
"
" Ret: -
"
"
fu! Utl_utilCopyExtract(srcFile, outFile, mark)
call Utl_trace("- start Utl_utilCopyExtract(".a:srcFile.",".a:outFile.",".a:mark.")",1,1)
let go_back = 'b ' . bufnr("%")
enew!
exe 'read '.a:srcFile
setl noswapfile modifiable
norm gg
let buf = bufnr("%")
" Delete from first line to the first line that starts with a:mark
let delCmd='1,/\M^'.a:mark.'/d'
call Utl_trace("- command to delete from top to begin mark= `".delCmd."'")
exe delCmd
" Delete from the now first line that starts with a:mark to the end of the text
let delCmd='/\M^'.a:mark.'/,$d'
call Utl_trace("- command to delete from end mark to bottom= `".delCmd."'")
exe delCmd
0insert
' *****
' CREATED BY VIM PLUGIN UTL.VIM BY FUNCTION Utl_utilCopyExtract()
' *****
.
exe 'w! '.a:outFile
exe go_back
exe 'bwipeout ' . buf
echohl MoreMsg
call input("Success: Created file ".a:outFile." <RETURN>")
echohl None
call Utl_trace("- end Utl_utilCopyExtract()",1,-1)
endfu
"-------------------------------------------------------------------------------
" Substitute all slashes with forward slashes in copy of a:str and return it.
fu! Utl_utilFwd2BackSlashes(str)
return substitute( a:str , '/', '\', 'g')
endfu
"-------------------------------------------------------------------------------
" Substitute all backslashes with slashes in copy of a:str and return it.
fu! Utl_utilBack2FwdSlashes(str)
return substitute( a:str , '\', '/', 'g')
endfu
" ]
" BEGIN OF DEFINITION OF STANDARD UTL `DRIVERS' " id=utl_drivers [
"-------------------------------------------------------------------------------
" Retrieve a resource from the web using the wget network retriever.
" Function designed as g:utl_cfg_hdl_scm_http interface function, e.g. intended to
" be used via :let g:utl_cfg_hdl_scm_http="call Utl_if_hdl_scm_http__wget('%u')".
" See also #r=utl_cfg_hdl_scm_http__wget
"
" Arg: url - URL to be downloaded
" Ret: global Vim var g:utl__hdl_scm_ret_list set, containing one element:
" the name of a temporary file where wget downloaded into.
"
" Setup: See <url:config:#r=utl_if_hdl_scm_http_wget_setup>
"
fu! Utl_if_hdl_scm_http__wget(url)
call Utl_trace("- start Utl_if_hdl_scm_http__wget(".a:url.")",1,1)
" Possibly transfer suffix from URL to tempname for correct subsequent
" media type handling If no suffix then assume 'html' (ok for
" http://www.vim.org -> index.html). But is not generally ok
" (example: http://www.vim.org/download.php).
" TODO:
" Should determine media type from HTTP Header, e.g.
" wget --save-headers -> Content-Type: text/html)
let suffix = fnamemodify( UtlUri_path(a:url), ":e")
if suffix == ''
let suffix = 'html'
endif
let tmpFile = Utl_utilBack2FwdSlashes( tempname() ) .'.'.suffix
call Utl_trace("- tmpFile name with best guess suffix: ".tmpFile)
if ! executable('wget')
call Utl_trace("- Vim variable g:utl_cfg_hdl_scm_mail does not exist")
echohl WarningMsg
let v:errmsg="No executable `wget' found."
call input( v:errmsg . " Entering Setup now. <RETURN>")
echohl None
Utl openLink config:#r=utl_if_hdl_scm_http_wget_setup split
call Utl_trace("- end execution of Utl_AddressScheme_mail",1,-1)
return
endif
let cmd = '!wget '.a:url.' -O '.tmpFile
call Utl_trace("- executing cmd: `".cmd."'")
exe cmd
call Utl_trace("- setting global list g:utl__hdl_scm_ret_list to `[".tmpFile."]'")
let g:utl__hdl_scm_ret_list = [tmpFile]
call Utl_trace("- end Utl_if_hdl_scm_http__wget()",1,-1)
endfu
"-------------------------------------------------------------------------------
" Display an email in Outlook
" Function designed as g:utl_cfg_hdl_scm_mail interface function, e.g. intended to
" be used via :let g:utl_cfg_hdl_scm_mail="call Utl_if_hdl_scm_mail__outlook('%a',
" '%p','%d','%f','%s')". See also #r=utl_cfg_hdl_scm_mail__outlook
"
" Args: ...
" Ret: -
"
" Setup: See <url:config:#r=utl_if_hdl_scm_mail__outlook_setup>
fu! Utl_if_hdl_scm_mail__outlook(authority, path, date, from, subject)
call Utl_trace("- start Utl_if_hdl_scm_mail__outlook(".a:authority.",".a:path.",".a:date.",".a:from.",".a:subject.")",1,1)
if ! exists('g:utl__file_if_hdl_scm__outlook')
let g:utl__file_if_hdl_scm__outlook = fnamemodify(g:utl__file, ":h") . '/../utl_if_hdl_scm__outlook.vbs'
call Utl_trace("- configure interface handler variable for Outlook g:utl__file_if_hdl_scm__outlook=")
call Utl_trace(" ".g:utl__file_if_hdl_scm__outlook)
endif
if ! filereadable(g:utl__file_if_hdl_scm__outlook)
echohl WarningMsg
let v:errmsg="No Outlook interface found."
call input( v:errmsg . " Entering Setup now. <RETURN>")
echohl None
Utl openLink config:#r=Utl_if_hdl_scm_mail__outlook_setup split
call Utl_trace("- end Utl_if_hdl_scm_mail__outlook()",1,-1)
return
endif
let cmd='!start wscript "'.g:utl__file_if_hdl_scm__outlook .'" "'. a:authority.'" "'.a:path.'" "'.a:date.'" "'.a:from.'" "'.a:subject.'"'
call Utl_trace("- executing cmd: `".cmd."'")
exe cmd
call Utl_trace("- end Utl_if_hdl_scm_mail__outlook()",1,-1)
endfu
"-------------------------------------------------------------------------------
" Display a file in Acrobat Reader. #page=123 Fragments are supported, i.e.
" display the file at this given page.
" Function designed as g:utl_cfg_hdl_mt_application_pdf interface function,
" e.g. intended to be used via :let g:utl_cfg_hdl_mt_application_pdf="call
" Utl_if_hdl_mt_application_pdf_acrobat('%P', '%f')".
" See also #r=utl_cfg_hdl_mt_application_pdf_acrobat.
"
" Arg: path - file to be displayed in Acrobat (full path)
" fragment - fragment (without #) or empty string if no fragment
"
" Ret: -
"
" Setup: See <config:#r=Utl_if_hdl_mt_application_pdf_acrobat_setup>
"
fu! Utl_if_hdl_mt_application_pdf_acrobat(path,fragment)
call Utl_trace("- start Utl_if_hdl_mt_application_pdf_acrobat(".a:path.",".a:fragment.")",1,1)
let switches = ''
if a:fragment != ''
let ufrag = UtlUri_unescape(a:fragment)
if ufrag =~ '^page='
let fval = substitute(ufrag, '^page=', '', '')
let switches = '/a page='.fval
else
echohl ErrorMsg
echo "Unsupported fragment `#".ufrag."' Valid only `#page='"
echohl None
return
endif
endif
if ! exists('g:utl_cfg_hdl_mt_application_pdf_acrobat_exe_path') " Entering setup
call Utl_trace("- Vim variable `g:utl_cfg_hdl_mt_application_pdf_acrobat_exe_path.' does not exist")
echohl WarningMsg
call input('variable g:utl_cfg_hdl_mt_application_pdf_acrobat_exe_path not defined. Entering Setup now. <RETURN>')
echohl None
Utl openLink config:#r=Utl_if_hdl_mt_application_pdf_acrobat_setup split
call Utl_trace("- end Utl_if_hdl_mt_application_pdf_acrobat() (not successful)",1,-1)
return
endif
" id=ar_switches
let cmd = ':silent !start '.g:utl_cfg_hdl_mt_application_pdf_acrobat_exe_path.' /a page='.ufrag.' "'.a:path.'"'
call Utl_trace("- executing cmd: `".cmd."'")
exe cmd
call Utl_trace("- end Utl_if_hdl_mt_application_pdf_acrobat()",1,-1)
endfu
"-------------------------------------------------------------------------------
" Display a file in MS-Word. #tn=text Fragments are supported, i.e.
" display the file at position of first occurrence of text.
" Function designed as g:utl_cfg_hdl_mt_application_msword interface function,
" e.g. intended to be used via :let g:utl_cfg_hdl_mt_application_msword="call
" Utl_if_hdl_mt_application_msword__word('%P', '%f')".
" See also #r=utl_cfg_hdl_mt_application_msword__word.
"
" Arg: path - file to be displayed in Acrobat (full path)
" fragment - fragment (without #) or empty string if no fragment
"
" Ret: -
"
" Setup: See <config:#r=Utl_if_hdl_mt_application_msword__word_setup>
"
fu! Utl_if_hdl_mt_application_msword__word(path,fragment)
call Utl_trace("- start Utl_if_hdl_mt_application_msword__word(".a:path.",".a:fragment.")",1,1)
if ! exists('g:utl__file_if_hdl_mt_application_msword__word')
let g:utl__file_if_hdl_mt_application_msword__word = fnamemodify(g:utl__file, ":h") . '/../utl_if_hdl_mt_application_msword__word.vbs'
call Utl_trace("- configure interface handler variable for MS-Word g:utl__file_if_hdl_mt_application_msword__word=")
call Utl_trace(" ".g:utl__file_if_hdl_mt_application_msword__word)
endif
if ! filereadable(g:utl__file_if_hdl_mt_application_msword__word)
echohl WarningMsg
let v:errmsg="No Word interface found."
call input( v:errmsg . " Entering Setup now. <RETURN>")
echohl None
Utl openLink config:#r=Utl_if_hdl_mt_application_msword__word_setup split
call Utl_trace("- end Utl_if_hdl_mt_application_msword__word() (not successful)",1,-1)
return
endif
if ! exists('g:utl_cfg_hdl_mt_application_msword__word_exe_path') " Entering setup
call Utl_trace("- Vim variable `g:utl_cfg_hdl_mt_application_pdf_acrobat_exe_path.' does not exist")
echohl WarningMsg
call input('variable g:utl_cfg_hdl_mt_application_msword__word_exe_path not defined. Entering Setup now. <RETURN>')
echohl None
Utl openLink config:#r=Utl_if_hdl_mt_application_msword__word_setup split
call Utl_trace("- end Utl_if_hdl_mt_application_msword__word() (not successful)",1,-1)
return
endif
let cmd = 'silent !start '.g:utl_cfg_hdl_mt_application_msword__word_exe_path.' "'.a:path.'"'
call Utl_trace("- cmd to open document: `".cmd."'")
exe cmd
if a:fragment == ''
call Utl_trace("- end Utl_if_hdl_mt_application_msword__word() (successful, no fragment)",1,-1)
return
endif
" (CR044:frag)
let ufrag = UtlUri_unescape(a:fragment)
if ufrag =~ '^tn=' " text next / text previous
let fval = substitute(ufrag, '^tn=', '', '')
elseif ufrag =~ '[a-z]\+='
echohl ErrorMsg
echo 'Unsupported fragment key `'.substitute(ufrag, '\c^\([a-z]\+\).*', '\1=', '')."'. Valid only: `tn='"
echohl None
call Utl_trace("- end Utl_if_hdl_mt_application_msword__word() (not successful)",1,-1)
return
else
let fval=ufrag " naked fragment same as tn=
endif
let cmd='silent !start wscript "'.g:utl__file_if_hdl_mt_application_msword__word .'" "'. a:path.'" "'.fval.'"'
call Utl_trace("- cmd to address fragment: `".cmd."'")
exe cmd
call Utl_trace("- end Utl_if_hdl_mt_application_msword__word()",1,-1)
endfu
let &cpo = s:save_cpo
finish
=== FILE_OUTLOOK_VBS {{{
' file: utl_if_hdl_scm__outlook.vbs
' synopsis: utl_if_hdl_scm__outlook.vbs "" "Inbox" "08.02.2008 13:31" "" ""
' collaboration: - Used by utl.vim when accessing "mail:" URLs using MS-Outlook.
' - Outlook must be running
' hist:
' 2008-02-29/Stb: Version for Utl.vim v3.0a
Option Explicit
Dim ol, olns, folder, entryId, item, myNewFolder
Dim a_authority, a_path, a_from, a_subject, a_date
a_authority = WScript.Arguments(0)
a_path = WScript.Arguments(1)
a_date = WScript.Arguments(2)
a_from = WScript.Arguments(3)
a_subject = WScript.Arguments(4)
if a_from <> "" Then
MsgBox "utl_if_hdl_scm__outlook.vbs: Sorry: from= query not supported. Will be ignored"
end if
if a_from <> "" Then
MsgBox "utl_if_hdl_scm__outlook.vbs: Sorry: subject= query not supported. Will be ignored"
end if
Set ol = GetObject(, "Outlook.Application")
Set olns = ol.GetNameSpace("MAPI")
'-----
' Get root folder
if a_authority = "" Then
' No a_authority defaults to folder which contains the default folders
Set folder = olns.GetDefaultFolder(6)
Set folder = folder.Parent
else
Set folder = olns.Folders.item( a_authority )
end if
'-----
' Trailing slash possible even with no path defined.
' So remove it independently of path treatment
if a_path <> "" Then
' Remove leading "/"
a_path = Right( a_path, Len(a_path)-1 )
end if
'-----
' If a_path given search a_path recursively to get corresponding
' folder object (currently no hierarchies, only one subfolder)
if a_path <> "" Then
Set folder = folder.Folders.item( a_path )
end if
Dim sFilter
'-----
' Four minute time range turned out to work fairly well finally...
Dim dateMin, dateMax
dateMin = CStr( DateAdd("n", -2, a_date) )
dateMax = CStr( DateAdd("n", 2, a_date) )
' cut seconds added by DateAdd
dateMin = Left(dateMin, Len(dateMin) -3 )
dateMax = Left(dateMax, Len(dateMax) -3 )
'id=adapt_column_name
' Unless you have a german Outlook adapt the following line to match you language.
' The Word "Erhalten" probably something like "Received" in english.
' Have a look in you Outlook; its the name of the column which shows and sorts
' by date.
'
'
' [id=received] Change to actual column name in your Outlook
' +---------------------------------+
' v v
sFilter = "[Erhalten] > '" + dateMin + "' AND [Erhalten] < '" + dateMax + "'"
Set item = folder.Items.find(sFilter)
item.Display
=== FILE_OUTLOOK_VBS }}}
=== FILE_WORD_VBS {{{
' usage: utl_if_hdl_mt_application_msword__word.vbs <.doc file> <string_to_search>
' description: Position cursor in Word document <.doc file> at string
' <string_to_search>
' Collaboration: Word being started or running. Document subject to fragment
' addressing active or being opened and activated.
' hist:
' 2008-03-20/Stb: Version for Utl.vim v3.0a
' TODO: "Option Explicit" ( Can't get it running with... %-/ )
const wdGoToPage = 1
const wdGoToAbsolute = 1
const wdFindContinue = 1
docPath = WScript.Arguments(0)
fragment = WScript.Arguments(1)
' Wait for WORD in case it just starts up
countTries = 0
maxTries = 50
Do While countTries < maxTries
countTries = countTries+1
On Error Resume Next
Set o = GetObject(, "Word.Application")
If Err Then
WScript.Sleep 200
Err.Clear
Else
Exit Do
End If
Loop
' TODO: Exit if still not loaded
' Wait until document loaded
countTries = 0
maxTries = 20
docFound = FALSE
Do While countTries < maxTries
countTries = countTries+1
' schauen ob ActiveDocument.Name (schon) gleich
' dem docPath ist.
pos = InStr(1, docPath, o.ActiveDocument.Name, 1)
If pos <> 0 then
docFound = TRUE
Exit Do
End If
WScript.Sleep 200
Loop
If docFound=FALSE then
WScript.Echo("Document not found")
End If
' TODO: Exit If docFound=FALSE
' assertion: document active
' process fragment
' TODO: support also page= fragment:
' 'o.Selection.GoTo wdGotoPage, wdGoToAbsolute, 20
o.Selection.Find.ClearFormatting
With o.Selection.Find
.Text = fragment
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
o.Selection.Find.Execute
=== FILE_WORD_VBS }}}
" END OF DEFINITION OF STANDARD UTL `DRIVERS' ]
" vim: set foldmethod=marker:
" -----id=foot1
" Thanks for trying out Utl.vim :-)