aboutsummaryrefslogtreecommitdiff
path: root/runtime/autoload
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/autoload')
-rw-r--r--runtime/autoload/getscript.vim667
-rw-r--r--runtime/autoload/msgpack.vim820
-rw-r--r--runtime/autoload/provider/python.vim2
-rw-r--r--runtime/autoload/provider/python3.vim2
-rw-r--r--runtime/autoload/remote/host.vim17
-rw-r--r--runtime/autoload/shada.vim696
-rw-r--r--runtime/autoload/spellfile.vim8
-rw-r--r--runtime/autoload/tutor.vim7
8 files changed, 1542 insertions, 677 deletions
diff --git a/runtime/autoload/getscript.vim b/runtime/autoload/getscript.vim
deleted file mode 100644
index d50bc2edc0..0000000000
--- a/runtime/autoload/getscript.vim
+++ /dev/null
@@ -1,667 +0,0 @@
-" ---------------------------------------------------------------------
-" getscript.vim
-" Author: Charles E. Campbell
-" Date: Jan 21, 2014
-" Version: 36
-" Installing: :help glvs-install
-" Usage: :help glvs
-"
-" GetLatestVimScripts: 642 1 :AutoInstall: getscript.vim
-"redraw!|call inputsave()|call input("Press <cr> to continue")|call inputrestore()
-" ---------------------------------------------------------------------
-" Initialization: {{{1
-" if you're sourcing this file, surely you can't be
-" expecting vim to be in its vi-compatible mode!
-if exists("g:loaded_getscript")
- finish
-endif
-let g:loaded_getscript= "v36"
-if &cp
- echoerr "GetLatestVimScripts is not vi-compatible; not loaded (you need to set nocp)"
- finish
-endif
-if v:version < 702
- echohl WarningMsg
- echo "***warning*** this version of getscript needs vim 7.2"
- echohl Normal
- finish
-endif
-let s:keepcpo = &cpo
-set cpo&vim
-"DechoTabOn
-
-" ---------------------------
-" Global Variables: {{{1
-" ---------------------------
-" Cygwin Detection ------- {{{2
-if !exists("g:getscript_cygwin")
- if has("win32") || has("win95") || has("win64") || has("win16")
- if &shell =~ '\%(\<bash\>\|\<zsh\>\)\%(\.exe\)\=$'
- let g:getscript_cygwin= 1
- else
- let g:getscript_cygwin= 0
- endif
- else
- let g:getscript_cygwin= 0
- endif
-endif
-
-" wget vs curl {{{2
-if !exists("g:GetLatestVimScripts_wget")
- if executable("wget")
- let g:GetLatestVimScripts_wget= "wget"
- elseif executable("curl")
- let g:GetLatestVimScripts_wget= "curl"
- else
- let g:GetLatestVimScripts_wget = 'echo "GetLatestVimScripts needs wget or curl"'
- let g:GetLatestVimScripts_options = ""
- endif
-endif
-
-" options that wget and curl require:
-if !exists("g:GetLatestVimScripts_options")
- if g:GetLatestVimScripts_wget == "wget"
- let g:GetLatestVimScripts_options= "-q -O"
- elseif g:GetLatestVimScripts_wget == "curl"
- let g:GetLatestVimScripts_options= "-s -O"
- else
- let g:GetLatestVimScripts_options= ""
- endif
-endif
-
-" by default, allow autoinstall lines to work
-if !exists("g:GetLatestVimScripts_allowautoinstall")
- let g:GetLatestVimScripts_allowautoinstall= 1
-endif
-
-" set up default scriptaddr address
-if !exists("g:GetLatestVimScripts_scriptaddr")
- let g:GetLatestVimScripts_scriptaddr = 'http://vim.sourceforge.net/script.php?script_id='
-endif
-
-"" For debugging:
-"let g:GetLatestVimScripts_wget = "echo"
-"let g:GetLatestVimScripts_options = "options"
-
-" ---------------------------------------------------------------------
-" Check If AutoInstall Capable: {{{1
-let s:autoinstall= ""
-if g:GetLatestVimScripts_allowautoinstall
-
- if (has("win32") || has("gui_win32") || has("gui_win32s") || has("win16") || has("win64") || has("win32unix") || has("win95")) && &shell != "bash"
- " windows (but not cygwin/bash)
- let s:dotvim= "vimfiles"
- if !exists("g:GetLatestVimScripts_mv")
- let g:GetLatestVimScripts_mv= "ren"
- endif
-
- else
- " unix
- let s:dotvim= ".vim"
- if !exists("g:GetLatestVimScripts_mv")
- let g:GetLatestVimScripts_mv= "mv"
- endif
- endif
-
- if exists("g:GetLatestVimScripts_autoinstalldir") && isdirectory(g:GetLatestVimScripts_autoinstalldir)
- let s:autoinstall= g:GetLatestVimScripts_autoinstalldir"
- elseif exists('$HOME') && isdirectory(expand("$HOME")."/".s:dotvim)
- let s:autoinstall= $HOME."/".s:dotvim
- endif
-" call Decho("s:autoinstall<".s:autoinstall.">")
-"else "Decho
-" call Decho("g:GetLatestVimScripts_allowautoinstall=".g:GetLatestVimScripts_allowautoinstall.": :AutoInstall: disabled")
-endif
-
-" ---------------------------------------------------------------------
-" Public Interface: {{{1
-com! -nargs=0 GetLatestVimScripts call getscript#GetLatestVimScripts()
-com! -nargs=0 GetScript call getscript#GetLatestVimScripts()
-silent! com -nargs=0 GLVS call getscript#GetLatestVimScripts()
-
-" ---------------------------------------------------------------------
-" GetLatestVimScripts: this function gets the latest versions of {{{1
-" scripts based on the list in
-" (first dir in runtimepath)/GetLatest/GetLatestVimScripts.dat
-fun! getscript#GetLatestVimScripts()
-" call Dfunc("GetLatestVimScripts() autoinstall<".s:autoinstall.">")
-
-" insure that wget is executable
- if executable(g:GetLatestVimScripts_wget) != 1
- echoerr "GetLatestVimScripts needs ".g:GetLatestVimScripts_wget." which apparently is not available on your system"
-" call Dret("GetLatestVimScripts : wget not executable/availble")
- return
- endif
-
- " insure that fnameescape() is available
- if !exists("*fnameescape")
- echoerr "GetLatestVimScripts needs fnameescape() (provided by 7.1.299 or later)"
- return
- endif
-
- " Find the .../GetLatest subdirectory under the runtimepath
- for datadir in split(&rtp,',') + ['']
- if isdirectory(datadir."/GetLatest")
-" call Decho("found directory<".datadir.">")
- let datadir= datadir . "/GetLatest"
- break
- endif
- if filereadable(datadir."GetLatestVimScripts.dat")
-" call Decho("found ".datadir."/GetLatestVimScripts.dat")
- break
- endif
- endfor
-
- " Sanity checks: readability and writability
- if datadir == ""
- echoerr 'Missing "GetLatest/" on your runtimepath - see :help glvs-dist-install'
-" call Dret("GetLatestVimScripts : unable to find a GetLatest subdirectory")
- return
- endif
- if filewritable(datadir) != 2
- echoerr "(getLatestVimScripts) Your ".datadir." isn't writable"
-" call Dret("GetLatestVimScripts : non-writable directory<".datadir.">")
- return
- endif
- let datafile= datadir."/GetLatestVimScripts.dat"
- if !filereadable(datafile)
- echoerr "Your data file<".datafile."> isn't readable"
-" call Dret("GetLatestVimScripts : non-readable datafile<".datafile.">")
- return
- endif
- if !filewritable(datafile)
- echoerr "Your data file<".datafile."> isn't writable"
-" call Dret("GetLatestVimScripts : non-writable datafile<".datafile.">")
- return
- endif
- " --------------------
- " Passed sanity checks
- " --------------------
-
-" call Decho("datadir <".datadir.">")
-" call Decho("datafile <".datafile.">")
-
- " don't let any event handlers interfere (like winmanager's, taglist's, etc)
- let eikeep = &ei
- let hlskeep = &hls
- let acdkeep = &acd
- set ei=all hls&vim noacd
-
- " Edit the datafile (ie. GetLatestVimScripts.dat):
- " 1. record current directory (origdir),
- " 2. change directory to datadir,
- " 3. split window
- " 4. edit datafile
- let origdir= getcwd()
-" call Decho("exe cd ".fnameescape(substitute(datadir,'\','/','ge')))
- exe "cd ".fnameescape(substitute(datadir,'\','/','ge'))
- split
-" call Decho("exe e ".fnameescape(substitute(datafile,'\','/','ge')))
- exe "e ".fnameescape(substitute(datafile,'\','/','ge'))
- res 1000
- let s:downloads = 0
- let s:downerrors= 0
-
- " Check on dependencies mentioned in plugins
-" call Decho(" ")
-" call Decho("searching plugins for GetLatestVimScripts dependencies")
- let lastline = line("$")
-" call Decho("lastline#".lastline)
- let firstdir = substitute(&rtp,',.*$','','')
- let plugins = split(globpath(firstdir,"plugin/**/*.vim"),'\n')
- let plugins = plugins + split(globpath(firstdir,"AsNeeded/**/*.vim"),'\n')
- let foundscript = 0
-
- " this loop updates the GetLatestVimScripts.dat file
- " with dependencies explicitly mentioned in the plugins
- " via GetLatestVimScripts: ... lines
- " It reads the plugin script at the end of the GetLatestVimScripts.dat
- " file, examines it, and then removes it.
- for plugin in plugins
-" call Decho(" ")
-" call Decho("plugin<".plugin.">")
-
- " read plugin in
- " evidently a :r creates a new buffer (the "#" buffer) that is subsequently unused -- bwiping it
- $
-" call Decho(".dependency checking<".plugin."> line$=".line("$"))
-" call Decho("..exe silent r ".fnameescape(plugin))
- exe "silent r ".fnameescape(plugin)
- exe "silent bwipe ".bufnr("#")
-
- while search('^"\s\+GetLatestVimScripts:\s\+\d\+\s\+\d\+','W') != 0
- let depscript = substitute(getline("."),'^"\s\+GetLatestVimScripts:\s\+\d\+\s\+\d\+\s\+\(.*\)$','\1','e')
- let depscriptid = substitute(getline("."),'^"\s\+GetLatestVimScripts:\s\+\(\d\+\)\s\+.*$','\1','')
- let llp1 = lastline+1
-" call Decho("..depscript<".depscript.">")
-
- " found a "GetLatestVimScripts: # #" line in the script;
- " check if its already in the datafile by searching backwards from llp1,
- " the (prior to reading in the plugin script) last line plus one of the GetLatestVimScripts.dat file,
- " for the script-id with no wrapping allowed.
- let curline = line(".")
- let noai_script = substitute(depscript,'\s*:AutoInstall:\s*','','e')
- exe llp1
- let srchline = search('^\s*'.depscriptid.'\s\+\d\+\s\+.*$','bW')
- if srchline == 0
- " this second search is taken when, for example, a 0 0 scriptname is to be skipped over
- let srchline= search('\<'.noai_script.'\>','bW')
- endif
-" call Decho("..noai_script<".noai_script."> depscriptid#".depscriptid." srchline#".srchline." curline#".line(".")." lastline#".lastline)
-
- if srchline == 0
- " found a new script to permanently include in the datafile
- let keep_rega = @a
- let @a = substitute(getline(curline),'^"\s\+GetLatestVimScripts:\s\+','','')
- echomsg "Appending <".@a."> to ".datafile." for ".depscript
-" call Decho("..Appending <".@a."> to ".datafile." for ".depscript)
- exe lastline."put a"
- let @a = keep_rega
- let lastline = llp1
- let curline = curline + 1
- let foundscript = foundscript + 1
-" else " Decho
-" call Decho("..found <".noai_script."> (already in datafile at line#".srchline.")")
- endif
-
- let curline = curline + 1
- exe curline
- endwhile
-
- " llp1: last line plus one
- let llp1= lastline + 1
-" call Decho(".deleting lines: ".llp1.",$d")
- exe "silent! ".llp1.",$d"
- endfor
-" call Decho("--- end dependency checking loop --- foundscript=".foundscript)
-" call Decho(" ")
-" call Dredir("BUFFER TEST (GetLatestVimScripts 1)","ls!")
-
- if foundscript == 0
- setlocal nomod
- endif
-
- " --------------------------------------------------------------------
- " Check on out-of-date scripts using GetLatest/GetLatestVimScripts.dat
- " --------------------------------------------------------------------
-" call Decho("begin: checking out-of-date scripts using datafile<".datafile.">")
- setlocal lz
- 1
-" /^-----/,$g/^\s*\d/call Decho(getline("."))
- 1
- /^-----/,$g/^\s*\d/call s:GetOneScript()
-" call Decho("--- end out-of-date checking --- ")
-
- " Final report (an echomsg)
- try
- silent! ?^-------?
- catch /^Vim\%((\a\+)\)\=:E114/
-" call Dret("GetLatestVimScripts : nothing done!")
- return
- endtry
- exe "norm! kz\<CR>"
- redraw!
- let s:msg = ""
- if s:downloads == 1
- let s:msg = "Downloaded one updated script to <".datadir.">"
- elseif s:downloads == 2
- let s:msg= "Downloaded two updated scripts to <".datadir.">"
- elseif s:downloads > 1
- let s:msg= "Downloaded ".s:downloads." updated scripts to <".datadir.">"
- else
- let s:msg= "Everything was already current"
- endif
- if s:downerrors > 0
- let s:msg= s:msg." (".s:downerrors." downloading errors)"
- endif
- echomsg s:msg
- " save the file
- if &mod
- silent! w!
- endif
- q!
-
- " restore events and current directory
- exe "cd ".fnameescape(substitute(origdir,'\','/','ge'))
- let &ei = eikeep
- let &hls = hlskeep
- let &acd = acdkeep
- setlocal nolz
-" call Dredir("BUFFER TEST (GetLatestVimScripts 2)","ls!")
-" call Dret("GetLatestVimScripts : did ".s:downloads." downloads")
-endfun
-
-" ---------------------------------------------------------------------
-" GetOneScript: (Get Latest Vim Script) this function operates {{{1
-" on the current line, interpreting two numbers and text as
-" ScriptID, SourceID, and Filename.
-" It downloads any scripts that have newer versions from vim.sourceforge.net.
-fun! s:GetOneScript(...)
-" call Dfunc("GetOneScript()")
-
- " set options to allow progress to be shown on screen
- let rega= @a
- let t_ti= &t_ti
- let t_te= &t_te
- let rs = &rs
- set t_ti= t_te= nors
-
- " put current line on top-of-screen and interpret it into
- " a script identifer : used to obtain webpage
- " source identifier : used to identify current version
- " and an associated comment: used to report on what's being considered
- if a:0 >= 3
- let scriptid = a:1
- let srcid = a:2
- let fname = a:3
- let cmmnt = ""
-" call Decho("scriptid<".scriptid.">")
-" call Decho("srcid <".srcid.">")
-" call Decho("fname <".fname.">")
- else
- let curline = getline(".")
- if curline =~ '^\s*#'
- let @a= rega
-" call Dret("GetOneScript : skipping a pure comment line")
- return
- endif
- let parsepat = '^\s*\(\d\+\)\s\+\(\d\+\)\s\+\(.\{-}\)\(\s*#.*\)\=$'
- try
- let scriptid = substitute(curline,parsepat,'\1','e')
- catch /^Vim\%((\a\+)\)\=:E486/
- let scriptid= 0
- endtry
- try
- let srcid = substitute(curline,parsepat,'\2','e')
- catch /^Vim\%((\a\+)\)\=:E486/
- let srcid= 0
- endtry
- try
- let fname= substitute(curline,parsepat,'\3','e')
- catch /^Vim\%((\a\+)\)\=:E486/
- let fname= ""
- endtry
- try
- let cmmnt= substitute(curline,parsepat,'\4','e')
- catch /^Vim\%((\a\+)\)\=:E486/
- let cmmnt= ""
- endtry
-" call Decho("curline <".curline.">")
-" call Decho("parsepat<".parsepat.">")
-" call Decho("scriptid<".scriptid.">")
-" call Decho("srcid <".srcid.">")
-" call Decho("fname <".fname.">")
- endif
-
- " plugin author protection from downloading his/her own scripts atop their latest work
- if scriptid == 0 || srcid == 0
- " When looking for :AutoInstall: lines, skip scripts that have 0 0 scriptname
- let @a= rega
-" call Dret("GetOneScript : skipping a scriptid==srcid==0 line")
- return
- endif
-
- let doautoinstall= 0
- if fname =~ ":AutoInstall:"
-" call Decho("case AutoInstall: fname<".fname.">")
- let aicmmnt= substitute(fname,'\s\+:AutoInstall:\s\+',' ','')
-" call Decho("aicmmnt<".aicmmnt."> s:autoinstall=".s:autoinstall)
- if s:autoinstall != ""
- let doautoinstall = g:GetLatestVimScripts_allowautoinstall
- endif
- else
- let aicmmnt= fname
- endif
-" call Decho("aicmmnt<".aicmmnt.">: doautoinstall=".doautoinstall)
-
- exe "norm z\<CR>"
- redraw!
-" call Decho('considering <'.aicmmnt.'> scriptid='.scriptid.' srcid='.srcid)
- echo 'considering <'.aicmmnt.'> scriptid='.scriptid.' srcid='.srcid
-
- " grab a copy of the plugin's vim.sourceforge.net webpage
- let scriptaddr = g:GetLatestVimScripts_scriptaddr.scriptid
- let tmpfile = tempname()
- let v:errmsg = ""
-
- " make up to three tries at downloading the description
- let itry= 1
- while itry <= 3
-" call Decho(".try#".itry." to download description of <".aicmmnt."> with addr=".scriptaddr)
- if has("win32") || has("win16") || has("win95")
-" call Decho(".new|exe silent r!".g:GetLatestVimScripts_wget." ".g:GetLatestVimScripts_options." ".shellescape(tmpfile).' '.shellescape(scriptaddr)."|bw!")
- new|exe "silent r!".g:GetLatestVimScripts_wget." ".g:GetLatestVimScripts_options." ".shellescape(tmpfile).' '.shellescape(scriptaddr)|bw!
- else
-" call Decho(".exe silent !".g:GetLatestVimScripts_wget." ".g:GetLatestVimScripts_options." ".shellescape(tmpfile)." ".shellescape(scriptaddr))
- exe "silent !".g:GetLatestVimScripts_wget." ".g:GetLatestVimScripts_options." ".shellescape(tmpfile)." ".shellescape(scriptaddr)
- endif
- if itry == 1
- exe "silent vsplit ".fnameescape(tmpfile)
- else
- silent! e %
- endif
- setlocal bh=wipe
-
- " find the latest source-id in the plugin's webpage
- silent! 1
- let findpkg= search('Click on the package to download','W')
- if findpkg > 0
- break
- endif
- let itry= itry + 1
- endwhile
-" call Decho(" --- end downloading tries while loop --- itry=".itry)
-
- " testing: did finding "Click on the package..." fail?
- if findpkg == 0 || itry >= 4
- silent q!
- call delete(tmpfile)
- " restore options
- let &t_ti = t_ti
- let &t_te = t_te
- let &rs = rs
- let s:downerrors = s:downerrors + 1
-" call Decho("***warning*** couldn'".'t find "Click on the package..." in description page for <'.aicmmnt.">")
- echomsg "***warning*** couldn'".'t find "Click on the package..." in description page for <'.aicmmnt.">"
-" call Dret("GetOneScript : srch for /Click on the package/ failed")
- let @a= rega
- return
- endif
-" call Decho('found "Click on the package to download"')
-
- let findsrcid= search('src_id=','W')
- if findsrcid == 0
- silent q!
- call delete(tmpfile)
- " restore options
- let &t_ti = t_ti
- let &t_te = t_te
- let &rs = rs
- let s:downerrors = s:downerrors + 1
-" call Decho("***warning*** couldn'".'t find "src_id=" in description page for <'.aicmmnt.">")
- echomsg "***warning*** couldn'".'t find "src_id=" in description page for <'.aicmmnt.">"
- let @a= rega
-" call Dret("GetOneScript : srch for /src_id/ failed")
- return
- endif
-" call Decho('found "src_id=" in description page')
-
- let srcidpat = '^\s*<td class.*src_id=\(\d\+\)">\([^<]\+\)<.*$'
- let latestsrcid= substitute(getline("."),srcidpat,'\1','')
- let sname = substitute(getline("."),srcidpat,'\2','') " script name actually downloaded
-" call Decho("srcidpat<".srcidpat."> latestsrcid<".latestsrcid."> sname<".sname.">")
- silent q!
- call delete(tmpfile)
-
- " convert the strings-of-numbers into numbers
- let srcid = srcid + 0
- let latestsrcid = latestsrcid + 0
-" call Decho("srcid=".srcid." latestsrcid=".latestsrcid." sname<".sname.">")
-
- " has the plugin's most-recent srcid increased, which indicates that it has been updated
- if latestsrcid > srcid
-" call Decho("[latestsrcid=".latestsrcid."] <= [srcid=".srcid."]: need to update <".sname.">")
-
- let s:downloads= s:downloads + 1
- if sname == bufname("%")
- " GetLatestVimScript has to be careful about downloading itself
- let sname= "NEW_".sname
- endif
-
- " -----------------------------------------------------------------------------
- " the plugin has been updated since we last obtained it, so download a new copy
- " -----------------------------------------------------------------------------
-" call Decho(".downloading new <".sname.">")
- echomsg ".downloading new <".sname.">"
- if has("win32") || has("win16") || has("win95")
-" call Decho(".new|exe silent r!".g:GetLatestVimScripts_wget." ".g:GetLatestVimScripts_options." ".shellescape(sname)." ".shellescape('http://vim.sourceforge.net/scripts/download_script.php?src_id='.latestsrcid)."|q")
- new|exe "silent r!".g:GetLatestVimScripts_wget." ".g:GetLatestVimScripts_options." ".shellescape(sname)." ".shellescape('http://vim.sourceforge.net/scripts/download_script.php?src_id='.latestsrcid)|q
- else
-" call Decho(".exe silent !".g:GetLatestVimScripts_wget." ".g:GetLatestVimScripts_options." ".shellescape(sname)." ".shellescape('http://vim.sourceforge.net/scripts/download_script.php?src_id='))
- exe "silent !".g:GetLatestVimScripts_wget." ".g:GetLatestVimScripts_options." ".shellescape(sname)." ".shellescape('http://vim.sourceforge.net/scripts/download_script.php?src_id=').latestsrcid
- endif
-
- " --------------------------------------------------------------------------
- " AutoInstall: only if doautoinstall has been requested by the plugin itself
- " --------------------------------------------------------------------------
-" call Decho("checking if plugin requested autoinstall: doautoinstall=".doautoinstall)
- if doautoinstall
-" call Decho(" ")
-" call Decho("Autoinstall: getcwd<".getcwd()."> filereadable(".sname.")=".filereadable(sname))
- if filereadable(sname)
-" call Decho("<".sname."> is readable")
-" call Decho("exe silent !".g:GetLatestVimScripts_mv." ".shellescape(sname)." ".shellescape(s:autoinstall))
- exe "silent !".g:GetLatestVimScripts_mv." ".shellescape(sname)." ".shellescape(s:autoinstall)
- let curdir = fnameescape(substitute(getcwd(),'\','/','ge'))
- let installdir= curdir."/Installed"
- if !isdirectory(installdir)
- call mkdir(installdir)
- endif
-" call Decho("curdir<".curdir."> installdir<".installdir.">")
-" call Decho("exe cd ".fnameescape(s:autoinstall))
- exe "cd ".fnameescape(s:autoinstall)
-
- " determine target directory for moves
- let firstdir= substitute(&rtp,',.*$','','')
- let pname = substitute(sname,'\..*','.vim','')
-" call Decho("determine tgtdir: is <".firstdir.'/AsNeeded/'.pname." readable?")
- if filereadable(firstdir.'/AsNeeded/'.pname)
- let tgtdir= "AsNeeded"
- else
- let tgtdir= "plugin"
- endif
-" call Decho("tgtdir<".tgtdir."> pname<".pname.">")
-
- " decompress
- if sname =~ '\.bz2$'
-" call Decho("decompress: attempt to bunzip2 ".sname)
- exe "sil !bunzip2 ".shellescape(sname)
- let sname= substitute(sname,'\.bz2$','','')
-" call Decho("decompress: new sname<".sname."> after bunzip2")
- elseif sname =~ '\.gz$'
-" call Decho("decompress: attempt to gunzip ".sname)
- exe "sil !gunzip ".shellescape(sname)
- let sname= substitute(sname,'\.gz$','','')
-" call Decho("decompress: new sname<".sname."> after gunzip")
- elseif sname =~ '\.xz$'
-" call Decho("decompress: attempt to unxz ".sname)
- exe "sil !unxz ".shellescape(sname)
- let sname= substitute(sname,'\.xz$','','')
-" call Decho("decompress: new sname<".sname."> after unxz")
- else
-" call Decho("no decompression needed")
- endif
-
- " distribute archive(.zip, .tar, .vba, ...) contents
- if sname =~ '\.zip$'
-" call Decho("dearchive: attempt to unzip ".sname)
- exe "silent !unzip -o ".shellescape(sname)
- elseif sname =~ '\.tar$'
-" call Decho("dearchive: attempt to untar ".sname)
- exe "silent !tar -xvf ".shellescape(sname)
- elseif sname =~ '\.tgz$'
-" call Decho("dearchive: attempt to untar+gunzip ".sname)
- exe "silent !tar -zxvf ".shellescape(sname)
- elseif sname =~ '\.taz$'
-" call Decho("dearchive: attempt to untar+uncompress ".sname)
- exe "silent !tar -Zxvf ".shellescape(sname)
- elseif sname =~ '\.tbz$'
-" call Decho("dearchive: attempt to untar+bunzip2 ".sname)
- exe "silent !tar -jxvf ".shellescape(sname)
- elseif sname =~ '\.txz$'
-" call Decho("dearchive: attempt to untar+xz ".sname)
- exe "silent !tar -Jxvf ".shellescape(sname)
- elseif sname =~ '\.vba$'
-" call Decho("dearchive: attempt to handle a vimball: ".sname)
- silent 1split
- if exists("g:vimball_home")
- let oldvimballhome= g:vimball_home
- endif
- let g:vimball_home= s:autoinstall
- exe "silent e ".fnameescape(sname)
- silent so %
- silent q
- if exists("oldvimballhome")
- let g:vimball_home= oldvimballhome
- else
- unlet g:vimball_home
- endif
- else
-" call Decho("no dearchiving needed")
- endif
-
- " ---------------------------------------------
- " move plugin to plugin/ or AsNeeded/ directory
- " ---------------------------------------------
- if sname =~ '.vim$'
-" call Decho("dearchive: attempt to simply move ".sname." to ".tgtdir)
- exe "silent !".g:GetLatestVimScripts_mv." ".shellescape(sname)." ".tgtdir
- else
-" call Decho("dearchive: move <".sname."> to installdir<".installdir.">")
- exe "silent !".g:GetLatestVimScripts_mv." ".shellescape(sname)." ".installdir
- endif
- if tgtdir != "plugin"
-" call Decho("exe silent !".g:GetLatestVimScripts_mv." plugin/".shellescape(pname)." ".tgtdir)
- exe "silent !".g:GetLatestVimScripts_mv." plugin/".shellescape(pname)." ".tgtdir
- endif
-
- " helptags step
- let docdir= substitute(&rtp,',.*','','e')."/doc"
-" call Decho("helptags: docdir<".docdir.">")
- exe "helptags ".fnameescape(docdir)
- exe "cd ".fnameescape(curdir)
- endif
- if fname !~ ':AutoInstall:'
- let modline=scriptid." ".latestsrcid." :AutoInstall: ".fname.cmmnt
- else
- let modline=scriptid." ".latestsrcid." ".fname.cmmnt
- endif
- else
- let modline=scriptid." ".latestsrcid." ".fname.cmmnt
- endif
-
- " update the data in the <GetLatestVimScripts.dat> file
- call setline(line("."),modline)
-" call Decho("update data in ".expand("%")."#".line(".").": modline<".modline.">")
-" else " Decho
-" call Decho("[latestsrcid=".latestsrcid."] <= [srcid=".srcid."], no need to update")
- endif
-
- " restore options
- let &t_ti = t_ti
- let &t_te = t_te
- let &rs = rs
- let @a = rega
-" call Dredir("BUFFER TEST (GetOneScript)","ls!")
-
-" call Dret("GetOneScript")
-endfun
-
-" ---------------------------------------------------------------------
-" Restore Options: {{{1
-let &cpo= s:keepcpo
-unlet s:keepcpo
-
-" ---------------------------------------------------------------------
-" Modelines: {{{1
-" vim: ts=8 sts=2 fdm=marker nowrap
diff --git a/runtime/autoload/msgpack.vim b/runtime/autoload/msgpack.vim
new file mode 100644
index 0000000000..e6022922fe
--- /dev/null
+++ b/runtime/autoload/msgpack.vim
@@ -0,0 +1,820 @@
+if exists('g:loaded_msgpack_autoload')
+ finish
+endif
+let g:loaded_msgpack_autoload = 1
+
+""
+" Check that given value is an integer. Respects |msgpack-special-dict|.
+function msgpack#is_int(v) abort
+ return type(a:v) == type(0) || (
+ \type(a:v) == type({}) && get(a:v, '_TYPE') is# v:msgpack_types.integer)
+endfunction
+
+""
+" Check that given value is an unsigned integer. Respects
+" |msgpack-special-dict|.
+function msgpack#is_uint(v) abort
+ return msgpack#is_int(a:v) && (type(a:v) == type(0)
+ \? a:v >= 0
+ \: a:v._VAL[0] > 0)
+endfunction
+
+""
+" True if s:msgpack_init_python() function was already run.
+let s:msgpack_python_initialized = 0
+
+""
+" Cached return of s:msgpack_init_python() used when
+" s:msgpack_python_initialized is true.
+let s:msgpack_python_type = 0
+
+""
+" Create Python functions that are necessary for work. Also defines functions
+" s:msgpack_dict_strftime(format, timestamp) and s:msgpack_dict_strptime(format,
+" string).
+"
+" @return Zero in case no Python is available, empty string if Python-2 is
+" available and string `"3"` if Python-3 is available.
+function s:msgpack_init_python() abort
+ if s:msgpack_python_initialized
+ return s:msgpack_python_type
+ endif
+ let s:msgpack_python_initialized = 1
+ for suf in ['', '3']
+ try
+ execute 'python' . suf
+ \. "def shada_dict_strftime():\n"
+ \. " import datetime\n"
+ \. " import vim\n"
+ \. " fmt = vim.eval('a:format')\n"
+ \. " timestamp = vim.eval('a:timestamp')\n"
+ \. " timestamp = [int(v) for v in timestamp['_VAL']]\n"
+ \. " timestamp = timestamp[0] * (timestamp[1] << 62\n"
+ \. " | timestamp[2] << 31\n"
+ \. " | timestamp[3])\n"
+ \. " time = datetime.datetime.fromtimestamp(timestamp)\n"
+ \. " return time.strftime(fmt)\n"
+ \. "def shada_dict_strptime():\n"
+ \. " import datetime\n"
+ \. " import vim\n"
+ \. " fmt = vim.eval('a:format')\n"
+ \. " timestr = vim.eval('a:string')\n"
+ \. " timestamp = datetime.datetime.strptime(timestr, fmt)\n"
+ \. " timestamp = int(timestamp.timestamp())\n"
+ \. " if timestamp > 2 ** 31:\n"
+ \. " tsabs = abs(timestamp)"
+ \. " return ('{\"_TYPE\": v:msgpack_types.integer,'\n"
+ \. " + '\"_VAL\": [{sign},{v1},{v2},{v3}]}').format(\n"
+ \. " sign=1 if timestamp >= 0 else -1,\n"
+ \. " v1=((tsabs >> 62) & 0x3),\n"
+ \. " v2=((tsabs >> 31) & (2 ** 31 - 1)),\n"
+ \. " v3=(tsabs & (2 ** 31 - 1)))\n"
+ \. " else:\n"
+ \. " return str(timestamp)\n"
+ execute "function s:msgpack_dict_strftime(format, timestamp) abort\n"
+ \. " return py" . suf . "eval('shada_dict_strftime()')\n"
+ \. "endfunction\n"
+ \. "function s:msgpack_dict_strptime(format, string)\n"
+ \. " return eval(py" . suf . "eval('shada_dict_strptime()'))\n"
+ \. "endfunction\n"
+ let s:msgpack_python_type = suf
+ return suf
+ catch
+ continue
+ endtry
+ endfor
+
+ ""
+ " strftime() function for |msgpack-special-dict| values.
+ "
+ " @param[in] format String according to which time should be formatted.
+ " @param[in] timestamp Timestamp (seconds since epoch) to format.
+ "
+ " @return Formatted timestamp.
+ "
+ " @warning Without +python or +python3 this function does not work correctly.
+ " The VimL code contains “reference” implementation which does not
+ " really work because of precision loss.
+ function s:msgpack_dict_strftime(format, timestamp)
+ return msgpack#strftime(a:format, +msgpack#int_dict_to_str(a:timestamp))
+ endfunction
+
+ ""
+ " Function that parses given string according to given format.
+ "
+ " @param[in] format String according to which string was formatted.
+ " @param[in] string Time formatted according to format.
+ "
+ " @return Timestamp.
+ "
+ " @warning Without +python or +python3 this function is able to work only with
+ " 31-bit (32-bit signed) timestamps that have format
+ " `%Y-%m-%dT%H:%M:%S`.
+ function s:msgpack_dict_strptime(format, string)
+ let fmt = '%Y-%m-%dT%H:%M:%S'
+ if a:format isnot# fmt
+ throw 'notimplemented-format:Only ' . fmt . ' format is supported'
+ endif
+ let match = matchlist(a:string,
+ \'\v\C^(\d+)\-(\d+)\-(\d+)T(\d+)\:(\d+)\:(\d+)$')
+ if empty(match)
+ throw 'invalid-string:Given string does not match format ' . a:format
+ endif
+ call map(match, 'str2nr(v:val, 10)')
+ let [year, month, day, hour, minute, second] = match[1:6]
+ " Bisection start and end:
+ "
+ " Start: 365 days in year, 28 days in month, -12 hours tz offset.
+ let bisect_ts_start = (((((year - 1970) * 365
+ \+ (month - 1) * 28
+ \+ (day - 1)) * 24
+ \+ hour - 12) * 60
+ \+ minute) * 60
+ \+ second)
+ if bisect_ts_start < 0
+ let bisect_ts_start = 0
+ endif
+ let start_string = strftime(fmt, bisect_ts_start)
+ if start_string is# a:string
+ return bisect_ts_start
+ endif
+ " End: 366 days in year, 31 day in month, +14 hours tz offset.
+ let bisect_ts_end = (((((year - 1970) * 366
+ \+ (month - 1) * 31
+ \+ (day - 1)) * 24
+ \+ hour + 14) * 60
+ \+ minute) * 60
+ \+ second)
+ let end_string = strftime(fmt, bisect_ts_end)
+ if end_string is# a:string
+ return bisect_ts_end
+ endif
+ if start_string ># end_string
+ throw 'internal-start-gt:Internal error: start > end'
+ endif
+ if start_string is# end_string
+ throw printf('internal-start-eq:Internal error: '
+ \. 'start(%u)==end(%u), but start(%s)!=string(%s)',
+ \bisect_ts_start, bisect_ts_end,
+ \string(start_string), string(a:string))
+ endif
+ if start_string ># a:string
+ throw 'internal-start-string:Internal error: start > string'
+ endif
+ if end_string <# a:string
+ throw 'internal-end-string:Internal error: end < string'
+ endif
+ while 1
+ let bisect_ts_middle = (bisect_ts_start/2) + (bisect_ts_end/2)
+ let middle_string = strftime(fmt, bisect_ts_middle)
+ if a:string is# middle_string
+ return bisect_ts_middle
+ elseif a:string ># middle_string
+ if bisect_ts_middle == bisect_ts_start
+ let bisect_ts_start += 1
+ else
+ let bisect_ts_start = bisect_ts_middle
+ endif
+ else
+ if bisect_ts_middle == bisect_ts_end
+ let bisect_ts_end -= 1
+ else
+ let bisect_ts_end = bisect_ts_middle
+ endif
+ endif
+ if bisect_ts_start >= bisect_ts_end
+ throw 'not-found:Unable to find timestamp'
+ endif
+ endwhile
+ endfunction
+
+ return 0
+endfunction
+
+""
+" Wrapper for strftime() that respects |msgpack-special-dict|. May actually use
+" non-standard strftime() implementations for |msgpack-special-dict| values.
+"
+" @param[in] format Format string.
+" @param[in] timestamp Formatted timestamp.
+function msgpack#strftime(format, timestamp) abort
+ if type(a:timestamp) == type({})
+ call s:msgpack_init_python()
+ return s:msgpack_dict_strftime(a:format, a:timestamp)
+ else
+ return strftime(a:format, a:timestamp)
+ endif
+endfunction
+
+""
+" Parse string according to the format.
+"
+" Requires +python available. If it is not then only supported format is
+" `%Y-%m-%dT%H:%M:%S` because this is the format used by ShaDa plugin. Also in
+" this case bisection will be used (timestamps tried with strftime() up until
+" result matches the string) and only 31-bit (signed 32-bit: with negative
+" timestamps being useless this leaves 31 bits) timestamps will be supported.
+"
+" @param[in] format Time format.
+" @param[in] string Parsed time string. Must match given format.
+"
+" @return Timestamp. Possibly as |msgpack-special-dict|.
+function msgpack#strptime(format, string) abort
+ call s:msgpack_init_python()
+ return s:msgpack_dict_strptime(a:format, a:string)
+endfunction
+
+let s:MSGPACK_HIGHEST_BIT = 1
+let s:MSGPACK_HIGHEST_BIT_NR = 0
+while s:MSGPACK_HIGHEST_BIT * 2 > 0
+ let s:MSGPACK_HIGHEST_BIT = s:MSGPACK_HIGHEST_BIT * 2
+ let s:MSGPACK_HIGHEST_BIT_NR += 1
+endwhile
+
+""
+" Shift given number by given amount of bits
+function s:shift(n, s) abort
+ if a:s == 0
+ return a:n
+ elseif a:s < 0
+ let ret = a:n
+ for _ in range(-a:s)
+ let ret = ret / 2
+ endfor
+ return ret
+ else
+ let ret = a:n
+ for i in range(a:s)
+ let new_ret = ret * 2
+ if new_ret < ret
+ " Overflow: remove highest bit
+ let ret = xor(s:MSGPACK_HIGHEST_BIT, ret) * 2
+ endif
+ let ret = new_ret
+ endfor
+ return ret
+ endif
+endfunction
+
+let s:msgpack_mask_cache = {
+ \s:MSGPACK_HIGHEST_BIT_NR : s:MSGPACK_HIGHEST_BIT - 1}
+
+""
+" Apply a mask where first m bits are ones and other are zeroes to a given
+" number
+function s:mask1(n, m) abort
+ if a:m > s:MSGPACK_HIGHEST_BIT_NR + 1
+ let m = s:MSGPACK_HIGHEST_BIT_NR + 1
+ else
+ let m = a:m
+ endif
+ if !has_key(s:msgpack_mask_cache, m)
+ let p = 0
+ for _ in range(m)
+ let p = p * 2 + 1
+ endfor
+ let s:msgpack_mask_cache[m] = p
+ endif
+ return and(a:n, s:msgpack_mask_cache[m])
+endfunction
+
+""
+" Convert |msgpack-special-dict| that represents integer value to a string. Uses
+" hexadecimal representation starting with 0x because it is the easiest to
+" convert to.
+function msgpack#int_dict_to_str(v) abort
+ let v = a:v._VAL
+ " 64-bit number:
+ " 0000000001111111111222222222233333333334444444444555555555566666
+ " 1234567890123456789012345678901234567890123456789012345678901234
+ " Split in _VAL:
+ " 0000000001111111111222222222233 3333333344444444445555555555666 66
+ " 1234567890123456789012345678901 2345678901234567890123456789012 34
+ " Split by hex digits:
+ " 0000 0000 0111 1111 1112 2222 2222 2333 3333 3334 4444 4444 4555 5555 5556 6666
+ " 1234 5678 9012 3456 7890 1234 5678 9012 3456 7890 1234 5678 9012 3456 7890 1234
+ "
+ " Total split:
+ " _VAL[3] _VAL[2] _VAL[1]
+ " ______________________________________ _______________________________________ __
+ " 0000 0000 0111 1111 1112 2222 2222 233 3 3333 3334 4444 4444 4555 5555 5556 66 66
+ " 1234 5678 9012 3456 7890 1234 5678 901 2 3456 7890 1234 5678 9012 3456 7890 12 34
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^
+ " g4 g3 g2 g1
+ " ********************************** *** * ********************************** ** **
+ " 1 2 3 4 5 6
+ " 1: s:mask1(v[3], 28): first 28 bits of _VAL[3]
+ " 2: s:shift(v[3], -28): last 3 bits of _VAL[3]
+ " 3: s:mask1(v[2], 1): first bit of _VAL[2]
+ " 4: s:mask1(s:shift(v[2], -1), 28): bits 2 .. 29 of _VAL[2]
+ " 5: s:shift(v[2], -29): last 2 bits of _VAL[2]
+ " 6: s:shift(v[1], 2): _VAL[1]
+ let g4 = printf('%07x', s:mask1(v[3], 28))
+ let g3 = printf('%01x', or(s:shift(v[3], -28), s:shift(s:mask1(v[2], 1), 3)))
+ let g2 = printf('%07x', s:mask1(s:shift(v[2], -1), 28))
+ let g1 = printf('%01x', or(s:shift(v[2], -29), s:shift(v[1], 2)))
+ return ((v[0] < 0 ? '-' : '') . '0x' . g1 . g2 . g3 . g4)
+endfunction
+
+""
+" True boolean value.
+let g:msgpack#true = {'_TYPE': v:msgpack_types.boolean, '_VAL': 1}
+lockvar! g:msgpack#true
+
+""
+" False boolean value.
+let g:msgpack#false = {'_TYPE': v:msgpack_types.boolean, '_VAL': 0}
+lockvar! g:msgpack#false
+
+""
+" NIL value.
+let g:msgpack#nil = {'_TYPE': v:msgpack_types.nil, '_VAL': 0}
+lockvar! g:msgpack#nil
+
+""
+" Deduce type of |msgpack-special-dict|.
+"
+" @return zero if given dictionary is not special or name of the key in
+" v:msgpack_types dictionary.
+function msgpack#special_type(v) abort
+ if type(a:v) != type({}) || !has_key(a:v, '_TYPE')
+ return 0
+ endif
+ for [k, v] in items(v:msgpack_types)
+ if a:v._TYPE is v
+ return k
+ endif
+ endfor
+ return 0
+endfunction
+
+""
+" Mapping that maps type() output to type names.
+let s:MSGPACK_STANDARD_TYPES = {
+ \type(0): 'integer',
+ \type(0.0): 'float',
+ \type(''): 'binary',
+ \type([]): 'array',
+ \type({}): 'map',
+\}
+
+""
+" Deduce type of one of items returned by msgpackparse().
+"
+" @return Name of a key in v:msgpack_types.
+function msgpack#type(v) abort
+ let special_type = msgpack#special_type(a:v)
+ if special_type is 0
+ return s:MSGPACK_STANDARD_TYPES[type(a:v)]
+ endif
+ return special_type
+endfunction
+
+""
+" Dump nil value.
+function s:msgpack_dump_nil(v) abort
+ return 'NIL'
+endfunction
+
+""
+" Dump boolean value.
+function s:msgpack_dump_boolean(v) abort
+ return a:v._VAL ? 'TRUE' : 'FALSE'
+endfunction
+
+""
+" Dump integer msgpack value.
+function s:msgpack_dump_integer(v) abort
+ if type(a:v) == type({})
+ return msgpack#int_dict_to_str(a:v)
+ else
+ return string(a:v)
+ endif
+endfunction
+
+""
+" Dump floating-point value.
+function s:msgpack_dump_float(v) abort
+ return string(type(a:v) == type({}) ? a:v._VAL : a:v)
+endfunction
+
+""
+" Dump |msgpack-special-dict| that represents a string. If any additional
+" parameter is given then it dumps binary string.
+function s:msgpack_dump_string(v, ...) abort
+ let ret = [a:0 ? '"' : '="']
+ for v in a:v._VAL
+ call add(
+ \ret,
+ \substitute(
+ \substitute(v, '["\\]', '\\\0', 'g'),
+ \'\n', '\\0', 'g'))
+ call add(ret, '\n')
+ endfor
+ let ret[-1] = '"'
+ return join(ret, '')
+endfunction
+
+""
+" Dump binary string.
+function s:msgpack_dump_binary(v) abort
+ if type(a:v) == type({})
+ return s:msgpack_dump_string(a:v, 1)
+ else
+ return s:msgpack_dump_string({'_VAL': split(a:v, "\n", 1)}, 1)
+ endif
+endfunction
+
+""
+" Dump array value.
+function s:msgpack_dump_array(v) abort
+ let val = type(a:v) == type({}) ? a:v._VAL : a:v
+ return '[' . join(map(val[:], 'msgpack#string(v:val)'), ', ') . ']'
+endfunction
+
+""
+" Dump dictionary value.
+function s:msgpack_dump_map(v) abort
+ let ret = ['{']
+ if msgpack#special_type(a:v) is 0
+ for [k, v] in items(a:v)
+ let ret += [s:msgpack_dump_string({'_VAL': split(k, "\n", 1)}),
+ \': ',
+ \msgpack#string(v),
+ \', ']
+ unlet v
+ endfor
+ if !empty(a:v)
+ call remove(ret, -1)
+ endif
+ else
+ for [k, v] in sort(copy(a:v._VAL))
+ let ret += [msgpack#string(k),
+ \': ',
+ \msgpack#string(v),
+ \', ']
+ unlet k
+ unlet v
+ endfor
+ if !empty(a:v._VAL)
+ call remove(ret, -1)
+ endif
+ endif
+ let ret += ['}']
+ return join(ret, '')
+endfunction
+
+""
+" Dump extension value.
+function s:msgpack_dump_ext(v) abort
+ return printf('+(%i)%s', a:v._VAL[0],
+ \s:msgpack_dump_string({'_VAL': a:v._VAL[1]}, 1))
+endfunction
+
+""
+" Convert msgpack object to a string, like string() function does. Result of the
+" conversion may be passed to msgpack#eval().
+function msgpack#string(v) abort
+ if type(a:v) == type({})
+ let type = msgpack#special_type(a:v)
+ if type is 0
+ let type = 'map'
+ endif
+ else
+ let type = get(s:MSGPACK_STANDARD_TYPES, type(a:v), 0)
+ if type is 0
+ throw printf('msgpack:invtype: Unable to convert value %s', string(a:v))
+ endif
+ endif
+ return s:msgpack_dump_{type}(a:v)
+endfunction
+
+""
+" Copy msgpack object like deepcopy() does, but leave types intact
+function msgpack#deepcopy(obj) abort
+ if type(a:obj) == type([])
+ return map(copy(a:obj), 'msgpack#deepcopy(v:val)')
+ elseif type(a:obj) == type({})
+ let special_type = msgpack#special_type(a:obj)
+ if special_type is 0
+ return map(copy(a:obj), 'msgpack#deepcopy(v:val)')
+ else
+ return {
+ \'_TYPE': v:msgpack_types[special_type],
+ \'_VAL': msgpack#deepcopy(a:obj._VAL)
+ \}
+ endif
+ else
+ return copy(a:obj)
+ endif
+endfunction
+
+""
+" Convert an escaped character to needed value
+function s:msgpack_eval_str_sub(ch) abort
+ if a:ch is# 'n'
+ return '", "'
+ elseif a:ch is# '0'
+ return '\n'
+ else
+ return '\' . a:ch
+ endif
+endfunction
+
+let s:MSGPACK_SPECIAL_OBJECTS = {
+ \'NIL': '{''_TYPE'': v:msgpack_types.nil, ''_VAL'': 0}',
+ \'TRUE': '{''_TYPE'': v:msgpack_types.boolean, ''_VAL'': 1}',
+ \'FALSE': '{''_TYPE'': v:msgpack_types.boolean, ''_VAL'': 0}',
+ \'nan': '(-(1.0/0.0-1.0/0.0))',
+ \'inf': '(1.0/0.0)',
+\}
+
+""
+" Convert msgpack object dumped by msgpack#string() to a VimL object suitable
+" for msgpackdump().
+"
+" @param[in] s String to evaluate.
+" @param[in] special_objs Additional special objects, in the same format as
+" s:MSGPACK_SPECIAL_OBJECTS.
+"
+" @return Any value that msgpackparse() may return.
+function msgpack#eval(s, special_objs) abort
+ let s = a:s
+ let expr = []
+ let context = []
+ while !empty(s)
+ let s = substitute(s, '^\s*', '', '')
+ if s[0] =~# '\v^\h$'
+ let name = matchstr(s, '\v\C^\w+')
+ if has_key(s:MSGPACK_SPECIAL_OBJECTS, name)
+ call add(expr, s:MSGPACK_SPECIAL_OBJECTS[name])
+ elseif has_key(a:special_objs, name)
+ call add(expr, a:special_objs[name])
+ else
+ throw 'name-unknown:Unknown name ' . name . ': ' . s
+ endif
+ let s = s[len(name):]
+ elseif (s[0] is# '-' && s[1] =~# '\v^\d$') || s[0] =~# '\v^\d$'
+ let sign = 1
+ if s[0] is# '-'
+ let s = s[1:]
+ let sign = -1
+ endif
+ if s[0:1] is# '0x'
+ " See comment in msgpack#int_dict_to_str().
+ let s = s[2:]
+ let hexnum = matchstr(s, '\v\C^\x+')
+ if empty(hexnum)
+ throw '0x-empty:Must have number after 0x: ' . s
+ elseif len(hexnum) > 16
+ throw '0x-long:Must have at most 16 hex digits: ' . s
+ endif
+ let s = s[len(hexnum):]
+ let hexnum = repeat('0', 16 - len(hexnum)) . hexnum
+ let g1 = str2nr(hexnum[0], 16)
+ let g2 = str2nr(hexnum[1:7], 16)
+ let g3 = str2nr(hexnum[8], 16)
+ let g4 = str2nr(hexnum[9:15], 16)
+ let v1 = s:shift(g1, -2)
+ let v2 = or(or(s:shift(s:mask1(g1, 2), 29), s:shift(g2, 1)),
+ \s:mask1(s:shift(g3, -3), 1))
+ let v3 = or(s:shift(s:mask1(g3, 3), 28), g4)
+ call add(expr, printf('{''_TYPE'': v:msgpack_types.integer, '.
+ \'''_VAL'': [%i, %u, %u, %u]}',
+ \sign, v1, v2, v3))
+ else
+ let num = matchstr(s, '\v\C^\d+')
+ let s = s[len(num):]
+ if sign == -1
+ call add(expr, '-')
+ endif
+ call add(expr, num)
+ if s[0] is# '.'
+ let dec = matchstr(s, '\v\C^\.\d+%(e[+-]?\d+)?')
+ if empty(dec)
+ throw '0.-nodigits:Decimal dot must be followed by digit(s): ' . s
+ endif
+ let s = s[len(dec):]
+ call add(expr, dec)
+ endif
+ endif
+ elseif s =~# '-\?\%(inf\|nan\)'
+ if s[0] is# '-'
+ call add(expr, '-')
+ let s = s[1:]
+ endif
+ call add(expr, s:MSGPACK_SPECIAL_OBJECTS[s[0:2]])
+ let s = s[3:]
+ elseif stridx('="+', s[0]) != -1
+ let match = matchlist(s, '\v\C^(\=|\+\((\-?\d+)\)|)(\"%(\\.|[^\\"]+)*\")')
+ if empty(match)
+ throw '"-invalid:Invalid string: ' . s
+ endif
+ call add(expr, '{''_TYPE'': v:msgpack_types.')
+ if empty(match[1])
+ call add(expr, 'binary')
+ elseif match[1] is# '='
+ call add(expr, 'string')
+ else
+ call add(expr, 'ext')
+ endif
+ call add(expr, ', ''_VAL'': [')
+ if match[1][0] is# '+'
+ call add(expr, match[2] . ', [')
+ endif
+ call add(expr, substitute(match[3], '\v\C\\(.)',
+ \'\=s:msgpack_eval_str_sub(submatch(1))', 'g'))
+ if match[1][0] is# '+'
+ call add(expr, ']')
+ endif
+ call add(expr, ']}')
+ let s = s[len(match[0]):]
+ elseif s[0] is# '{'
+ call add(context, 'map')
+ call add(expr, '{''_TYPE'': v:msgpack_types.map, ''_VAL'': [')
+ call add(expr, '[')
+ let s = s[1:]
+ elseif s[0] is# '['
+ call add(context, 'array')
+ call add(expr, '[')
+ let s = s[1:]
+ elseif s[0] is# ':'
+ call add(expr, ',')
+ let s = s[1:]
+ elseif s[0] is# ','
+ if context[-1] is# 'array'
+ call add(expr, ',')
+ else
+ call add(expr, '], [')
+ endif
+ let s = s[1:]
+ elseif s[0] is# ']'
+ call remove(context, -1)
+ call add(expr, ']')
+ let s = s[1:]
+ elseif s[0] is# '}'
+ call remove(context, -1)
+ if expr[-1] is# "\x5B"
+ call remove(expr, -1)
+ else
+ call add(expr, ']')
+ endif
+ call add(expr, ']}')
+ let s = s[1:]
+ elseif s[0] is# ''''
+ let char = matchstr(s, '\m\C^''\zs.\ze''')
+ if empty(char)
+ throw 'char-invalid:Invalid integer character literal format: ' . s
+ endif
+ call add(expr, char2nr(char))
+ let s = s[len(char) + 2:]
+ else
+ throw 'unknown:Invalid non-space character: ' . s
+ endif
+ endwhile
+ if empty(expr)
+ throw 'empty:Parsed string is empty'
+ endif
+ return eval(join(expr, ''))
+endfunction
+
+""
+" Check whether two msgpack values are equal
+function msgpack#equal(a, b)
+ let atype = msgpack#type(a:a)
+ let btype = msgpack#type(a:b)
+ if atype isnot# btype
+ return 0
+ endif
+ let aspecial = msgpack#special_type(a:a)
+ let bspecial = msgpack#special_type(a:b)
+ if aspecial is# bspecial
+ if aspecial is# 0
+ if type(a:a) == type({})
+ if len(a:a) != len(a:b)
+ return 0
+ endif
+ if !empty(filter(keys(a:a), '!has_key(a:b, v:val)'))
+ return 0
+ endif
+ for [k, v] in items(a:a)
+ if !msgpack#equal(v, a:b[k])
+ return 0
+ endif
+ unlet v
+ endfor
+ return 1
+ elseif type(a:a) == type([])
+ if len(a:a) != len(a:b)
+ return 0
+ endif
+ let i = 0
+ for asubval in a:a
+ if !msgpack#equal(asubval, a:b[i])
+ return 0
+ endif
+ let i += 1
+ unlet asubval
+ endfor
+ return 1
+ elseif type(a:a) == type(0.0)
+ return (a:a == a:a ? a:a == a:b : string(a:a) ==# string(a:b))
+ else
+ return a:a ==# a:b
+ endif
+ elseif aspecial is# 'map' || aspecial is# 'array'
+ if len(a:a._VAL) != len(a:b._VAL)
+ return 0
+ endif
+ let alist = aspecial is# 'map' ? sort(copy(a:a._VAL)) : a:a._VAL
+ let blist = bspecial is# 'map' ? sort(copy(a:b._VAL)) : a:b._VAL
+ let i = 0
+ for asubval in alist
+ let bsubval = blist[i]
+ if aspecial is# 'map'
+ if !(msgpack#equal(asubval[0], bsubval[0])
+ \&& msgpack#equal(asubval[1], bsubval[1]))
+ return 0
+ endif
+ else
+ if !msgpack#equal(asubval, bsubval)
+ return 0
+ endif
+ endif
+ let i += 1
+ unlet asubval
+ unlet bsubval
+ endfor
+ return 1
+ elseif aspecial is# 'nil'
+ return 1
+ elseif aspecial is# 'float'
+ return (a:a._VAL == a:a._VAL
+ \? (a:a._VAL == a:b._VAL)
+ \: (string(a:a._VAL) ==# string(a:b._VAL)))
+ else
+ return a:a._VAL ==# a:b._VAL
+ endif
+ else
+ if atype is# 'array'
+ let a = aspecial is 0 ? a:a : a:a._VAL
+ let b = bspecial is 0 ? a:b : a:b._VAL
+ return msgpack#equal(a, b)
+ elseif atype is# 'binary'
+ let a = (aspecial is 0 ? split(a:a, "\n", 1) : a:a._VAL)
+ let b = (bspecial is 0 ? split(a:b, "\n", 1) : a:b._VAL)
+ return a ==# b
+ elseif atype is# 'map'
+ if aspecial is 0
+ let akeys = copy(a:a)
+ if len(a:b._VAL) != len(akeys)
+ return 0
+ endif
+ for [k, v] in a:b._VAL
+ if msgpack#type(k) isnot# 'string'
+ " Non-special mapping cannot have non-string keys
+ return 0
+ endif
+ if (empty(k._VAL)
+ \|| k._VAL ==# [""]
+ \|| !empty(filter(copy(k._VAL), 'stridx(v:val, "\n") != -1')))
+ " Non-special mapping cannot have zero byte in key or an empty key
+ return 0
+ endif
+ let kstr = join(k._VAL, "\n")
+ if !has_key(akeys, kstr)
+ " Protects from both missing and duplicate keys
+ return 0
+ endif
+ if !msgpack#equal(akeys[kstr], v)
+ return 0
+ endif
+ call remove(akeys, kstr)
+ unlet k
+ unlet v
+ endfor
+ return 1
+ else
+ return msgpack#equal(a:b, a:a)
+ endif
+ elseif atype is# 'float'
+ let a = aspecial is 0 ? a:a : a:a._VAL
+ let b = bspecial is 0 ? a:b : a:b._VAL
+ return (a == a ? a == b : string(a) ==# string(b))
+ elseif atype is# 'integer'
+ if aspecial is 0
+ let sign = a:a >= 0 ? 1 : -1
+ let a = sign * a:a
+ let v1 = s:mask1(s:shift(a, -62), 2)
+ let v2 = s:mask1(s:shift(a, -31), 31)
+ let v3 = s:mask1(a, 31)
+ return [sign, v1, v2, v3] == a:b._VAL
+ else
+ return msgpack#equal(a:b, a:a)
+ endif
+ else
+ throw printf('internal-invalid-type: %s == %s, but special %s /= %s',
+ \atype, btype, aspecial, bspecial)
+ endif
+ endif
+endfunction
diff --git a/runtime/autoload/provider/python.vim b/runtime/autoload/provider/python.vim
index d4a509864f..b769895357 100644
--- a/runtime/autoload/provider/python.vim
+++ b/runtime/autoload/provider/python.vim
@@ -46,7 +46,7 @@ function! provider#python#Call(method, args)
echohl WarningMsg
echomsg v:exception
echohl None
- finish
+ return
endtry
endif
return call(s:rpcrequest, insert(insert(a:args, 'python_'.a:method), s:host))
diff --git a/runtime/autoload/provider/python3.vim b/runtime/autoload/provider/python3.vim
index f469bf55aa..2952f76b40 100644
--- a/runtime/autoload/provider/python3.vim
+++ b/runtime/autoload/provider/python3.vim
@@ -46,7 +46,7 @@ function! provider#python3#Call(method, args)
echohl WarningMsg
echomsg v:exception
echohl None
- finish
+ return
endtry
endif
return call(s:rpcrequest, insert(insert(a:args, 'python_'.a:method), s:host))
diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim
index afbf136861..d04dea180c 100644
--- a/runtime/autoload/remote/host.vim
+++ b/runtime/autoload/remote/host.vim
@@ -168,10 +168,15 @@ function! s:UpdateRemotePlugins()
let hosts = keys(s:hosts)
for host in hosts
if has_key(s:plugin_patterns, host)
- let commands = commands
- \ + ['" '.host.' plugins']
- \ + s:RegistrationCommands(host)
- \ + ['', '']
+ try
+ let commands +=
+ \ ['" '.host.' plugins']
+ \ + s:RegistrationCommands(host)
+ \ + ['', '']
+ catch
+ echomsg v:throwpoint
+ echomsg v:exception
+ endtry
endif
endfor
call writefile(commands, s:remote_plugins_manifest)
@@ -212,9 +217,11 @@ function! s:RequirePythonHost(host)
return channel_id
endif
catch
+ echomsg v:throwpoint
echomsg v:exception
endtry
- throw 'Failed to load Python host. You can try to see what happened '.
+ throw 'Failed to load '. a:host.orig_name . ' host. '.
+ \ 'You can try to see what happened '.
\ 'by starting Neovim with the environment variable '.
\ '$NVIM_PYTHON_LOG_FILE set to a file and opening '.
\ 'the generated log file. Also, the host stderr will be available '.
diff --git a/runtime/autoload/shada.vim b/runtime/autoload/shada.vim
new file mode 100644
index 0000000000..9be85b6f2e
--- /dev/null
+++ b/runtime/autoload/shada.vim
@@ -0,0 +1,696 @@
+if exists('g:loaded_shada_autoload')
+ finish
+endif
+let g:loaded_shada_autoload = 1
+
+""
+" If true keep the old header entry when editing existing ShaDa file.
+"
+" Old header entry will be kept only if it is listed in the opened file. To
+" remove old header entry despite of the setting just remove it from the
+" listing. Setting it to false makes plugin ignore all header entries. Defaults
+" to 1.
+let g:shada#keep_old_header = get(g:, 'shada#keep_old_header', 1)
+
+""
+" If true then first entry will be plugin’s own header entry.
+let g:shada#add_own_header = get(g:, 'shada#add_own_header', 1)
+
+""
+" Dictionary that maps ShaDa types to their names.
+let s:SHADA_ENTRY_NAMES = {
+ \1: 'header',
+ \2: 'search_pattern',
+ \3: 'replacement_string',
+ \4: 'history_entry',
+ \5: 'register',
+ \6: 'variable',
+ \7: 'global_mark',
+ \8: 'jump',
+ \9: 'buffer_list',
+ \10: 'local_mark',
+ \11: 'change',
+\}
+
+""
+" Dictionary that maps ShaDa names to corresponding types
+let s:SHADA_ENTRY_TYPES = {}
+call map(copy(s:SHADA_ENTRY_NAMES),
+ \'extend(s:SHADA_ENTRY_TYPES, {v:val : +v:key})')
+
+""
+" Map that maps entry names to lists of keys that can be used by this entry.
+" Only contains data for entries which are represented as mappings, except for
+" the header.
+let s:SHADA_MAP_ENTRIES = {
+ \'search_pattern': ['sp', 'sh', 'ss', 'sb', 'sm', 'sc', 'sl', 'se', 'so',
+ \ 'su'],
+ \'register': ['n', 'rc', 'rw', 'rt'],
+ \'global_mark': ['n', 'f', 'l', 'c'],
+ \'local_mark': ['f', 'n', 'l', 'c'],
+ \'jump': ['f', 'l', 'c'],
+ \'change': ['f', 'l', 'c'],
+ \'header': [],
+\}
+
+""
+" Like one of the values from s:SHADA_MAP_ENTRIES, but for a single buffer in
+" buffer list entry.
+let s:SHADA_BUFFER_LIST_KEYS = ['f', 'l', 'c']
+
+""
+" List of possible history types. Maps integer values that represent history
+" types to human-readable names.
+let s:SHADA_HISTORY_TYPES = ['command', 'search', 'expression', 'input', 'debug']
+
+""
+" Map that maps entry names to their descriptions. Only for entries which have
+" list as a data type. Description is a list of lists where each entry has item
+" description and item type.
+let s:SHADA_FIXED_ARRAY_ENTRIES = {
+ \'replacement_string': [[':s replacement string', 'bin']],
+ \'history_entry': [
+ \['history type', 'histtype'],
+ \['contents', 'bin'],
+ \['separator', 'intchar'],
+ \],
+ \'variable': [['name', 'bin'], ['value', 'any']],
+\}
+
+""
+" Dictionary that maps enum names to dictionary with enum values. Dictionary
+" with enum values maps enum human-readable names to corresponding values. Enums
+" are used as type names in s:SHADA_FIXED_ARRAY_ENTRIES and
+" s:SHADA_STANDARD_KEYS.
+let s:SHADA_ENUMS = {
+ \'histtype': {
+ \'CMD': 0,
+ \'SEARCH': 1,
+ \'EXPR': 2,
+ \'INPUT': 3,
+ \'DEBUG': 4,
+ \},
+ \'regtype': {
+ \'CHARACTERWISE': 0,
+ \'LINEWISE': 1,
+ \'BLOCKWISE': 2,
+ \}
+\}
+
+""
+" Second argument to msgpack#eval.
+let s:SHADA_SPECIAL_OBJS = {}
+call map(values(s:SHADA_ENUMS),
+ \'extend(s:SHADA_SPECIAL_OBJS, map(copy(v:val), "string(v:val)"))')
+
+""
+" Like s:SHADA_ENUMS, but inner dictionary maps values to names and not names to
+" values.
+let s:SHADA_REV_ENUMS = map(copy(s:SHADA_ENUMS), '{}')
+call map(copy(s:SHADA_ENUMS),
+ \'map(copy(v:val), '
+ \. '"extend(s:SHADA_REV_ENUMS[" . string(v:key) . "], '
+ \. '{v:val : v:key})")')
+
+""
+" Maximum length of ShaDa entry name. Used to arrange entries to the table.
+let s:SHADA_MAX_ENTRY_LENGTH = max(
+ \map(values(s:SHADA_ENTRY_NAMES), 'len(v:val)')
+ \+ [len('unknown (0x)') + 16])
+
+""
+" Object that marks required value.
+let s:SHADA_REQUIRED = []
+
+""
+" Dictionary that maps default key names to their description. Description is
+" a list that contains human-readable hint, key type and default value.
+let s:SHADA_STANDARD_KEYS = {
+ \'sm': ['magic value', 'boolean', g:msgpack#true],
+ \'sc': ['smartcase value', 'boolean', g:msgpack#false],
+ \'sl': ['has line offset', 'boolean', g:msgpack#false],
+ \'se': ['place cursor at end', 'boolean', g:msgpack#false],
+ \'so': ['offset value', 'integer', 0],
+ \'su': ['is last used', 'boolean', g:msgpack#true],
+ \'ss': ['is :s pattern', 'boolean', g:msgpack#false],
+ \'sh': ['v:hlsearch value', 'boolean', g:msgpack#false],
+ \'sp': ['pattern', 'bin', s:SHADA_REQUIRED],
+ \'sb': ['search backward', 'boolean', g:msgpack#false],
+ \'rt': ['type', 'regtype', s:SHADA_ENUMS.regtype.CHARACTERWISE],
+ \'rw': ['block width', 'uint', 0],
+ \'rc': ['contents', 'binarray', s:SHADA_REQUIRED],
+ \'n': ['name', 'intchar', char2nr('"')],
+ \'l': ['line number', 'uint', 1],
+ \'c': ['column', 'uint', 0],
+ \'f': ['file name', 'bin', s:SHADA_REQUIRED],
+\}
+
+""
+" Set of entry types containing entries which require `n` key.
+let s:SHADA_REQUIRES_NAME = {'local_mark': 1, 'global_mark': 1, 'register': 1}
+
+""
+" Maximum width of human-readable hint. Used to arrange data in table.
+let s:SHADA_MAX_HINT_WIDTH = max(map(values(s:SHADA_STANDARD_KEYS),
+ \'len(v:val[0])'))
+
+""
+" Default mark name for the cases when it makes sense (i.e. for local marks).
+let s:SHADA_DEFAULT_MARK_NAME = '"'
+
+""
+" Mapping that maps timestamps represented using msgpack#string to strftime
+" output. Used by s:shada_strftime.
+let s:shada_strftime_cache = {}
+
+""
+" Mapping that maps strftime output from s:shada_strftime to timestamps.
+let s:shada_strptime_cache = {}
+
+""
+" Time format used for displaying ShaDa files.
+let s:SHADA_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S'
+
+""
+" Wrapper around msgpack#strftime that caches its output.
+"
+" Format is hardcoded to s:SHADA_TIME_FORMAT.
+function s:shada_strftime(timestamp) abort
+ let key = msgpack#string(a:timestamp)
+ if has_key(s:shada_strftime_cache, key)
+ return s:shada_strftime_cache[key]
+ endif
+ let val = msgpack#strftime(s:SHADA_TIME_FORMAT, a:timestamp)
+ let s:shada_strftime_cache[key] = val
+ let s:shada_strptime_cache[val] = a:timestamp
+ return val
+endfunction
+
+""
+" Wrapper around msgpack#strftime that uses cache created by s:shada_strftime().
+"
+" Also caches its own results. Format is hardcoded to s:SHADA_TIME_FORMAT.
+function s:shada_strptime(string) abort
+ if has_key(s:shada_strptime_cache, a:string)
+ return s:shada_strptime_cache[a:string]
+ endif
+ let ts = msgpack#strptime(s:SHADA_TIME_FORMAT, a:string)
+ let s:shada_strptime_cache[a:string] = ts
+ return ts
+endfunction
+
+""
+" Check whether given value matches given type.
+"
+" @return Zero if value matches, error message string if it does not.
+function s:shada_check_type(type, val) abort
+ let type = msgpack#type(a:val)
+ if type is# a:type
+ return 0
+ endif
+ if has_key(s:SHADA_ENUMS, a:type)
+ let msg = s:shada_check_type('uint', a:val)
+ if msg isnot 0
+ return msg
+ endif
+ if !has_key(s:SHADA_REV_ENUMS[a:type], a:val)
+ let evals_msg = join(map(sort(items(s:SHADA_REV_ENUMS[a:type])),
+ \'v:val[0] . " (" . v:val[1] . ")"'), ', ')
+ return 'Unexpected enum value: expected one of ' . evals_msg
+ endif
+ return 0
+ elseif a:type is# 'uint'
+ if type isnot# 'integer'
+ return 'Expected integer'
+ endif
+ if !(type(a:val) == type({}) ? a:val._VAL[0] == 1 : a:val >= 0)
+ return 'Value is negative'
+ endif
+ return 0
+ elseif a:type is# 'bin'
+ " Binary string without zero bytes
+ if type isnot# 'binary'
+ return 'Expected binary string'
+ elseif (type(a:val) == type({})
+ \&& !empty(filter(copy(a:val._VAL), 'stridx(v:val, "\n") != -1')))
+ return 'Expected no NUL bytes'
+ endif
+ return 0
+ elseif a:type is# 'intchar'
+ let msg = s:shada_check_type('uint', a:val)
+ if msg isnot# 0
+ return msg
+ endif
+ if a:val > 0 || a:val < 1
+ endif
+ return 0
+ elseif a:type is# 'binarray'
+ if type isnot# 'array'
+ return 'Expected array value'
+ elseif !empty(filter(copy(type(a:val) == type({}) ? a:val._VAL : a:val),
+ \'msgpack#type(v:val) isnot# "binary"'))
+ return 'Expected array of binary strings'
+ else
+ for element in (type(a:val) == type({}) ? a:val._VAL : a:val)
+ if (type(element) == type({})
+ \&& !empty(filter(copy(element._VAL), 'stridx(v:val, "\n") != -1')))
+ return 'Expected no NUL bytes'
+ endif
+ unlet element
+ endfor
+ endif
+ return 0
+ elseif a:type is# 'boolean'
+ return 'Expected boolean'
+ elseif a:type is# 'integer'
+ return 'Expected integer'
+ elseif a:type is# 'any'
+ return 0
+ endif
+ return 'Internal error: unknown type ' . a:type
+endfunction
+
+""
+" Convert msgpack mapping object to a list of strings for
+" s:shada_convert_entry().
+"
+" @param[in] map Mapping to convert.
+" @param[in] default_keys List of keys which have default value in this
+" mapping.
+" @param[in] name Name of the converted entry.
+function s:shada_convert_map(map, default_keys, name) abort
+ let ret = []
+ let keys = copy(a:default_keys)
+ call map(sort(keys(a:map)), 'index(keys, v:val) == -1 ? add(keys, v:val) : 0')
+ let descriptions = map(copy(keys),
+ \'get(s:SHADA_STANDARD_KEYS, v:val, ["", 0, 0])')
+ let max_key_len = max(map(copy(keys), 'len(v:val)'))
+ let max_desc_len = max(map(copy(descriptions),
+ \'v:val[0] is 0 ? 0 : len(v:val[0])'))
+ if max_key_len < len('Key')
+ let max_key_len = len('Key')
+ endif
+ let key_header = 'Key' . repeat('_', max_key_len - len('Key'))
+ if max_desc_len == 0
+ call add(ret, printf(' %% %s %s', key_header, 'Value'))
+ else
+ if max_desc_len < len('Description')
+ let max_desc_len = len('Description')
+ endif
+ let desc_header = ('Description'
+ \. repeat('_', max_desc_len - len('Description')))
+ call add(ret, printf(' %% %s %s %s', key_header, desc_header, 'Value'))
+ endif
+ let i = 0
+ for key in keys
+ let [description, type, default] = descriptions[i]
+ if a:name isnot# 'local_mark' && key is# 'n'
+ unlet default
+ let default = s:SHADA_REQUIRED
+ endif
+ let value = get(a:map, key, default)
+ if (key is# 'n' && !has_key(s:SHADA_REQUIRES_NAME, a:name)
+ \&& value is# s:SHADA_REQUIRED)
+ " Do nothing
+ elseif value is s:SHADA_REQUIRED
+ call add(ret, ' # Required key missing: ' . key)
+ elseif max_desc_len == 0
+ call add(ret, printf(' + %-*s %s',
+ \max_key_len, key,
+ \msgpack#string(value)))
+ else
+ if type isnot 0 && value isnot# default
+ let msg = s:shada_check_type(type, value)
+ if msg isnot 0
+ call add(ret, ' # ' . msg)
+ endif
+ endif
+ let strval = s:shada_string(type, value)
+ if msgpack#type(value) is# 'array' && msg is 0
+ let shift = 2 + 2 + max_key_len + 2 + max_desc_len + 2
+ " Value: 1 2 3 4 5 6:
+ " " + Key Description Value"
+ " 1122333445555555555566
+ if shift + strdisplaywidth(strval, shift) > 80
+ let strval = '@'
+ endif
+ endif
+ call add(ret, printf(' + %-*s %-*s %s',
+ \max_key_len, key,
+ \max_desc_len, description,
+ \strval))
+ if strval is '@'
+ for v in value
+ call add(ret, printf(' | - %s', msgpack#string(v)))
+ unlet v
+ endfor
+ endif
+ endif
+ let i += 1
+ unlet value
+ unlet default
+ endfor
+ return ret
+endfunction
+
+""
+" Wrapper around msgpack#string() which may return string from s:SHADA_REV_ENUMS
+function s:shada_string(type, v) abort
+ if (has_key(s:SHADA_ENUMS, a:type) && type(a:v) == type(0)
+ \&& has_key(s:SHADA_REV_ENUMS[a:type], a:v))
+ return s:SHADA_REV_ENUMS[a:type][a:v]
+ elseif (a:type is# 'intchar' && type(a:v) == type(0)
+ \&& strtrans(nr2char(a:v)) is# nr2char(a:v))
+ return "'" . nr2char(a:v) . "'"
+ else
+ return msgpack#string(a:v)
+ endif
+endfunction
+
+""
+" Evaluate string obtained by s:shada_string().
+function s:shada_eval(s) abort
+ return msgpack#eval(a:s, s:SHADA_SPECIAL_OBJS)
+endfunction
+
+""
+" Convert one ShaDa entry to a list of strings suitable for setline().
+"
+" Returned format looks like this:
+"
+" TODO
+function s:shada_convert_entry(entry) abort
+ if type(a:entry.type) == type({})
+ " |msgpack-special-dict| may only be used if value does not fit into the
+ " default integer type. All known entry types do fit, so it is definitely
+ " unknown entry.
+ let name = 'unknown_(' . msgpack#int_dict_to_str(a:entry.type) . ')'
+ else
+ let name = get(s:SHADA_ENTRY_NAMES, a:entry.type, 0)
+ if name is 0
+ let name = printf('unknown_(0x%x)', a:entry.type)
+ endif
+ endif
+ let title = toupper(name[0]) . tr(name[1:], '_', ' ')
+ let header = printf('%s with timestamp %s:', title,
+ \s:shada_strftime(a:entry.timestamp))
+ let ret = [header]
+ if name[:8] is# 'unknown_(' && name[-1:] is# ')'
+ call add(ret, ' = ' . msgpack#string(a:entry.data))
+ elseif has_key(s:SHADA_FIXED_ARRAY_ENTRIES, name)
+ if type(a:entry.data) != type([])
+ call add(ret, printf(' # Unexpected type: %s instead of array',
+ \msgpack#type(a:entry.data)))
+ call add(ret, ' = ' . msgpack#string(a:entry.data))
+ return ret
+ endif
+ let i = 0
+ let max_desc_len = max(map(copy(s:SHADA_FIXED_ARRAY_ENTRIES[name]),
+ \'len(v:val[0])'))
+ if max_desc_len < len('Description')
+ let max_desc_len = len('Description')
+ endif
+ let desc_header = ('Description'
+ \. repeat('_', max_desc_len - len('Description')))
+ call add(ret, printf(' @ %s %s', desc_header, 'Value'))
+ for value in a:entry.data
+ let [desc, type] = get(s:SHADA_FIXED_ARRAY_ENTRIES[name], i, ['', 0])
+ if (i == 2 && name is# 'history_entry'
+ \&& a:entry.data[0] isnot# s:SHADA_ENUMS.histtype.SEARCH)
+ let [desc, type] = ['', 0]
+ endif
+ if type isnot 0
+ let msg = s:shada_check_type(type, value)
+ if msg isnot 0
+ call add(ret, ' # ' . msg)
+ endif
+ endif
+ call add(ret, printf(' - %-*s %s', max_desc_len, desc,
+ \s:shada_string(type, value)))
+ let i += 1
+ unlet value
+ endfor
+ if (len(a:entry.data) < len(s:SHADA_FIXED_ARRAY_ENTRIES[name])
+ \&& !(name is# 'history_entry'
+ \&& len(a:entry.data) == 2
+ \&& a:entry.data[0] isnot# s:SHADA_ENUMS.histtype.SEARCH))
+ call add(ret, ' # Expected more elements in list')
+ endif
+ elseif has_key(s:SHADA_MAP_ENTRIES, name)
+ if type(a:entry.data) != type({})
+ call add(ret, printf(' # Unexpected type: %s instead of map',
+ \msgpack#type(a:entry.data)))
+ call add(ret, ' = ' . msgpack#string(a:entry.data))
+ return ret
+ endif
+ if msgpack#special_type(a:entry.data) isnot 0
+ call add(ret, ' # Entry is a special dict which is unexpected')
+ call add(ret, ' = ' . msgpack#string(a:entry.data))
+ return ret
+ endif
+ let ret += s:shada_convert_map(a:entry.data, s:SHADA_MAP_ENTRIES[name],
+ \name)
+ elseif name is# 'buffer_list'
+ if type(a:entry.data) != type([])
+ call add(ret, printf(' # Unexpected type: %s instead of array',
+ \msgpack#type(a:entry.data)))
+ call add(ret, ' = ' . msgpack#string(a:entry.data))
+ return ret
+ elseif !empty(filter(copy(a:entry.data),
+ \'type(v:val) != type({}) '
+ \. '|| msgpack#special_type(v:val) isnot 0'))
+ call add(ret, ' # Expected array of maps')
+ call add(ret, ' = ' . msgpack#string(a:entry.data))
+ return ret
+ endif
+ for bufdef in a:entry.data
+ if bufdef isnot a:entry.data[0]
+ call add(ret, '')
+ endif
+ let ret += s:shada_convert_map(bufdef, s:SHADA_BUFFER_LIST_KEYS, name)
+ endfor
+ else
+ throw 'internal-unknown-type:Internal error: unknown type name: ' . name
+ endif
+ return ret
+endfunction
+
+""
+" Order of msgpack objects in one ShaDa entry. Each item in the list is name of
+" the key in dictionaries returned by shada#read().
+let s:SHADA_ENTRY_OBJECT_SEQUENCE = ['type', 'timestamp', 'length', 'data']
+
+""
+" Convert list returned by msgpackparse() to a list of ShaDa objects
+"
+" @param[in] mpack List of VimL objects returned by msgpackparse().
+"
+" @return List of dictionaries with keys type, timestamp, length and data. Each
+" dictionary describes one ShaDa entry.
+function shada#mpack_to_sd(mpack) abort
+ let ret = []
+ let i = 0
+ for element in a:mpack
+ let key = s:SHADA_ENTRY_OBJECT_SEQUENCE[
+ \i % len(s:SHADA_ENTRY_OBJECT_SEQUENCE)]
+ if key is# 'type'
+ call add(ret, {})
+ endif
+ let ret[-1][key] = element
+ if key isnot# 'data'
+ if !msgpack#is_uint(element)
+ throw printf('not-uint:Entry %i has %s element '.
+ \'which is not an unsigned integer',
+ \len(ret), key)
+ endif
+ if key is# 'type' && msgpack#equal(element, 0)
+ throw printf('zero-uint:Entry %i has %s element '.
+ \'which is zero',
+ \len(ret), key)
+ endif
+ endif
+ let i += 1
+ unlet element
+ endfor
+ return ret
+endfunction
+
+""
+" Convert read ShaDa file to a list of lines suitable for setline()
+"
+" @param[in] shada List of ShaDa entries like returned by shada#mpack_to_sd().
+"
+" @return List of strings suitable for setline()-like functions.
+function shada#sd_to_strings(shada) abort
+ let ret = []
+ for entry in a:shada
+ let ret += s:shada_convert_entry(entry)
+ endfor
+ return ret
+endfunction
+
+""
+" Convert a readfile()-like list of strings to a list of lines suitable for
+" setline().
+"
+" @param[in] binstrings List of strings to convert.
+"
+" @return List of lines.
+function shada#get_strings(binstrings) abort
+ return shada#sd_to_strings(shada#mpack_to_sd(msgpackparse(a:binstrings)))
+endfunction
+
+""
+" Convert s:shada_convert_entry() output to original entry.
+function s:shada_convert_strings(strings) abort
+ let strings = copy(a:strings)
+ let match = matchlist(
+ \strings[0],
+ \'\v\C^(.{-})\m with timestamp \(\d\{4}-\d\d-\d\dT\d\d:\d\d:\d\d\):$')
+ if empty(match)
+ throw 'invalid-header:Header has invalid format: ' . strings[0]
+ endif
+ call remove(strings, 0)
+ let title = match[1]
+ let name = tolower(title[0]) . tr(title[1:], ' ', '_')
+ let ret = {}
+ let empty_default = g:msgpack#nil
+ if name[:8] is# 'unknown_(' && name[-1:] is# ')'
+ let ret.type = +name[9:-2]
+ elseif has_key(s:SHADA_ENTRY_TYPES, name)
+ let ret.type = s:SHADA_ENTRY_TYPES[name]
+ if has_key(s:SHADA_MAP_ENTRIES, name)
+ unlet empty_default
+ let empty_default = {}
+ elseif has_key(s:SHADA_FIXED_ARRAY_ENTRIES, name) || name is# 'buffer_list'
+ unlet empty_default
+ let empty_default = []
+ endif
+ else
+ throw 'invalid-type:Unknown type ' . name
+ endif
+ let ret.timestamp = s:shada_strptime(match[2])
+ if empty(strings)
+ let ret.data = empty_default
+ else
+ while !empty(strings)
+ if strings[0][2] is# '='
+ let data = s:shada_eval(strings[0][4:])
+ call remove(strings, 0)
+ elseif strings[0][2] is# '%'
+ if name is# 'buffer_list' && !has_key(ret, 'data')
+ let ret.data = []
+ endif
+ let match = matchlist(
+ \strings[0],
+ \'\m\C^ % \(Key_*\)\( Description_*\)\? Value')
+ if empty(match)
+ throw 'invalid-map-header:Invalid mapping header: ' . strings[0]
+ endif
+ call remove(strings, 0)
+ let key_len = len(match[1])
+ let desc_skip_len = len(match[2])
+ let data = {'_TYPE': v:msgpack_types.map, '_VAL': []}
+ while !empty(strings) && strings[0][2] is# '+'
+ let line = remove(strings, 0)[4:]
+ let key = substitute(line[:key_len - 1], '\v\C\ *$', '', '')
+ let strval = line[key_len + desc_skip_len + 2:]
+ if strval is# '@'
+ let val = []
+ while !empty(strings) && strings[0][2] is# '|'
+ if strings[0][4] isnot# '-'
+ throw ('invalid-array:Expected hyphen-minus at column 5: '
+ \. strings)
+ endif
+ call add(val, s:shada_eval(remove(strings, 0)[5:]))
+ endwhile
+ else
+ let val = s:shada_eval(strval)
+ endif
+ if (has_key(s:SHADA_STANDARD_KEYS, key)
+ \&& s:SHADA_STANDARD_KEYS[key][2] isnot# s:SHADA_REQUIRED
+ \&& msgpack#equal(s:SHADA_STANDARD_KEYS[key][2], val))
+ unlet val
+ continue
+ endif
+ call add(data._VAL, [{'_TYPE': v:msgpack_types.string, '_VAL': [key]},
+ \val])
+ unlet val
+ endwhile
+ elseif strings[0][2] is# '@'
+ let match = matchlist(
+ \strings[0],
+ \'\m\C^ @ \(Description_* \)\?Value')
+ if empty(match)
+ throw 'invalid-array-header:Invalid array header: ' . strings[0]
+ endif
+ call remove(strings, 0)
+ let desc_skip_len = len(match[1])
+ let data = []
+ while !empty(strings) && strings[0][2] is# '-'
+ let val = remove(strings, 0)[4 + desc_skip_len :]
+ call add(data, s:shada_eval(val))
+ endwhile
+ else
+ throw 'invalid-line:Unrecognized line: ' . strings[0]
+ endif
+ if !has_key(ret, 'data')
+ let ret.data = data
+ elseif type(ret.data) == type([])
+ call add(ret.data, data)
+ else
+ let ret.data = [ret.data, data]
+ endif
+ unlet data
+ endwhile
+ endif
+ let ret._data = msgpackdump([ret.data])
+ let ret.length = len(ret._data) - 1
+ for s in ret._data
+ let ret.length += len(s)
+ endfor
+ return ret
+endfunction
+
+""
+" Convert s:shada_sd_to_strings() output to a list of original entries.
+function shada#strings_to_sd(strings) abort
+ let strings = filter(copy(a:strings), 'v:val !~# ''\v^\s*%(\#|$)''')
+ let stringss = []
+ for string in strings
+ if string[0] isnot# ' '
+ call add(stringss, [])
+ endif
+ call add(stringss[-1], string)
+ endfor
+ return map(copy(stringss), 's:shada_convert_strings(v:val)')
+endfunction
+
+""
+" Convert a list of strings to list of strings suitable for writefile().
+function shada#get_binstrings(strings) abort
+ let entries = shada#strings_to_sd(a:strings)
+ if !g:shada#keep_old_header
+ call filter(entries, 'v:val.type != ' . s:SHADA_ENTRY_TYPES.header)
+ endif
+ if g:shada#add_own_header
+ let data = {'version': v:version, 'generator': 'shada.vim'}
+ let dumped_data = msgpackdump([data])
+ let length = len(dumped_data) - 1
+ for s in dumped_data
+ let length += len(s)
+ endfor
+ call insert(entries, {
+ \'type': s:SHADA_ENTRY_TYPES.header,
+ \'timestamp': localtime(),
+ \'length': length,
+ \'data': data,
+ \'_data': dumped_data,
+ \})
+ endif
+ let mpack = []
+ for entry in entries
+ let mpack += map(copy(s:SHADA_ENTRY_OBJECT_SEQUENCE), 'entry[v:val]')
+ endfor
+ return msgpackdump(mpack)
+endfunction
diff --git a/runtime/autoload/spellfile.vim b/runtime/autoload/spellfile.vim
index 5b1079e919..c32dd5df9b 100644
--- a/runtime/autoload/spellfile.vim
+++ b/runtime/autoload/spellfile.vim
@@ -196,9 +196,11 @@ function! spellfile#GetDirChoices()
endfunc
function! spellfile#WritableSpellDir()
- if has("unix")
- " For Unix always use the $HOME/.nvim directory
- return $HOME . "/.nvim/spell"
+ " Always use the $XDG_DATA_HOME/nvim/site directory
+ if exists('$XDG_DATA_HOME')
+ return $XDG_DATA_HOME . "/nvim/site/spell"
+ else
+ return $HOME . "/.local/share/nvim/site/spell"
endif
for dir in split(&rtp, ',')
if filewritable(dir) == 2
diff --git a/runtime/autoload/tutor.vim b/runtime/autoload/tutor.vim
index d2881f7f34..4d5a10a97c 100644
--- a/runtime/autoload/tutor.vim
+++ b/runtime/autoload/tutor.vim
@@ -2,6 +2,12 @@
" Setup: {{{1
function! tutor#SetupVim()
+ if &columns < 90
+ set columns=90
+ endif
+ if !exists('g:did_load_ftplugin') || g:did_load_ftplugin != 1
+ filetype plugin on
+ endif
if has('syntax')
if !exists('g:syntax_on') || g:syntax_on == 0
syntax on
@@ -336,6 +342,7 @@ function! tutor#TutorCmd(tutor_name)
let l:to_open = l:tutors[l:tutor_to_open-1]
endif
+ call tutor#SetupVim()
exe "edit ".l:to_open
endfunction