More work on completion for the SSH kitten
This commit is contained in:
parent
21ce0e90bf
commit
d8d5a8fada
@ -164,6 +164,14 @@ def get_kitten_cli_docs(kitten: str) -> Any:
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
def get_kitten_completer(kitten: str) -> Any:
|
||||||
|
run_kitten(kitten, run_name='__completer__')
|
||||||
|
ans = getattr(sys, 'kitten_completer', None)
|
||||||
|
if ans is not None:
|
||||||
|
delattr(sys, 'kitten_completer')
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def get_kitten_conf_docs(kitten: str) -> Definition:
|
def get_kitten_conf_docs(kitten: str) -> Definition:
|
||||||
setattr(sys, 'options_definition', None)
|
setattr(sys, 'options_definition', None)
|
||||||
run_kitten(kitten, run_name='__conf__')
|
run_kitten(kitten, run_name='__conf__')
|
||||||
|
|||||||
@ -5,10 +5,13 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Callable, Dict, Iterable, Iterator, Tuple
|
from typing import Callable, Dict, Iterable, Iterator, Sequence, Tuple
|
||||||
|
|
||||||
|
from kitty.complete import Completions, debug
|
||||||
from kitty.types import run_once
|
from kitty.types import run_once
|
||||||
|
|
||||||
|
debug
|
||||||
|
|
||||||
|
|
||||||
def lines_from_file(path: str) -> Iterator[str]:
|
def lines_from_file(path: str) -> Iterator[str]:
|
||||||
try:
|
try:
|
||||||
@ -97,3 +100,107 @@ def ssh_options() -> Dict[str, str]:
|
|||||||
else:
|
else:
|
||||||
ans.update(dict.fromkeys(q[1:], ''))
|
ans.update(dict.fromkeys(q[1:], ''))
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
# option help {{{
|
||||||
|
@run_once
|
||||||
|
def option_help_map() -> Dict[str, str]:
|
||||||
|
ans: Dict[str, str] = {}
|
||||||
|
lines = '''
|
||||||
|
-4 -- force ssh to use IPv4 addresses only
|
||||||
|
-6 -- force ssh to use IPv6 addresses only
|
||||||
|
-a -- disable forwarding of authentication agent connection
|
||||||
|
-A -- enable forwarding of the authentication agent connection
|
||||||
|
-B -- bind to specified interface before attempting to connect
|
||||||
|
-b -- specify interface to transmit on
|
||||||
|
-C -- compress data
|
||||||
|
-c -- select encryption cipher
|
||||||
|
-D -- specify a dynamic port forwarding
|
||||||
|
-E -- append log output to file instead of stderr
|
||||||
|
-e -- set escape character
|
||||||
|
-f -- go to background
|
||||||
|
-F -- specify alternate config file
|
||||||
|
-g -- allow remote hosts to connect to local forwarded ports
|
||||||
|
-G -- output configuration and exit
|
||||||
|
-i -- select identity file
|
||||||
|
-I -- specify smartcard device
|
||||||
|
-J -- connect via a jump host
|
||||||
|
-k -- disable forwarding of GSSAPI credentials
|
||||||
|
-K -- enable GSSAPI-based authentication and forwarding
|
||||||
|
-L -- specify local port forwarding
|
||||||
|
-l -- specify login name
|
||||||
|
-M -- master mode for connection sharing
|
||||||
|
-m -- specify mac algorithms
|
||||||
|
-N -- don't execute a remote command
|
||||||
|
-n -- redirect stdin from /dev/null
|
||||||
|
-O -- control an active connection multiplexing master process
|
||||||
|
-o -- specify extra options
|
||||||
|
-p -- specify port on remote host
|
||||||
|
-P -- use non privileged port
|
||||||
|
-Q -- query parameters
|
||||||
|
-q -- quiet operation
|
||||||
|
-R -- specify remote port forwarding
|
||||||
|
-s -- invoke subsystem
|
||||||
|
-S -- specify location of control socket for connection sharing
|
||||||
|
-T -- disable pseudo-tty allocation
|
||||||
|
-t -- force pseudo-tty allocation
|
||||||
|
-V -- show version number
|
||||||
|
-v -- verbose mode (multiple increase verbosity, up to 3)
|
||||||
|
-W -- forward standard input and output to host
|
||||||
|
-w -- request tunnel device forwarding
|
||||||
|
-x -- disable X11 forwarding
|
||||||
|
-X -- enable (untrusted) X11 forwarding
|
||||||
|
-Y -- enable trusted X11 forwarding
|
||||||
|
-y -- send log info via syslog instead of stderr
|
||||||
|
'''.splitlines()
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
if line:
|
||||||
|
parts = line.split(maxsplit=2)
|
||||||
|
ans[parts[0]] = parts[2]
|
||||||
|
return ans
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
def complete_arg(ans: Completions, option_name: str, prefix: str = '') -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def complete_destination(ans: Completions, prefix: str = '') -> None:
|
||||||
|
result = {k: '' for k in known_hosts() if k.startswith(prefix)}
|
||||||
|
ans.match_groups['remote host name'] = result
|
||||||
|
|
||||||
|
|
||||||
|
def complete_option(ans: Completions, prefix: str = '-') -> None:
|
||||||
|
result = {k: v for k, v in option_help_map().items() if k.startswith(prefix)}
|
||||||
|
ans.match_groups['option'] = result
|
||||||
|
|
||||||
|
|
||||||
|
def complete(ans: Completions, words: Sequence[str], new_word: bool) -> None:
|
||||||
|
options = ssh_options()
|
||||||
|
expecting_arg = False
|
||||||
|
types = ['' for i in range(len(words))]
|
||||||
|
for i, word in enumerate(words):
|
||||||
|
if expecting_arg:
|
||||||
|
types[i] = 'arg'
|
||||||
|
expecting_arg = False
|
||||||
|
continue
|
||||||
|
if word.startswith('-'):
|
||||||
|
types[i] = 'option'
|
||||||
|
if len(word) == 2 and options.get(word[1]):
|
||||||
|
expecting_arg = True
|
||||||
|
continue
|
||||||
|
types[i] = 'destination'
|
||||||
|
break
|
||||||
|
if new_word:
|
||||||
|
if words:
|
||||||
|
if expecting_arg:
|
||||||
|
return complete_arg(ans, words[-1])
|
||||||
|
return complete_destination(ans)
|
||||||
|
if words:
|
||||||
|
if types[-1] == 'arg' and len(words) > 1:
|
||||||
|
return complete_arg(ans, words[-2], words[-1])
|
||||||
|
if types[-1] == 'destination':
|
||||||
|
return complete_destination(ans, words[-1])
|
||||||
|
if words[-1] == '-':
|
||||||
|
return complete_option(ans)
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import List, NoReturn, Optional, Set, Tuple
|
from typing import List, NoReturn, Optional, Set, Tuple
|
||||||
from .completion import ssh_options
|
from .completion import ssh_options, complete
|
||||||
|
|
||||||
from kitty.utils import SSHConnectionData
|
from kitty.utils import SSHConnectionData
|
||||||
|
|
||||||
@ -272,3 +272,5 @@ def main(args: List[str]) -> NoReturn:
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main(sys.argv)
|
main(sys.argv)
|
||||||
|
elif __name__ == '__completer__':
|
||||||
|
setattr(sys, 'kitten_completer', complete)
|
||||||
|
|||||||
@ -9,7 +9,9 @@ from typing import (
|
|||||||
Any, Callable, Dict, Iterable, List, Optional, Sequence, Set, Tuple
|
Any, Callable, Dict, Iterable, List, Optional, Sequence, Set, Tuple
|
||||||
)
|
)
|
||||||
|
|
||||||
from kittens.runner import all_kitten_names, get_kitten_cli_docs
|
from kittens.runner import (
|
||||||
|
all_kitten_names, get_kitten_cli_docs, get_kitten_completer
|
||||||
|
)
|
||||||
|
|
||||||
from .cli import (
|
from .cli import (
|
||||||
OptionDict, OptionSpecSeq, options_for_completion, parse_option_spec
|
OptionDict, OptionSpecSeq, options_for_completion, parse_option_spec
|
||||||
@ -39,7 +41,7 @@ them into something your shell will understand.
|
|||||||
|
|
||||||
parsers: Dict[str, Callable] = {}
|
parsers: Dict[str, Callable] = {}
|
||||||
serializers: Dict[str, Callable] = {}
|
serializers: Dict[str, Callable] = {}
|
||||||
MathGroup = Dict[str, str]
|
MatchGroup = Dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
def debug(*a: Any, **kw: Any) -> None:
|
def debug(*a: Any, **kw: Any) -> None:
|
||||||
@ -69,7 +71,7 @@ class Delegate:
|
|||||||
class Completions:
|
class Completions:
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.match_groups: Dict[str, MathGroup] = {}
|
self.match_groups: Dict[str, MatchGroup] = {}
|
||||||
self.no_space_groups: Set[str] = set()
|
self.no_space_groups: Set[str] = set()
|
||||||
self.files_groups: Set[str] = set()
|
self.files_groups: Set[str] = set()
|
||||||
self.delegate: Delegate = Delegate()
|
self.delegate: Delegate = Delegate()
|
||||||
@ -450,6 +452,13 @@ def complete_diff_args(ans: Completions, opt: Optional[OptionDict], prefix: str,
|
|||||||
|
|
||||||
|
|
||||||
def complete_kitten(ans: Completions, kitten: str, words: Sequence[str], new_word: bool) -> None:
|
def complete_kitten(ans: Completions, kitten: str, words: Sequence[str], new_word: bool) -> None:
|
||||||
|
try:
|
||||||
|
completer = get_kitten_completer(kitten)
|
||||||
|
except SystemExit:
|
||||||
|
completer = None
|
||||||
|
if completer is not None:
|
||||||
|
completer(ans, words, new_word)
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
cd = get_kitten_cli_docs(kitten)
|
cd = get_kitten_cli_docs(kitten)
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user