kitty/kitty_tests/completion.py
Kovid Goyal 3c29ce936b
Dont recurse for file completion
We could potentially end up recursing over the entire file system. And
for completion we only present the candidates in the immediate directory
anyway.
2022-11-14 15:41:57 +05:30

110 lines
3.3 KiB
Python

#!/usr/bin/env python
# License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net>
import json
import os
import shlex
import subprocess
import tempfile
from kitty.constants import kitty_tool_exe as kitty_tool
from . import BaseTest
class TestCompletion(BaseTest):
def test_completion(self):
with tempfile.TemporaryDirectory() as tdir:
completion(self, tdir)
def has_words(*words):
def t(self, result):
q = set(words)
for group in result.get('groups', ()):
for m in group['matches']:
if m['word'] in words:
q.discard(m['word'])
self.assertFalse(q, f'Command line: {self.current_cmd!r}')
return t
def all_words(*words):
def t(self, result):
expected = set(words)
actual = set()
for group in result.get('groups', ()):
for m in group['matches']:
actual.add(m['word'])
self.assertEqual(expected, actual, f'Command line: {self.current_cmd!r}')
return t
def completion(self: TestCompletion, tdir: str):
all_cmds = []
all_argv = []
all_tests = []
def add(cmdline: str, *tests):
all_cmds.append(cmdline)
new_word = cmdline.endswith(' ')
if new_word:
cmdline = cmdline[:-1]
all_argv.append(shlex.split(cmdline))
if new_word:
all_argv[-1].append('')
all_tests.append(tests)
def run_tool():
env = os.environ.copy()
env['PATH'] = os.path.join(tdir, 'bin')
env['HOME'] = os.path.join(tdir, 'sub')
cp = subprocess.run(
[kitty_tool(), '__complete__', 'json'],
check=True, stdout=subprocess.PIPE, cwd=tdir, input=json.dumps(all_argv).encode(), env=env
)
self.assertEqual(cp.returncode, 0, f'kitty-tool __complete__ failed with exit code: {cp.returncode}')
return json.loads(cp.stdout)
add('kitty ', has_words('@', '@ls'))
add('kitty @ l', has_words('ls', 'last-used-layout', 'launch'))
add('kitty @l', has_words('@ls', '@last-used-layout', '@launch'))
def make_file(path, mode=None):
with open(os.path.join(tdir, path), mode='x') as f:
if mode is not None:
os.chmod(f.fileno(), mode)
os.mkdir(os.path.join(tdir, 'bin'))
os.mkdir(os.path.join(tdir, 'sub'))
make_file('bin/exe1', 0o700)
make_file('bin/exe-not1')
make_file('exe2', 0o700)
make_file('exe-not2.jpeg')
make_file('sub/exe3', 0o700)
make_file('sub/exe-not3.png')
add('kitty x', all_words())
add('kitty e', all_words('exe1'))
add('kitty ./', all_words('./bin/', './sub/', './exe2'))
add('kitty ./e', all_words('./exe2'))
add('kitty ./s', all_words('./sub/'))
add('kitty ~', all_words('~/exe3'))
add('kitty ~/', all_words('~/exe3'))
add('kitty ~/e', all_words('~/exe3'))
add('kitty @ goto-layout ', has_words('tall', 'fat'))
add('kitty @ goto-layout spli', all_words('splits'))
add('kitty @ goto-layout f f', all_words())
add('kitty @ set-window-logo ', all_words('exe-not2.jpeg', 'sub/', 'bin/'))
add('kitty @ set-window-logo e', all_words('exe-not2.jpeg'))
add('kitty @ set-window-logo e e', all_words())
for cmd, tests, result in zip(all_cmds, all_tests, run_tool()):
self.current_cmd = cmd
for test in tests:
test(self, result)