feat: заменен фреймворк для написания TUI, написана первая рабочая версия TUI
This commit is contained in:
130
src/dbg_tui.py
130
src/dbg_tui.py
@ -1,12 +1,10 @@
|
||||
from dpdebugger import Debugger
|
||||
from dataclasses import dataclass
|
||||
from rich import print as rprint
|
||||
from rich.layout import Layout
|
||||
from rich.prompt import Prompt
|
||||
from rich.panel import Panel
|
||||
from rich.text import Text
|
||||
from rich.console import Console
|
||||
import math
|
||||
import py_cui
|
||||
import py_cui.keys
|
||||
import re
|
||||
import shlex
|
||||
|
||||
@dataclass
|
||||
class SourceLines:
|
||||
@ -14,12 +12,6 @@ class SourceLines:
|
||||
begining_number: int
|
||||
lines: list[str]
|
||||
|
||||
@dataclass
|
||||
class RichedSourceLines:
|
||||
active: int
|
||||
begining_number: int
|
||||
lines: list[Text]
|
||||
|
||||
def _get_source_lines(
|
||||
srcline: int,
|
||||
lines: list[str],
|
||||
@ -49,61 +41,67 @@ def _get_source_lines(
|
||||
lines=list(lines[start_bound-1:end_bound])
|
||||
)
|
||||
|
||||
def _source_lines_to_rich(srclines: SourceLines) -> RichedSourceLines:
|
||||
riched_lines = RichedSourceLines(
|
||||
active=srclines.active,
|
||||
begining_number=srclines.begining_number,
|
||||
lines=list(map(Text, srclines.lines))
|
||||
)
|
||||
active_index = srclines.active - srclines.begining_number
|
||||
active_line = riched_lines.lines[active_index]
|
||||
active_line.stylize('bold red')
|
||||
return riched_lines
|
||||
class DebuggerUI:
|
||||
ACTIVE_LINE_POINTER = "~> "
|
||||
def __init__(self, master: py_cui.PyCUI, debugger: Debugger, src: str):
|
||||
self.master = master
|
||||
self.dbg = debugger
|
||||
self.src = src
|
||||
self.srclines = src.split('\n')[:-1]
|
||||
self.source_panel = self.master.add_text_block(
|
||||
"Source code", 0, 0
|
||||
)
|
||||
|
||||
self.prompt_panel = self.master.add_text_box("Prompt",
|
||||
1, 0,
|
||||
row_span=1
|
||||
)
|
||||
self.prompt_panel.add_key_command(py_cui.keys.KEY_ENTER, self._process_prompt)
|
||||
self.terminal_panel = self.master.add_text_block("Debugger Console",
|
||||
2, 0,
|
||||
initial_text="to exit type in \"exit\""
|
||||
)
|
||||
self.master.move_focus(self.prompt_panel)
|
||||
self.master.add_key_command(
|
||||
py_cui.keys.KEY_ENTER,
|
||||
lambda: self.master.move_focus(self.prompt_panel)
|
||||
)
|
||||
self._display_source_lines()
|
||||
|
||||
def _join_riched_lines(rl: RichedSourceLines) -> Text:
|
||||
return Text("\n").join(rl.lines)
|
||||
def _process_prompt(self):
|
||||
user_input = self.prompt_panel.get()
|
||||
if user_input == "exit":
|
||||
exit()
|
||||
self.prompt_panel.clear()
|
||||
dbg_output = self.dbg.do_command(user_input.split())
|
||||
self.terminal_panel.write(dbg_output)
|
||||
self._display_source_lines()
|
||||
|
||||
def _generate_source_lines(
|
||||
debugger: Debugger,
|
||||
srcfile: str,
|
||||
size: int
|
||||
) -> Panel:
|
||||
sl = _get_source_lines(
|
||||
lines=srcfile.split('\n')[:-1],
|
||||
max_height=size,
|
||||
srcline=debugger.get_current_source_line_number()
|
||||
)
|
||||
rl = _source_lines_to_rich(sl)
|
||||
full = _join_riched_lines(rl)
|
||||
return Panel(full)
|
||||
def _display_source_lines(self):
|
||||
active_line = self.dbg.get_current_source_line_number()
|
||||
lines = _get_source_lines(
|
||||
srcline=active_line,
|
||||
lines=self.srclines,
|
||||
max_height=self.source_panel.get_viewport_height()
|
||||
)
|
||||
# emplace line lumbers
|
||||
linenos = [lines.begining_number + i
|
||||
for i in range(len(lines.lines))]
|
||||
lines_with_linenos: list[str] =[]
|
||||
# длина самого большого числа для вычисления выравнивания
|
||||
align_with = len(str(linenos[-1]))
|
||||
for lineno, line in zip(linenos, lines.lines):
|
||||
if lineno == lines.active:
|
||||
padding = len(line) - len(stripped := line.lstrip(" "))
|
||||
line = self.ACTIVE_LINE_POINTER.rjust(padding) + stripped
|
||||
lines_with_linenos.append(
|
||||
f"{str(lineno).rjust(align_with)}. {line}"
|
||||
)
|
||||
self.source_panel.set_text("\n".join(lines_with_linenos))
|
||||
|
||||
def main(debugger: Debugger, srcfile: str):
|
||||
SRC_WIN_HEIGHT = 10
|
||||
layout = Layout()
|
||||
layout.split_column(
|
||||
Layout(
|
||||
_generate_source_lines(debugger, srcfile, SRC_WIN_HEIGHT),
|
||||
size=SRC_WIN_HEIGHT,
|
||||
name="source"),
|
||||
Layout(name="terminal")
|
||||
)
|
||||
layout["source"].update(_generate_source_lines(
|
||||
debugger=debugger,
|
||||
srcfile=srcfile,
|
||||
size=SRC_WIN_HEIGHT
|
||||
))
|
||||
|
||||
print()
|
||||
rprint(layout)
|
||||
|
||||
if __name__ == "__main__":
|
||||
console = Console()
|
||||
with open("test.dasm", 'r') as f:
|
||||
lines = f.read().split('\n')[:-1]
|
||||
srclines = _get_source_lines(22, lines, 7)
|
||||
riched = _source_lines_to_rich(srclines)
|
||||
print(f"focus: {srclines.active}; start: {srclines.begining_number}")
|
||||
print("_"*20)
|
||||
# rprint(*riched.lines, sep="\n")
|
||||
rprint(_join_riched_lines(riched))
|
||||
|
||||
root = py_cui.PyCUI(3, 1)
|
||||
root.set_title("Stupid DP32 debugger")
|
||||
root.set_status_bar_text("")
|
||||
DebuggerUI(root, debugger, srcfile)
|
||||
root.start()
|
||||
|
||||
Reference in New Issue
Block a user