feat: rebuild master from the live desktop, and add the KDE configuration

master still carried the 2021 tree. Task 6 does a checkout over $HOME, so nine
of those files would have overwritten the current configuration rather than
updated it - i3, sway, dunst, nvim, vim and tmux, all diverged by years. The
plan had no step for this; the design warned about it and then nothing
implemented the warning.

The nine are now taken from the live machine verbatim, and the 31 files with no
counterpart there are dropped. Everything remains on archive/2021-i3-sway.
README.md and .scripts/install.sh are kept despite having no live counterpart:
the first documents the repository and the second is what ls.shron.de/dotconf
serves, so deleting it would break that link.

Verified byte-identical to the live files afterwards, which is the point - a
checkout on this machine must change nothing.

KDE has been in daily use for a while with nothing backing it up. Eighteen rc
files and the nine autostart entries are added: window rules and shortcuts,
notification behaviour, the lock screen, and the panel layout in
plasma-org.kde.plasma.desktop-appletsrc. That last one is rewritten by
plasmashell whenever anything moves, so it will produce churn - kept anyway,
since a lost panel layout is the most tedious thing here to rebuild by hand.

.config/kdeconnect/ is excluded rather than added. It holds the device
certificate and its private key, and is pairing state rather than
configuration - the only place under .config that carries a secret.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
thomas.kopp
2026-08-07 15:53:50 +02:00
co-authored by Claude Opus 5
parent ce560c315d
commit d215dfefc5
68 changed files with 3574 additions and 1889 deletions
+169 -80
View File
@@ -99,7 +99,13 @@ let s:mac_gui = has('gui_macvim') && has('gui_running')
let s:is_win = has('win32')
let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win)
let s:vim8 = has('patch-8.0.0039') && exists('*job_start')
let s:me = resolve(expand('<sfile>:p'))
if s:is_win && &shellslash
set noshellslash
let s:me = resolve(expand('<sfile>:p'))
set shellslash
else
let s:me = resolve(expand('<sfile>:p'))
endif
let s:base_spec = { 'branch': 'master', 'frozen': 0 }
let s:TYPE = {
\ 'string': type(''),
@@ -110,10 +116,42 @@ let s:TYPE = {
let s:loaded = get(s:, 'loaded', {})
let s:triggers = get(s:, 'triggers', {})
if s:is_win
function! s:plug_call(fn, ...)
let shellslash = &shellslash
try
set noshellslash
return call(a:fn, a:000)
finally
let &shellslash = shellslash
endtry
endfunction
else
function! s:plug_call(fn, ...)
return call(a:fn, a:000)
endfunction
endif
function! s:plug_getcwd()
return s:plug_call('getcwd')
endfunction
function! s:plug_fnamemodify(fname, mods)
return s:plug_call('fnamemodify', a:fname, a:mods)
endfunction
function! s:plug_expand(fmt)
return s:plug_call('expand', a:fmt, 1)
endfunction
function! s:plug_tempname()
return s:plug_call('tempname')
endfunction
function! plug#begin(...)
if a:0 > 0
let s:plug_home_org = a:1
let home = s:path(fnamemodify(expand(a:1), ':p'))
let home = s:path(s:plug_fnamemodify(s:plug_expand(a:1), ':p'))
elseif exists('g:plug_home')
let home = s:path(g:plug_home)
elseif !empty(&rtp)
@@ -121,7 +159,7 @@ function! plug#begin(...)
else
return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.')
endif
if fnamemodify(home, ':t') ==# 'plugin' && fnamemodify(home, ':h') ==# s:first_rtp
if s:plug_fnamemodify(home, ':t') ==# 'plugin' && s:plug_fnamemodify(home, ':h') ==# s:first_rtp
return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.')
endif
@@ -139,6 +177,16 @@ function! s:define_commands()
if !executable('git')
return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.')
endif
if has('win32')
\ && &shellslash
\ && (&shell =~# 'cmd\.exe' || &shell =~# 'powershell\.exe')
return s:err('vim-plug does not support shell, ' . &shell . ', when shellslash is set.')
endif
if !has('nvim')
\ && (has('win32') || has('win32unix'))
\ && !has('multi_byte')
return s:err('Vim needs +multi_byte feature on Windows to run shell commands. Enable +iconv for best results.')
endif
command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(<bang>0, [<f-args>])
command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(<bang>0, [<f-args>])
command! -nargs=0 -bar -bang PlugClean call s:clean(<bang>0)
@@ -193,9 +241,17 @@ function! s:ask_no_interrupt(...)
endtry
endfunction
function! s:lazy(plug, opt)
return has_key(a:plug, a:opt) &&
\ (empty(s:to_a(a:plug[a:opt])) ||
\ !isdirectory(a:plug.dir) ||
\ len(s:glob(s:rtp(a:plug), 'plugin')) ||
\ len(s:glob(s:rtp(a:plug), 'after/plugin')))
endfunction
function! plug#end()
if !exists('g:plugs')
return s:err('Call plug#begin() first')
return s:err('plug#end() called without calling plug#begin() first')
endif
if exists('#PlugLOD')
@@ -214,7 +270,7 @@ function! plug#end()
continue
endif
let plug = g:plugs[name]
if get(s:loaded, name, 0) || !has_key(plug, 'on') && !has_key(plug, 'for')
if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for')
let s:loaded[name] = 1
continue
endif
@@ -326,11 +382,11 @@ function! s:progress_opt(base)
\ s:git_version_requirement(1, 7, 1) ? '--progress' : ''
endfunction
if s:is_win
function! s:rtp(spec)
return s:path(a:spec.dir . get(a:spec, 'rtp', ''))
endfunction
function! s:rtp(spec)
return s:path(a:spec.dir . get(a:spec, 'rtp', ''))
endfunction
if s:is_win
function! s:path(path)
return s:trim(substitute(a:path, '/', '\', 'g'))
endfunction
@@ -342,11 +398,33 @@ if s:is_win
function! s:is_local_plug(repo)
return a:repo =~? '^[a-z]:\|^[%~]'
endfunction
else
function! s:rtp(spec)
return s:dirpath(a:spec.dir . get(a:spec, 'rtp', ''))
" Copied from fzf
function! s:wrap_cmds(cmds)
let cmds = [
\ '@echo off',
\ 'setlocal enabledelayedexpansion']
\ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds])
\ + ['endlocal']
if has('iconv')
if !exists('s:codepage')
let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0)
endif
return map(cmds, printf('iconv(v:val."\r", "%s", "cp%d")', &encoding, s:codepage))
endif
return map(cmds, 'v:val."\r"')
endfunction
function! s:batchfile(cmd)
let batchfile = s:plug_tempname().'.bat'
call writefile(s:wrap_cmds(a:cmd), batchfile)
let cmd = plug#shellescape(batchfile, {'shell': &shell, 'script': 0})
if &shell =~# 'powershell\.exe'
let cmd = '& ' . cmd
endif
return [batchfile, cmd]
endfunction
else
function! s:path(path)
return s:trim(a:path)
endfunction
@@ -426,8 +504,8 @@ endfunction
function! s:dobufread(names)
for name in a:names
let path = s:rtp(g:plugs[name]).'/**'
for dir in ['ftdetect', 'ftplugin']
let path = s:rtp(g:plugs[name])
for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin']
if len(finddir(dir, path))
if exists('#BufRead')
doautocmd BufRead
@@ -546,7 +624,7 @@ function! plug#(repo, ...)
try
let repo = s:trim(a:repo)
let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec
let name = get(opts, 'as', fnamemodify(repo, ':t:s?\.git$??'))
let name = get(opts, 'as', s:plug_fnamemodify(repo, ':t:s?\.git$??'))
let spec = extend(s:infer_properties(name, repo), opts)
if !has_key(g:plugs, name)
call add(g:plugs_order, name)
@@ -566,7 +644,7 @@ function! s:parse_options(arg)
elseif type == s:TYPE.dict
call extend(opts, a:arg)
if has_key(opts, 'dir')
let opts.dir = s:dirpath(expand(opts.dir))
let opts.dir = s:dirpath(s:plug_expand(opts.dir))
endif
else
throw 'Invalid argument type (expected: string or dictionary)'
@@ -577,7 +655,7 @@ endfunction
function! s:infer_properties(name, repo)
let repo = a:repo
if s:is_local_plug(repo)
return { 'dir': s:dirpath(expand(repo)) }
return { 'dir': s:dirpath(s:plug_expand(repo)) }
else
if repo =~ ':'
let uri = repo
@@ -730,7 +808,7 @@ function! s:finish_bindings()
endfunction
function! s:prepare(...)
if empty(getcwd())
if empty(s:plug_getcwd())
throw 'Invalid current working directory. Cannot proceed.'
endif
@@ -763,6 +841,9 @@ function! s:prepare(...)
execute 'silent! unmap <buffer>' k
endfor
setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell
if exists('+colorcolumn')
setlocal colorcolumn=
endif
setf vim-plug
if exists('g:syntax_on')
call s:syntax()
@@ -783,31 +864,28 @@ endfunction
function! s:chsh(swap)
let prev = [&shell, &shellcmdflag, &shellredir]
if s:is_win
set shell=cmd.exe shellcmdflag=/c shellredir=>%s\ 2>&1
elseif a:swap
if !s:is_win && a:swap
set shell=sh shellredir=>%s\ 2>&1
endif
return prev
endfunction
function! s:bang(cmd, ...)
let batchfile = ''
try
let [sh, shellcmdflag, shrd] = s:chsh(a:0)
" FIXME: Escaping is incomplete. We could use shellescape with eval,
" but it won't work on Windows.
let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd
if s:is_win
let batchfile = tempname().'.bat'
call writefile(["@echo off\r", cmd . "\r"], batchfile)
let cmd = batchfile
let [batchfile, cmd] = s:batchfile(cmd)
endif
let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%')
execute "normal! :execute g:_plug_bang\<cr>\<cr>"
finally
unlet g:_plug_bang
let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
if s:is_win
if s:is_win && filereadable(batchfile)
call delete(batchfile)
endif
endtry
@@ -886,7 +964,7 @@ function! s:checkout(spec)
let output = s:system('git rev-parse HEAD', a:spec.dir)
if !v:shell_error && !s:hash_match(sha, s:lines(output)[0])
let output = s:system(
\ 'git fetch --depth 999999 && git checkout '.s:esc(sha).' --', a:spec.dir)
\ 'git fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir)
endif
return output
endfunction
@@ -1004,10 +1082,12 @@ function! s:update_impl(pull, force, args) abort
let s:clone_opt = get(g:, 'plug_shallow', 1) ?
\ '--depth 1' . (s:git_version_requirement(1, 7, 10) ? ' --no-single-branch' : '') : ''
if has('win32unix')
if has('win32unix') || has('wsl')
let s:clone_opt .= ' -c core.eol=lf -c core.autocrlf=input'
endif
let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : ''
" Python version requirement (>= 2.7)
if python && !has('python3') && !ruby && !use_job && s:update.threads > 1
redir => pyv
@@ -1081,7 +1161,7 @@ function! s:update_finish()
elseif has_key(spec, 'tag')
let tag = spec.tag
if tag =~ '\*'
let tags = s:lines(s:system('git tag --list '.s:shellesc(tag).' --sort -version:refname 2>&1', spec.dir))
let tags = s:lines(s:system('git tag --list '.plug#shellescape(tag).' --sort -version:refname 2>&1', spec.dir))
if !v:shell_error && !empty(tags)
let tag = tags[0]
call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag))
@@ -1089,17 +1169,17 @@ function! s:update_finish()
endif
endif
call s:log4(name, 'Checking out '.tag)
let out = s:system('git checkout -q '.s:esc(tag).' -- 2>&1', spec.dir)
let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir)
else
let branch = s:esc(get(spec, 'branch', 'master'))
call s:log4(name, 'Merging origin/'.branch)
let out = s:system('git checkout -q '.branch.' -- 2>&1'
\. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only origin/'.branch.' 2>&1')), spec.dir)
let branch = get(spec, 'branch', 'master')
call s:log4(name, 'Merging origin/'.s:esc(branch))
let out = s:system('git checkout -q '.plug#shellescape(branch).' -- 2>&1'
\. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only '.plug#shellescape('origin/'.branch).' 2>&1')), spec.dir)
endif
if !v:shell_error && filereadable(spec.dir.'/.gitmodules') &&
\ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir))
call s:log4(name, 'Updating submodules. This may take a while.')
let out .= s:bang('git submodule update --init --recursive 2>&1', spec.dir)
let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir)
endif
let msg = s:format_message(v:shell_error ? 'x': '-', name, out)
if v:shell_error
@@ -1138,7 +1218,7 @@ function! s:job_abort()
silent! call job_stop(j.jobid)
endif
if j.new
call s:system('rm -rf ' . s:shellesc(g:plugs[name].dir))
call s:rm_rf(g:plugs[name].dir)
endif
endfor
let s:jobs = {}
@@ -1191,22 +1271,17 @@ endfunction
function! s:spawn(name, cmd, opts)
let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''],
\ 'batchfile': (s:is_win && (s:nvim || s:vim8)) ? tempname().'.bat' : '',
\ 'new': get(a:opts, 'new', 0) }
let s:jobs[a:name] = job
let cmd = has_key(a:opts, 'dir') ? s:with_cd(a:cmd, a:opts.dir) : a:cmd
if !empty(job.batchfile)
call writefile(["@echo off\r", cmd . "\r"], job.batchfile)
let cmd = job.batchfile
endif
let argv = add(s:is_win ? ['cmd', '/c'] : ['sh', '-c'], cmd)
let cmd = has_key(a:opts, 'dir') ? s:with_cd(a:cmd, a:opts.dir, 0) : a:cmd
let argv = s:is_win ? ['cmd', '/s', '/c', '"'.cmd.'"'] : ['sh', '-c', cmd]
if s:nvim
call extend(job, {
\ 'on_stdout': function('s:nvim_cb'),
\ 'on_exit': function('s:nvim_cb'),
\ })
let jid = jobstart(argv, job)
let jid = s:plug_call('jobstart', argv, job)
if jid > 0
let job.jobid = jid
else
@@ -1249,9 +1324,6 @@ function! s:reap(name)
call s:log(bullet, a:name, empty(result) ? 'OK' : result)
call s:bar()
if has_key(job, 'batchfile') && !empty(job.batchfile)
call delete(job.batchfile)
endif
call remove(s:jobs, a:name)
endfunction
@@ -1266,9 +1338,10 @@ function! s:bar()
endfunction
function! s:logpos(name)
for i in range(4, line('$'))
let max = line('$')
for i in range(4, max > 4 ? max : 4)
if getline(i) =~# '^[-+x*] '.a:name.':'
for j in range(i + 1, line('$'))
for j in range(i + 1, max > 5 ? max : 5)
if getline(j) !~ '^ '
return [i, j - 1]
endif
@@ -1318,7 +1391,7 @@ while 1 " Without TCO, Vim stack is bound to explode
let name = keys(s:update.todo)[0]
let spec = remove(s:update.todo, name)
let new = !isdirectory(spec.dir)
let new = empty(globpath(spec.dir, '.git', 1))
call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...')
redraw
@@ -1341,8 +1414,8 @@ while 1 " Without TCO, Vim stack is bound to explode
\ printf('git clone %s %s %s %s 2>&1',
\ has_tag ? '' : s:clone_opt,
\ prog,
\ s:shellesc(spec.uri),
\ s:shellesc(s:trim(spec.dir))), { 'new': 1 })
\ plug#shellescape(spec.uri, {'script': 0}),
\ plug#shellescape(s:trim(spec.dir), {'script': 0})), { 'new': 1 })
endif
if !s:jobs[name].running
@@ -1969,19 +2042,29 @@ function! s:update_ruby()
EOF
endfunction
function! s:shellesc_cmd(arg)
let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g')
let escaped = substitute(escaped, '%', '%%', 'g')
let escaped = substitute(escaped, '"', '\\^&', 'g')
let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g')
return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"'
function! s:shellesc_cmd(arg, script)
let escaped = substitute('"'.a:arg.'"', '[&|<>()@^!"]', '^&', 'g')
return substitute(escaped, '%', (a:script ? '%' : '^') . '&', 'g')
endfunction
function! s:shellesc(arg)
if &shell =~# 'cmd.exe$'
return s:shellesc_cmd(a:arg)
function! s:shellesc_ps1(arg)
return "'".substitute(escape(a:arg, '\"'), "'", "''", 'g')."'"
endfunction
function! s:shellesc_sh(arg)
return "'".substitute(a:arg, "'", "'\\\\''", 'g')."'"
endfunction
function! plug#shellescape(arg, ...)
let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {}
let shell = get(opts, 'shell', s:is_win ? 'cmd.exe' : 'sh')
let script = get(opts, 'script', 1)
if shell =~# 'cmd\.exe'
return s:shellesc_cmd(a:arg, script)
elseif shell =~# 'powershell\.exe' || shell =~# 'pwsh$'
return s:shellesc_ps1(a:arg)
endif
return shellescape(a:arg)
return s:shellesc_sh(a:arg)
endfunction
function! s:glob_dir(path)
@@ -2013,23 +2096,23 @@ function! s:format_message(bullet, name, message)
endif
endfunction
function! s:with_cd(cmd, dir)
return printf('cd%s %s && %s', s:is_win ? ' /d' : '', s:shellesc(a:dir), a:cmd)
function! s:with_cd(cmd, dir, ...)
let script = a:0 > 0 ? a:1 : 1
return printf('cd%s %s && %s', s:is_win ? ' /d' : '', plug#shellescape(a:dir, {'script': script}), a:cmd)
endfunction
function! s:system(cmd, ...)
let batchfile = ''
try
let [sh, shellcmdflag, shrd] = s:chsh(1)
let cmd = a:0 > 0 ? s:with_cd(a:cmd, a:1) : a:cmd
if s:is_win
let batchfile = tempname().'.bat'
call writefile(["@echo off\r", cmd . "\r"], batchfile)
let cmd = batchfile
let [batchfile, cmd] = s:batchfile(cmd)
endif
return system(s:is_win ? '('.cmd.')' : cmd)
return system(cmd)
finally
let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
if s:is_win
if s:is_win && filereadable(batchfile)
call delete(batchfile)
endif
endtry
@@ -2102,7 +2185,7 @@ endfunction
function! s:rm_rf(dir)
if isdirectory(a:dir)
call s:system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . s:shellesc(a:dir))
call s:system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . plug#shellescape(a:dir))
endif
endfunction
@@ -2134,7 +2217,7 @@ function! s:clean(force)
let allowed = {}
for dir in dirs
let allowed[s:dirpath(fnamemodify(dir, ':h:h'))] = 1
let allowed[s:dirpath(s:plug_fnamemodify(dir, ':h:h'))] = 1
let allowed[dir] = 1
for child in s:glob_dir(dir)
let allowed[child] = 1
@@ -2207,11 +2290,11 @@ endfunction
function! s:upgrade()
echo 'Downloading the latest version of vim-plug'
redraw
let tmp = tempname()
let tmp = s:plug_tempname()
let new = tmp . '/plug.vim'
try
let out = s:system(printf('git clone --depth 1 %s %s', s:plug_src, tmp))
let out = s:system(printf('git clone --depth 1 %s %s', plug#shellescape(s:plug_src), plug#shellescape(tmp)))
if v:shell_error
return s:err('Error upgrading vim-plug: '. out)
endif
@@ -2352,18 +2435,17 @@ function! s:preview_commit()
wincmd P
endif
setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable
let batchfile = ''
try
let [sh, shellcmdflag, shrd] = s:chsh(1)
let cmd = 'cd '.s:shellesc(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha
let cmd = 'cd '.plug#shellescape(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha
if s:is_win
let batchfile = tempname().'.bat'
call writefile(["@echo off\r", cmd . "\r"], batchfile)
let cmd = batchfile
let [batchfile, cmd] = s:batchfile(cmd)
endif
execute 'silent %!' cmd
finally
let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
if s:is_win
if s:is_win && filereadable(batchfile)
call delete(batchfile)
endif
endtry
@@ -2407,7 +2489,13 @@ function! s:diff()
call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:')
for [k, v] in plugs
let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..'
let diff = s:system_chomp('git log --graph --color=never '.join(map(['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range], 's:shellesc(v:val)')), v.dir)
let cmd = 'git log --graph --color=never '
\ . (s:git_version_requirement(2, 10, 0) ? '--no-show-signature ' : '')
\ . join(map(['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range], 'plug#shellescape(v:val)'))
if has_key(v, 'rtp')
let cmd .= ' -- '.plug#shellescape(v.rtp)
endif
let diff = s:system_chomp(cmd, v.dir)
if !empty(diff)
let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : ''
call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)')))
@@ -2453,7 +2541,7 @@ function! s:revert()
return
endif
call s:system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch).' --', g:plugs[name].dir)
call s:system('git reset --hard HEAD@{1} && git checkout '.plug#shellescape(g:plugs[name].branch).' --', g:plugs[name].dir)
setlocal modifiable
normal! "_dap
setlocal nomodifiable
@@ -2481,7 +2569,7 @@ function! s:snapshot(force, ...) abort
endfor
if a:0 > 0
let fn = expand(a:1)
let fn = s:plug_expand(a:1)
if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?'))
return
endif
@@ -2507,3 +2595,4 @@ endif
let &cpo = s:cpo_save
unlet s:cpo_save