feat(repl): group completions by scope and add keywords
This commit is contained in:
@@ -1,29 +1,39 @@
|
||||
from typing import Optional
|
||||
import os
|
||||
import readline
|
||||
import sys
|
||||
from typing import Optional, Sequence
|
||||
|
||||
from src.interpreter.environment import Environment
|
||||
from src.interpreter.interpreter import Interpreter
|
||||
from src.token.keyword import KEYWORDS
|
||||
|
||||
|
||||
class Completer:
|
||||
def __init__(self, interpreter: Interpreter):
|
||||
self.interpreter: Interpreter = interpreter
|
||||
self.options: list[str] = []
|
||||
self.matches: list[str] = []
|
||||
self.options: list[list[str]] = []
|
||||
self.matches: list[list[str]] = []
|
||||
|
||||
def complete(self, text: str, state: int) -> Optional[str]:
|
||||
if state == 0:
|
||||
self.update_matches(text)
|
||||
try:
|
||||
return self.matches[state]
|
||||
except IndexError:
|
||||
return self.get_match(state)
|
||||
|
||||
def get_match(self, state: int) -> Optional[str]:
|
||||
for grp in self.matches:
|
||||
if state < len(grp):
|
||||
return grp[state]
|
||||
state -= len(grp)
|
||||
return None
|
||||
|
||||
def update_matches(self, text: str):
|
||||
self.options = []
|
||||
self.options = [
|
||||
list(KEYWORDS.keys())
|
||||
]
|
||||
|
||||
env: Optional[Environment] = self.interpreter.env
|
||||
while env is not None:
|
||||
self.options.extend(env.values.keys())
|
||||
self.options.append(sorted(env.values.keys()))
|
||||
env = env.enclosing
|
||||
|
||||
self.options = sorted(self.options)
|
||||
@@ -32,7 +42,37 @@ class Completer:
|
||||
self.matches = self.options
|
||||
else:
|
||||
self.matches = [
|
||||
[
|
||||
opt
|
||||
for opt in self.options
|
||||
for opt in grp
|
||||
if opt.startswith(text)
|
||||
]
|
||||
for grp in self.options
|
||||
]
|
||||
self.matches = list(filter(lambda grp: grp, self.matches))
|
||||
|
||||
def display_matches(self, sub: str, matches: Sequence[str], longest_len: int):
|
||||
line_buf = readline.get_line_buffer()
|
||||
cols = os.get_terminal_size()[0]
|
||||
|
||||
for i, grp in enumerate(self.matches):
|
||||
print()
|
||||
self.display_group(grp, cols)
|
||||
|
||||
print(">>> ", end="")
|
||||
print(line_buf, end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
def display_group(self, group: list[str], cols: int):
|
||||
width: int = max(map(len, group))
|
||||
width = width * 6 // 5 + 2
|
||||
buf: str = ""
|
||||
for match in group:
|
||||
match = f"{match:{width}}"
|
||||
if len(buf) + width > cols:
|
||||
print(buf.rstrip())
|
||||
buf = ""
|
||||
buf += match
|
||||
|
||||
if buf:
|
||||
print(buf)
|
||||
|
||||
@@ -44,6 +44,7 @@ class REPL:
|
||||
def init_completer(self):
|
||||
readline.set_completer(self.completer.complete)
|
||||
readline.parse_and_bind("tab: complete")
|
||||
readline.set_completion_display_matches_hook(self.completer.display_matches)
|
||||
|
||||
def run(self):
|
||||
line: str
|
||||
|
||||
Reference in New Issue
Block a user