浏览代码

Update README and vim-plug

Weiyi Lou 10 年之前
父节点
当前提交
c6206c00f7
共有 2 个文件被更改,包括 93 次插入86 次删除
  1. 13 24
      README.md
  2. 80 62
      vim/autoload/plug.vim

+ 13 - 24
README.md

@@ -21,12 +21,12 @@ The configs reflect a heavy preference for `vim`-like bindings.
 - The [Solarized][] dark colour palette makes the `zsh` prompt nicer.
 - The [Meslo][] font (Menlo, patched for powerline), makes `vim` and `tmux` look
   better, and has [Rainbarf][] graph glyphs.
-- [Vim-Plug][] needs plain `vim` to have Python or Ruby support to perform
+- [Vim-Plug][] needs `vim` with Python or Ruby support or neovim to perform
   parallel downloads.
-- [The Silver Searcher][] should be installed where possible. Otherwise, [Ack][]
-  is part of this repo as a fallback (requires Perl 5.8.8).
+- [The Silver Searcher][] should be installed where possible. If not available,
+  [Ack][] (part of this repo) will be used as a fallback (requires Perl 5.8.8).
 - Install [Pandoc][] for vim to generate documents from `.pandoc` files ([Pandoc
-  Markdown][]). Use [pandoc-citeproc][] for bibliographical assistance.
+  Markdown][]). Install [pandoc-citeproc][] for bibliographical assistance.
 
 [Solarized]: http://ethanschoonover.com/solarized
 [Meslo]: https://github.com/Lokaltog/powerline-fonts
@@ -65,19 +65,19 @@ Enjoy the amount of time wasted on tweaking a setup :D
 
 ### Vim
 
-`Space` is the `<leader>`.
+`Space` is the `<Leader>`.
 
-- `<leader>d` is the filebrowser (netrw).
-- `<leader>p` fuzzy-finds files. Best in Git repositories.
-- `<leader>f` fuzzy-finds functions in the current file.
-- `<leader>t` opens a function/variable list for the current file.
-- `<leader>n` toggles line numbers.
-- `<leader>w` saves.
-- `<leader>q` closes files.
+- `<Leader>d` is the filebrowser (netrw).
+- `<Leader>p` fuzzy-finds files. Best in Git repositories.
+- `<Leader>f` fuzzy-finds functions in the current file.
+- `<Leader>t` opens a function/variable list for the current file.
+- `<Leader>n` toggles line numbers.
+- `<Leader>w` saves.
+- `<Leader>q` closes files.
 - Additional text objects exist (see `'Text Objects'` in [plugins.vim][]).
 - Saving `.pandoc` files also outputs `.docx` versions.
 - Activate `:Goyo` for distraction-free writing.
-- Don't forget to invoke `:call UltraPower()`.
+- 3 colour schemes are available. Toggle with `:Dark`, `:Light` and `:Neon`.
 
 [plugins.vim]: vim/plugins.vim
 
@@ -106,14 +106,3 @@ This config provides the following:
 - `j` and `k` half-pages down and up (`<C-d>`/`<C-u>` equivalents).
 - `H`, `J`, `K`, `L` are small motions (5 lines or chars) within a page.
 - `<C-h>` and `<C-l>` relocate a tab left and right.
-
-## Issues
-
-### ZSH is slow in OS X Mavericks!
-
-Check if the slowness occurs in Git repositories. If it does, this is because of
-the Apple-provided version of Git. Install Git through homebrew.
-
-More info: [stackexchange][]
-
-[stackexchange]: http://apple.stackexchange.com/questions/106784/terminal-goes-slow-after-install-mavericks-os

+ 80 - 62
vim/autoload/plug.vim

@@ -1050,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', '-']
@@ -1074,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))
@@ -1103,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:
@@ -1114,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]):
@@ -1128,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
 
@@ -1191,23 +1207,24 @@ class Command(object):
         if time_diff > self.timeout:
           raise CmdTimedOut(['Timeout!'])
 
+        thrd.join(0.5)
+
       tfile.seek(0)
       result = [line.decode('utf-8', 'replace').rstrip() for line in tfile]
 
-      if proc.returncode != 0:
-        msg = ['']
-        msg.extend(result)
-        raise CmdFailed(msg)
+      if self.proc.returncode != 0:
+        raise CmdFailed([''] + result)
+
+      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):
@@ -1228,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()
@@ -1253,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())
@@ -1278,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))
 
@@ -1326,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