mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 16:34:47 +01:00
Merge branch 'zajaczajac-master'
This commit is contained in:
commit
693c638faf
4 changed files with 70 additions and 1 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -28,3 +28,6 @@ pip-selfcheck.json
|
|||
bin/
|
||||
lib/
|
||||
include/
|
||||
|
||||
# Mac
|
||||
.DS_Store
|
||||
|
|
BIN
tests/man1/yes.1.gz
Normal file
BIN
tests/man1/yes.1.gz
Normal file
Binary file not shown.
20
tests/test_man.py
Normal file
20
tests/test_man.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
import os
|
||||
import platform
|
||||
|
||||
import nose
|
||||
from nose.tools import assert_true
|
||||
|
||||
from xonsh.completer import ManCompleter
|
||||
|
||||
os.environ['MANPATH'] = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
def test_man_completion():
|
||||
if (platform.system() != 'Windows'):
|
||||
man_completer = ManCompleter()
|
||||
completions = man_completer.option_complete('--', 'yes')
|
||||
assert_true('--version' in completions)
|
||||
assert_true('--help' in completions)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
nose.runmodule()
|
|
@ -3,6 +3,7 @@ from __future__ import print_function, unicode_literals
|
|||
import os
|
||||
import re
|
||||
import builtins
|
||||
import pickle
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
@ -43,6 +44,7 @@ class Completer(object):
|
|||
self._alias_checksum = None
|
||||
self._path_mtime = -1
|
||||
self._cmds_cache = frozenset()
|
||||
self._man_completer = ManCompleter()
|
||||
try:
|
||||
# FIXME this could be threaded for faster startup times
|
||||
self._load_bash_complete_funcs()
|
||||
|
@ -94,6 +96,8 @@ class Completer(object):
|
|||
elif prefix.startswith('${') or prefix.startswith('@('):
|
||||
# python mode explicitly
|
||||
rtn = set()
|
||||
elif prefix.startswith('-'):
|
||||
return sorted(self._man_completer.option_complete(prefix, cmd))
|
||||
elif cmd not in ctx:
|
||||
if cmd == 'import' and begidx == len('import '):
|
||||
# completing module to import
|
||||
|
@ -136,7 +140,7 @@ class Completer(object):
|
|||
return {s + space for s in self._all_commands() if s.startswith(cmd)}
|
||||
|
||||
def module_complete(self, prefix):
|
||||
"""Completes a name of a module to import"""
|
||||
"""Completes a name of a module to import."""
|
||||
modules = set(sys.modules.keys())
|
||||
return {s for s in modules if s.startswith(prefix)}
|
||||
|
||||
|
@ -298,3 +302,45 @@ class Completer(object):
|
|||
allcmds |= set(builtins.aliases.keys())
|
||||
self._cmds_cache = frozenset(allcmds)
|
||||
return self._cmds_cache
|
||||
|
||||
|
||||
OPTIONS_PATH = os.path.expanduser('~') + "/.xonsh_man_completions"
|
||||
SCRAPE_RE = re.compile(r'^(?:\s*(?:-\w|--[a-z0-9-]+)[\s,])+', re.M)
|
||||
INNER_OPTIONS_RE = re.compile(r'-\w|--[a-z0-9-]+')
|
||||
|
||||
|
||||
class ManCompleter(object):
|
||||
"""Helper class that loads completions derived from man pages."""
|
||||
|
||||
def __init__(self):
|
||||
self._load_cached_options()
|
||||
|
||||
def __del__(self):
|
||||
self._save_cached_options()
|
||||
|
||||
def option_complete(self, prefix, cmd):
|
||||
"""Completes an option name, basing on content of man page."""
|
||||
if cmd not in self._options.keys():
|
||||
try:
|
||||
manpage = subprocess.Popen(["man", cmd], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||
# This is a trick to get rid of reverse line feeds
|
||||
text = subprocess.check_output(["col", "-b"], stdin=manpage.stdout).decode('utf-8')
|
||||
scraped_text = ' '.join(SCRAPE_RE.findall(text))
|
||||
matches = INNER_OPTIONS_RE.findall(scraped_text)
|
||||
self._options[cmd] = matches
|
||||
except:
|
||||
return set()
|
||||
return {s for s in self._options[cmd] if s.startswith(prefix)}
|
||||
|
||||
def _load_cached_options(self):
|
||||
"""Load options from file at startup."""
|
||||
try:
|
||||
with open(OPTIONS_PATH, 'rb') as f:
|
||||
self._options = pickle.load(f)
|
||||
except:
|
||||
self._options = {}
|
||||
|
||||
def _save_cached_options(self):
|
||||
"""Save completions to file."""
|
||||
with open(OPTIONS_PATH, 'wb') as f:
|
||||
pickle.dump(self._options, f)
|
||||
|
|
Loading…
Add table
Reference in a new issue