feat(repl): add auto-completer
This commit is contained in:
0
src/completer/__init__.py
Normal file
0
src/completer/__init__.py
Normal file
38
src/completer/completer.py
Normal file
38
src/completer/completer.py
Normal 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)
|
||||||
|
]
|
||||||
19
src/repl.py
19
src/repl.py
@@ -3,6 +3,7 @@ import readline
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from src.ast.stmt import Stmt
|
from src.ast.stmt import Stmt
|
||||||
|
from src.completer.completer import Completer
|
||||||
from src.interpreter.interpreter import Interpreter
|
from src.interpreter.interpreter import Interpreter
|
||||||
from src.interpreter.resolver import Resolver
|
from src.interpreter.resolver import Resolver
|
||||||
from src.parser.parser import Parser
|
from src.parser.parser import Parser
|
||||||
@@ -16,6 +17,8 @@ class REPL:
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.interpreter: Interpreter = Interpreter()
|
self.interpreter: Interpreter = Interpreter()
|
||||||
|
self.completer: Completer = Completer(self.interpreter)
|
||||||
|
self.buf: str = ""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def greet():
|
def greet():
|
||||||
@@ -38,6 +41,10 @@ class REPL:
|
|||||||
|
|
||||||
atexit.register(save, h_len, self.HIST_FILE)
|
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):
|
def run(self):
|
||||||
line: str
|
line: str
|
||||||
tokens: list[Token]
|
tokens: list[Token]
|
||||||
@@ -45,22 +52,22 @@ class REPL:
|
|||||||
|
|
||||||
self.greet()
|
self.greet()
|
||||||
self.init_history()
|
self.init_history()
|
||||||
|
self.init_completer()
|
||||||
|
|
||||||
buf: str = ""
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
line = input(">>> " if len(buf) == 0 else "... ")
|
line = input(">>> " if len(self.buf) == 0 else "... ")
|
||||||
except EOFError:
|
except EOFError:
|
||||||
print()
|
print()
|
||||||
break
|
break
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
buf = ""
|
self.buf = ""
|
||||||
print()
|
print()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
buf += line + "\n"
|
self.buf += line + "\n"
|
||||||
try:
|
try:
|
||||||
tokens = Lexer(buf).process()
|
tokens = Lexer(self.buf).process()
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
if Pebble.had_error:
|
if Pebble.had_error:
|
||||||
@@ -71,7 +78,7 @@ class REPL:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
program = Parser(tokens).parse()
|
program = Parser(tokens).parse()
|
||||||
buf = ""
|
self.buf = ""
|
||||||
|
|
||||||
if Pebble.had_error:
|
if Pebble.had_error:
|
||||||
Pebble.had_error = False
|
Pebble.had_error = False
|
||||||
|
|||||||
Reference in New Issue
Block a user