feat(repl): group completions by scope and add keywords

This commit is contained in:
2026-02-08 14:48:14 +01:00
parent 218fb91053
commit e1f70e6f7f
2 changed files with 53 additions and 12 deletions

View File

@@ -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)

View File

@@ -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