From 4325da83822f80aeac5e2a71cb77c38bf66b5ccc Mon Sep 17 00:00:00 2001 From: Dustin Swan Date: Mon, 2 Nov 2015 16:25:20 +0000 Subject: [PATCH] updating vimplug, fixing neovim symlinks --- symlinks.sh | 5 +- vim/autoload/plug.vim | 151 ++++++++++++++++++++++++------------------ 2 files changed, 89 insertions(+), 67 deletions(-) diff --git a/symlinks.sh b/symlinks.sh index 57d6afe..c7dd1e0 100644 --- a/symlinks.sh +++ b/symlinks.sh @@ -6,9 +6,12 @@ rm -rf ~/.ghc; mkdir ~/.ghc; ln -s ~/dotfiles/ghci.conf ~/.ghc/ghci.conf rm ~/.gitconfig; ln -s ~/dotfiles/gitconfig ~/.gitconfig rm ~/.ruby-version; ln -s ~/dotfiles/ruby-version ~/.ruby-version rm ~/.tmux.conf; ln -s ~/dotfiles/tmux.conf ~/.tmux.conf + rm ~/.vimrc; ln -s ~/dotfiles/vimrc ~/.vimrc -rm -rf ~/.nvim; mkdir ~/.nvim; ln -s ~/dotfiles/vimrc ~/.nvim/nvimrc +rm ~/.nvimrc; ln -s ~/dotfiles/vimrc ~/.nvimrc rm -rf ~/.vim; ln -s ~/dotfiles/vim ~/.vim +rm -rf ~/.nvim; ln -s ~/dotfiles/vim ~/.nvim + rm -rf ~/.config/khal; mkdir -p ~/.config/khal; ln -s ~/dotfiles/khal.conf ~/.config/khal/khal.conf rm -rf ~/.vdirsyncer; mkdir ~/.vdirsyncer; ln -s ~/dotfiles/vdirsyncer/config ~/.vdirsyncer/config rm ~/.zshrc; ln -s ~/dotfiles/zshrc ~/.zshrc diff --git a/vim/autoload/plug.vim b/vim/autoload/plug.vim index cabeb4f..b63d777 100644 --- a/vim/autoload/plug.vim +++ b/vim/autoload/plug.vim @@ -33,6 +33,7 @@ " " Unmanaged plugin (manually installed and updated) " Plug '~/my-prototype-plugin' " +" " Add plugins to &runtimepath " call plug#end() " " Then reload .vimrc and :PlugInstall to install plugins. @@ -398,7 +399,7 @@ function! s:lod(names, types) endfunction function! s:lod_ft(pat, names) - call s:lod(a:names, ['plugin', 'after/plugin']) + call s:lod(a:names, ['plugin', 'after/plugin', 'syntax', 'after/syntax']) execute 'autocmd! PlugLOD FileType' a:pat if exists('#filetypeplugin#FileType') doautocmd filetypeplugin FileType @@ -645,7 +646,7 @@ function! s:do(pull, force, todo) endif let installed = has_key(s:update.new, name) let updated = installed ? 0 : - \ (a:pull && !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"', spec.dir))) + \ (a:pull && index(s:update.errors, name) < 0 && !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"', spec.dir))) if a:force || installed || updated execute 'cd' s:esc(spec.dir) call append(3, '- Post-update hook for '. name .' ... ') @@ -1049,17 +1050,17 @@ G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads')) G_STOP = thr.Event() G_THREADS = {} -class BaseExc(Exception): +class PlugError(Exception): def __init__(self, msg): self._msg = msg @property def msg(self): return self._msg -class CmdTimedOut(BaseExc): +class CmdTimedOut(PlugError): pass -class CmdFailed(BaseExc): +class CmdFailed(PlugError): pass -class InvalidURI(BaseExc): +class InvalidURI(PlugError): pass class Action(object): INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] @@ -1073,7 +1074,7 @@ class Buffer(object): self.maxy = int(vim.eval('winheight(".")')) self.num_plugs = num_plugs - def _where(self, name): + def __where(self, name): """ Find first line with name in current buffer. Return line num. """ found, lnum = False, 0 matcher = re.compile('^[-+x*] {0}:'.format(name)) @@ -1102,8 +1103,7 @@ class Buffer(object): def write(self, action, name, lines): first, rest = lines[0], lines[1:] msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)] - padded_rest = [' ' + line for line in rest] - msg.extend(padded_rest) + msg.extend([' ' + line for line in rest]) try: if action == Action.ERROR: @@ -1113,7 +1113,7 @@ class Buffer(object): self.bar += '=' curbuf = vim.current.buffer - lnum = self._where(name) + lnum = self.__where(name) if lnum != -1: # Found matching line num del curbuf[lnum] if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]): @@ -1127,56 +1127,73 @@ class Buffer(object): pass class Command(object): - def __init__(self, cmd, cmd_dir=None, timeout=60, ntries=3, cb=None, clean=None): + def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None): self.cmd = cmd self.cmd_dir = cmd_dir self.timeout = timeout - self.ntries = ntries self.callback = cb if cb else (lambda msg: None) - self.clean = clean + self.clean = clean if clean else (lambda: None) + self.proc = None - def attempt_cmd(self): - """ Tries to run the command, returns result if no exceptions. """ - attempt = 0 - finished = False - limit = self.timeout + @property + def alive(self): + """ Returns true only if command still running. """ + return self.proc and self.proc.poll() is None + + def execute(self, ntries=3): + """ Execute the command with ntries if CmdTimedOut. + Returns the output of the command if no Exception. + """ + attempt, finished, limit = 0, False, self.timeout while not finished: try: attempt += 1 - result = self.timeout_cmd() + result = self.try_command() finished = True + return result except CmdTimedOut: - if attempt != self.ntries: - for count in range(3, 0, -1): - if G_STOP.is_set(): - raise KeyboardInterrupt - msg = 'Timeout. Will retry in {0} second{1} ...'.format( - count, 's' if count != 1 else '') - self.callback([msg]) - time.sleep(1) + if attempt != ntries: + self.notify_retry() self.timeout += limit - self.callback(['Retrying ...']) else: raise - return result - - def timeout_cmd(self): + def notify_retry(self): + """ Retry required for command, notify user. """ + for count in range(3, 0, -1): + if G_STOP.is_set(): + raise KeyboardInterrupt + msg = 'Timeout. Will retry in {0} second{1} ...'.format( + count, 's' if count != 1 else '') + self.callback([msg]) + time.sleep(1) + self.callback(['Retrying ...']) + + def try_command(self): """ Execute a cmd & poll for callback. Returns list of output. - Raises CmdFailed -> return code for Popen isn't 0 - Raises CmdTimedOut -> command exceeded timeout without new output + Raises CmdFailed -> return code for Popen isn't 0 + Raises CmdTimedOut -> command exceeded timeout without new output """ - proc = None first_line = True + try: - tfile = tempfile.NamedTemporaryFile(mode='w+b', delete=False) - proc = subprocess.Popen(self.cmd, cwd=self.cmd_dir, stdout=tfile, - stderr=subprocess.STDOUT, shell=True, preexec_fn=os.setsid) - while proc.poll() is None: - # Yield this thread - time.sleep(0.2) + tfile = tempfile.NamedTemporaryFile(mode='w+b') + self.proc = subprocess.Popen(self.cmd, cwd=self.cmd_dir, stdout=tfile, + stderr=subprocess.STDOUT, shell=True, + preexec_fn=os.setsid) + thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,)) + thrd.start() + + thread_not_started = True + while thread_not_started: + try: + thrd.join(0.1) + thread_not_started = False + except RuntimeError: + pass + while self.alive: if G_STOP.is_set(): raise KeyboardInterrupt @@ -1190,23 +1207,24 @@ class Command(object): if time_diff > self.timeout: raise CmdTimedOut(['Timeout!']) + thrd.join(0.5) + tfile.seek(0) - result = [line.decode().rstrip() for line in tfile] + result = [line.decode('utf-8', 'replace').rstrip() for line in tfile] + + if self.proc.returncode != 0: + raise CmdFailed([''] + result) - if proc.returncode != 0: - msg = [''] - msg.extend(result) - raise CmdFailed(msg) + return result except: - if proc and proc.poll() is None: - os.killpg(proc.pid, signal.SIGTERM) - if self.clean: - self.clean() + self.terminate() raise - finally: - os.remove(tfile.name) - return result + def terminate(self): + """ Terminate process and cleanup. """ + if self.alive: + os.killpg(self.proc.pid, signal.SIGTERM) + self.clean() class Plugin(object): def __init__(self, name, args, buf_q, lock): @@ -1227,7 +1245,7 @@ class Plugin(object): self.install() with self.lock: thread_vim_command("let s:update.new['{0}'] = 1".format(self.name)) - except (CmdTimedOut, CmdFailed, InvalidURI) as exc: + except PlugError as exc: self.write(Action.ERROR, self.name, exc.msg) except KeyboardInterrupt: G_STOP.set() @@ -1252,11 +1270,18 @@ class Plugin(object): self.write(Action.INSTALL, self.name, ['Installing ...']) callback = functools.partial(self.write, Action.INSTALL, self.name) cmd = 'git clone {0} {1} --recursive {2} -b {3} {4} 2>&1'.format( - '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], self.checkout, esc(target)) - com = Command(cmd, None, G_TIMEOUT, G_RETRIES, callback, clean(target)) - result = com.attempt_cmd() + '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], + self.checkout, esc(target)) + com = Command(cmd, None, G_TIMEOUT, callback, clean(target)) + result = com.execute(G_RETRIES) self.write(Action.DONE, self.name, result[-1:]) + def repo_uri(self): + cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url' + command = Command(cmd, self.args['dir'], G_TIMEOUT,) + result = command.execute(G_RETRIES) + return result[-1] + def update(self): match = re.compile(r'git::?@') actual_uri = re.sub(match, '', self.repo_uri()) @@ -1277,18 +1302,12 @@ class Plugin(object): 'git merge --ff-only {0}'.format(self.merge), 'git submodule update --init --recursive'] cmd = ' 2>&1 && '.join(cmds) - com = Command(cmd, self.args['dir'], G_TIMEOUT, G_RETRIES, callback) - result = com.attempt_cmd() + com = Command(cmd, self.args['dir'], G_TIMEOUT, callback) + result = com.execute(G_RETRIES) self.write(Action.DONE, self.name, result[-1:]) else: self.write(Action.DONE, self.name, ['Already installed']) - def repo_uri(self): - cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url' - command = Command(cmd, self.args['dir'], G_TIMEOUT, G_RETRIES) - result = command.attempt_cmd() - return result[-1] - def write(self, action, name, msg): self.buf_q.put((action, name, msg)) @@ -1325,7 +1344,7 @@ class RefreshThread(thr.Thread): while self.running: with self.lock: thread_vim_command('noautocmd normal! a') - time.sleep(0.2) + time.sleep(0.33) def stop(self): self.running = False @@ -1343,7 +1362,7 @@ def esc(name): def nonblock_read(fname): """ Read a file with nonblock flag. Return the last line. """ fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) - buf = os.read(fread, 100000).decode() + buf = os.read(fread, 100000).decode('utf-8', 'replace') os.close(fread) line = buf.rstrip('\r\n')