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 dpdebugger import Debugger
|
||||||
from dataclasses import dataclass
|
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 math
|
||||||
|
import py_cui
|
||||||
|
import py_cui.keys
|
||||||
|
import re
|
||||||
|
import shlex
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SourceLines:
|
class SourceLines:
|
||||||
@ -14,12 +12,6 @@ class SourceLines:
|
|||||||
begining_number: int
|
begining_number: int
|
||||||
lines: list[str]
|
lines: list[str]
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class RichedSourceLines:
|
|
||||||
active: int
|
|
||||||
begining_number: int
|
|
||||||
lines: list[Text]
|
|
||||||
|
|
||||||
def _get_source_lines(
|
def _get_source_lines(
|
||||||
srcline: int,
|
srcline: int,
|
||||||
lines: list[str],
|
lines: list[str],
|
||||||
@ -49,61 +41,67 @@ def _get_source_lines(
|
|||||||
lines=list(lines[start_bound-1:end_bound])
|
lines=list(lines[start_bound-1:end_bound])
|
||||||
)
|
)
|
||||||
|
|
||||||
def _source_lines_to_rich(srclines: SourceLines) -> RichedSourceLines:
|
class DebuggerUI:
|
||||||
riched_lines = RichedSourceLines(
|
ACTIVE_LINE_POINTER = "~> "
|
||||||
active=srclines.active,
|
def __init__(self, master: py_cui.PyCUI, debugger: Debugger, src: str):
|
||||||
begining_number=srclines.begining_number,
|
self.master = master
|
||||||
lines=list(map(Text, srclines.lines))
|
self.dbg = debugger
|
||||||
)
|
self.src = src
|
||||||
active_index = srclines.active - srclines.begining_number
|
self.srclines = src.split('\n')[:-1]
|
||||||
active_line = riched_lines.lines[active_index]
|
self.source_panel = self.master.add_text_block(
|
||||||
active_line.stylize('bold red')
|
"Source code", 0, 0
|
||||||
return riched_lines
|
)
|
||||||
|
|
||||||
def _join_riched_lines(rl: RichedSourceLines) -> Text:
|
self.prompt_panel = self.master.add_text_box("Prompt",
|
||||||
return Text("\n").join(rl.lines)
|
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 _generate_source_lines(
|
def _process_prompt(self):
|
||||||
debugger: Debugger,
|
user_input = self.prompt_panel.get()
|
||||||
srcfile: str,
|
if user_input == "exit":
|
||||||
size: int
|
exit()
|
||||||
) -> Panel:
|
self.prompt_panel.clear()
|
||||||
sl = _get_source_lines(
|
dbg_output = self.dbg.do_command(user_input.split())
|
||||||
lines=srcfile.split('\n')[:-1],
|
self.terminal_panel.write(dbg_output)
|
||||||
max_height=size,
|
self._display_source_lines()
|
||||||
srcline=debugger.get_current_source_line_number()
|
|
||||||
)
|
def _display_source_lines(self):
|
||||||
rl = _source_lines_to_rich(sl)
|
active_line = self.dbg.get_current_source_line_number()
|
||||||
full = _join_riched_lines(rl)
|
lines = _get_source_lines(
|
||||||
return Panel(full)
|
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):
|
def main(debugger: Debugger, srcfile: str):
|
||||||
SRC_WIN_HEIGHT = 10
|
root = py_cui.PyCUI(3, 1)
|
||||||
layout = Layout()
|
root.set_title("Stupid DP32 debugger")
|
||||||
layout.split_column(
|
root.set_status_bar_text("")
|
||||||
Layout(
|
DebuggerUI(root, debugger, srcfile)
|
||||||
_generate_source_lines(debugger, srcfile, SRC_WIN_HEIGHT),
|
root.start()
|
||||||
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))
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user