1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""pgt TUI application loop."""
from __future__ import annotations
from pathlib import Path
from unicurses import ( # type: ignore[import-untyped]
KEY_RESIZE,
cbreak,
clear,
curs_set,
endwin,
getch,
getmaxyx,
initscr,
keypad,
noecho,
refresh,
)
from pygittools.tui.git_colors import init_tui_color_theme, status_bar_attr
from pygittools.tui.pages.home import HomePage, home_page
from pygittools.tui.pages.no_repo import NoRepoPage
from pygittools.tui.repo import try_open_page_context
from pygittools.tui.status_bar import content_height, draw_status_bar
from pygittools.tui.tabs import init_tab_colors
from pygittools.tui.types import Page, PageAction, PageContext, PageResult
def run_tui(repo_path: Path | None = None) -> int:
start = (repo_path or Path.cwd()).resolve()
ctx = try_open_page_context(start)
initial: Page = home_page() if ctx is not None else NoRepoPage(start)
stack: list[Page] = [initial]
stdscr = initscr()
try:
noecho()
cbreak()
curs_set(0)
keypad(stdscr, True)
init_tui_color_theme(ctx.repo if ctx is not None else None)
init_tab_colors()
if ctx is not None:
stack[0].on_enter(ctx)
while stack:
page = stack[-1]
height, width = getmaxyx(stdscr)
clear()
page.draw(stdscr, content_height(height), width)
if height > 0:
draw_status_bar(height - 1, width, page.status_text(), status_bar_attr())
refresh()
try:
key = getch()
except KeyboardInterrupt:
break
if key == KEY_RESIZE:
continue
result = page.handle_key(key)
ctx, stack = _apply_result(stack, ctx, result)
if result.action == PageAction.QUIT:
break
except KeyboardInterrupt:
pass
finally:
_persist_commit_draft(stack, ctx)
endwin()
return 0
def _persist_commit_draft(stack: list[Page], ctx: PageContext | None) -> None:
if ctx is None:
return
for page in reversed(stack):
if isinstance(page, HomePage):
page.changes.persist_commit_draft(ctx.repo)
return
def _apply_result(
stack: list[Page],
ctx: PageContext | None,
result: PageResult,
) -> tuple[PageContext | None, list[Page]]:
if result.switch_repo is not None:
_persist_commit_draft(stack, ctx)
new_ctx = try_open_page_context(result.switch_repo)
if new_ctx is not None:
ctx = new_ctx
init_tui_color_theme(ctx.repo)
init_tab_colors()
match result.action:
case PageAction.REPLACE:
if result.next_page is None:
return ctx, stack
if ctx is not None:
result.next_page.on_enter(ctx)
return ctx, [result.next_page]
case PageAction.PUSH:
if result.next_page is None:
return ctx, stack
if ctx is not None:
result.next_page.on_enter(ctx)
return ctx, [*stack, result.next_page]
case PageAction.POP:
if len(stack) <= 1:
return ctx, stack
stack = stack[:-1]
case _:
pass
if result.switch_repo is not None and ctx is not None and stack:
stack[-1].on_enter(ctx)
return ctx, stack