Skip to content

Commit

Permalink
Simple implementation of file system path completion.
Browse files Browse the repository at this point in the history
This behaves reasonably similarly to the readline default.

For example, try

$ bin/osh

osh$ ls c<TAB>
  • Loading branch information
Andy Chu committed Sep 21, 2018
1 parent fa78b9c commit ca9d0e4
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
30 changes: 29 additions & 1 deletion core/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,34 @@ def Matches(self, words, index, prefix):
yield name + ' ' # full word


class FileSystemAction(CompletionAction):
def __init__(self):
self.cache = {} # Do we need this?

def Matches(self, words, index, prefix):
i = prefix.rfind('/')
if i == -1:
base_dir = '.'
base = ''
else:
base_dir = prefix[:i]
base = base_dir
#log('base_dir %r', base_dir)

try:
names = os.listdir(base_dir)
except OSError as e:
return # nothing

for name in names:
path = os.path.join(base, name)
if path.startswith(prefix):
if os.path.isdir(path):
yield path + '/'
else:
yield path


class ShellFuncAction(CompletionAction):
def __init__(self, ex, func):
self.ex = ex
Expand Down Expand Up @@ -780,7 +808,7 @@ def Init(readline_mod, pool, builtins, mem, funcs, comp_lookup, progress_f,

# NOTE: Need set_completer_delims to be space here? Otherwise you complete
# as --a and --n. Why?
comp_lookup.RegisterName('__default__', WordsAction(['-a', '-n']))
comp_lookup.RegisterName('__default__', FileSystemAction())

A1 = WordsAction(['foo.py', 'foo', 'bar.py'])
A2 = WordsAction(['m%d' % i for i in range(5)], delay=0.1)
Expand Down
31 changes: 31 additions & 0 deletions core/completion_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from osh import parse_lib

assign_op_e = ast.assign_op_e
log = util.log


A1 = completion.WordsAction(['foo.py', 'foo', 'bar.py'])
Expand Down Expand Up @@ -71,6 +72,36 @@ def testExternalCommandAction(self):
a = completion.ExternalCommandAction(mem)
print(list(a.Matches([], 0, 'f')))

def testFileSystemAction(self):
a = completion.FileSystemAction()
# Current dir -- all files and dirs
print(list(a.Matches([], 0, '')))

# This test depends on actual file system content. But we choose things
# that shouldn't go away.
CASES = [
# Dirs and files
('c', ['core/', 'configure']),
('nonexistent/', []),
('README', ['README.md']),
# Directory should be completed to core/ ?
('core', ['core/']),
('asdl/R', ['asdl/README.md']),
('opy/doc', ['opy/doc/']),
('opy/doc/', ['opy/doc/opcodes.md']),
]

for prefix, expected in CASES:
log('')
log('-- PREFIX %s', prefix)
log('-- expected %s', expected)
self.assertEqual(expected, list(a.Matches([], 0, prefix)))

print(list(a.Matches([], 0, './o')))

# A bunch of repos in oilshell
print(list(a.Matches([], 0, '../o')))

def testShellFuncExecution(self):
ex = cmd_exec_test.InitExecutor()
func_node = ast.FuncDef()
Expand Down

0 comments on commit ca9d0e4

Please sign in to comment.