1847 lines
66 KiB
VimL
1847 lines
66 KiB
VimL
|
" ------------------------------------------------------------------------------
|
||
|
" 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 :-)
|