feat(repl): add auto-completer

This commit is contained in:
2026-02-08 14:32:41 +01:00
parent 94a3e3cbe2
commit 218fb91053
3 changed files with 51 additions and 6 deletions

View File

View File

@@ -0,0 +1,38 @@
from typing import Optional
from src.interpreter.environment import Environment
from src.interpreter.interpreter import Interpreter
class Completer:
def __init__(self, interpreter: Interpreter):
self.interpreter: Interpreter = interpreter
self.options: list[str] = []
self.matches: 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 None
def update_matches(self, text: str):
self.options = []
env: Optional[Environment] = self.interpreter.env
while env is not None:
self.options.extend(env.values.keys())
env = env.enclosing
self.options = sorted(self.options)
if not text:
self.matches = self.options
else:
self.matches = [
opt
for opt in self.options
if opt.startswith(text)
]

View File

@@ -3,6 +3,7 @@ import readline
from pathlib import Path
from src.ast.stmt import Stmt
from src.completer.completer import Completer
from src.interpreter.interpreter import Interpreter
from src.interpreter.resolver import Resolver
from src.parser.parser import Parser
@@ -16,6 +17,8 @@ class REPL:
def __init__(self):
self.interpreter: Interpreter = Interpreter()
self.completer: Completer = Completer(self.interpreter)
self.buf: str = ""
@staticmethod
def greet():
@@ -38,6 +41,10 @@ class REPL:
atexit.register(save, h_len, self.HIST_FILE)
def init_completer(self):
readline.set_completer(self.completer.complete)
readline.parse_and_bind("tab: complete")
def run(self):
line: str
tokens: list[Token]
@@ -45,22 +52,22 @@ class REPL:
self.greet()
self.init_history()
self.init_completer()
buf: str = ""
while True:
try:
line = input(">>> " if len(buf) == 0 else "... ")
line = input(">>> " if len(self.buf) == 0 else "... ")
except EOFError:
print()
break
except KeyboardInterrupt:
buf = ""
self.buf = ""
print()
continue
buf += line + "\n"
self.buf += line + "\n"
try:
tokens = Lexer(buf).process()
tokens = Lexer(self.buf).process()
except:
continue
if Pebble.had_error:
@@ -71,7 +78,7 @@ class REPL:
continue
program = Parser(tokens).parse()
buf = ""
self.buf = ""
if Pebble.had_error:
Pebble.had_error = False