@@ -34,24 +34,26 @@ import (
35// appModel represents the main application model that manages pages, dialogs, and UI state.
35// appModel represents the main application model that manages pages, dialogs, and UI state.
36type appModel struct {
36type appModel struct {
37+ wWidth, wHeight int // Window dimensions
37− width, height int
38+ width, height int
38− keyMap KeyMap
39+ keyMap KeyMap
40 currentPage page.PageID
41 currentPage page.PageID
41 previousPage page.PageID
42 previousPage page.PageID
42 pages map[page.PageID]util.Model
43 pages map[page.PageID]util.Model
43 loadedPages map[page.PageID]bool
44 loadedPages map[page.PageID]bool
45− status status.StatusCmp
47+ status status.StatusCmp
47 app *app.App
50 app *app.App
49 dialog dialogs.DialogCmp
52 dialog dialogs.DialogCmp
50 completions completions.Completions
53 completions completions.Completions
52− // Session
55+ // Chat Page Specific
53 selectedSessionID string // The ID of the currently selected session
56 selectedSessionID string // The ID of the currently selected session
54− fullHelp bool // Whether to show full help text
57// Init initializes the application model and returns initial commands.
59// Init initializes the application model and returns initial commands.
@@ -99,7 +101,7 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
100 return a, nil
102 return a, nil
101 case tea.WindowSizeMsg:
103 case tea.WindowSizeMsg:
102− return a, a.handleWindowResize(msg)
104+ return a, a.handleWindowResize(msg.Width, msg.Height)
104 // Completions messages
106 // Completions messages
105 case completions.OpenCompletionsMsg, completions.FilterCompletionsMsg, completions.CloseCompletionsMsg:
107 case completions.OpenCompletionsMsg, completions.FilterCompletionsMsg, completions.CloseCompletionsMsg:
@@ -244,23 +246,29 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
246// handleWindowResize processes window resize events and updates all components.
248// handleWindowResize processes window resize events and updates all components.
247−func (a *appModel) handleWindowResize(msg tea.WindowSizeMsg) tea.Cmd {
249+func (a *appModel) handleWindowResize(width, height int) tea.Cmd {
248 var cmds []tea.Cmd
250 var cmds []tea.Cmd
249− msg.Height -= 2 // Make space for the status bar
251+ a.wWidth, a.wHeight = width, height
252+ if a.showingFullHelp {
250− a.width, a.height = msg.Width, msg.Height
257+ a.width, a.height = width, height
252 // Update status bar
258 // Update status bar
253− s, cmd := a.status.Update(msg)
259+ s, cmd := a.status.Update(tea.WindowSizeMsg{Width: width, Height: height})
254 a.status = s.(status.StatusCmp)
260 a.status = s.(status.StatusCmp)
255 cmds = append(cmds, cmd)
261 cmds = append(cmds, cmd)
257 // Update the current page
263 // Update the current page
258− updated, cmd := a.pages[a.currentPage].Update(msg)
264+ for p, page := range a.pages {
265+ updated, pageCmd := page.Update(tea.WindowSizeMsg{Width: width, Height: height})
259− a.pages[a.currentPage] = updated.(util.Model)
266+ a.pages[p] = updated.(util.Model)
260− cmds = append(cmds, cmd)
267+ cmds = append(cmds, pageCmd)
262 // Update the dialogs
270 // Update the dialogs
263− dialog, cmd := a.dialog.Update(msg)
271+ dialog, cmd := a.dialog.Update(tea.WindowSizeMsg{Width: width, Height: height})
264 a.dialog = dialog.(dialogs.DialogCmp)
272 a.dialog = dialog.(dialogs.DialogCmp)
265 cmds = append(cmds, cmd)
273 cmds = append(cmds, cmd)
@@ -288,6 +296,11 @@ func (a *appModel) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd {
288 u, cmd := a.completions.Update(msg)
296 u, cmd := a.completions.Update(msg)
289 a.completions = u.(completions.Completions)
297 a.completions = u.(completions.Completions)
290 return cmd
298 return cmd
300+ case key.Matches(msg, a.keyMap.Help):
301+ a.status.ToggleFullHelp()
302+ a.showingFullHelp = !a.showingFullHelp
303+ return a.handleWindowResize(a.wWidth, a.wHeight)
291 // dialogs
304 // dialogs
292 case key.Matches(msg, a.keyMap.Quit):
305 case key.Matches(msg, a.keyMap.Quit):
293 if a.dialog.ActiveDialogID() == quit.QuitDialogID {
306 if a.dialog.ActiveDialogID() == quit.QuitDialogID {
@@ -345,7 +358,7 @@ func (a *appModel) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd {
345// moveToPage handles navigation between different pages in the application.
358// moveToPage handles navigation between different pages in the application.
346func (a *appModel) moveToPage(pageID page.PageID) tea.Cmd {
359func (a *appModel) moveToPage(pageID page.PageID) tea.Cmd {
347 if a.app.CoderAgent.IsBusy() {
360 if a.app.CoderAgent.IsBusy() {
348− // For now we don't move to any page if the agent is busy
361+ // TODO: maybe remove this : For now we don't move to any page if the agent is busy
349 return util.ReportWarn("Agent is busy, please wait...")
362 return util.ReportWarn("Agent is busy, please wait...")
@@ -367,7 +380,12 @@ func (a *appModel) moveToPage(pageID page.PageID) tea.Cmd {
368// View renders the complete application interface including pages, dialogs, and overlays.
381// View renders the complete application interface including pages, dialogs, and overlays.
369func (a *appModel) View() tea.View {
382func (a *appModel) View() tea.View {
370− pageView := a.pages[a.currentPage].View()
383+ page := a.pages[a.currentPage]
384+ if withHelp, ok := page.(layout.Help); ok {
385+ a.keyMap.pageBindings = withHelp.Bindings()
387+ a.status.SetKeyMap(a.keyMap)
388+ pageView := page.View()
371 components := []string{
389 components := []string{
372 pageView.String(),
390 pageView.String(),
@@ -412,17 +430,20 @@ func (a *appModel) View() tea.View {
413// New creates and initializes a new TUI application model.
431// New creates and initializes a new TUI application model.
414func New(app *app.App) tea.Model {
432func New(app *app.App) tea.Model {
415− startPage := chat.ChatPage
433+ chatPage := chat.NewChatPage(app)
434+ keyMap := DefaultKeyMap()
435+ keyMap.pageBindings = chatPage.Bindings()
416 model := &appModel{
437 model := &appModel{
417− currentPage: startPage,
438+ currentPage: chat.ChatPageID,
418 app: app,
439 app: app,
419− status: status.NewStatusCmp(),
440+ status: status.NewStatusCmp(keyMap),
420 loadedPages: make(map[page.PageID]bool),
441 loadedPages: make(map[page.PageID]bool),
421− keyMap: DefaultKeyMap(),
442+ keyMap: keyMap,
423 pages: map[page.PageID]util.Model{
444 pages: map[page.PageID]util.Model{
424− chat.ChatPage: chat.NewChatPage(app),
445+ chat.ChatPageID: chatPage,
425− logs.LogsPage: logs.NewLogsPage(),
446+ logs.LogsPage: logs.NewLogsPage(),
428 dialog: dialogs.NewDialogCmp(),
449 dialog: dialogs.NewDialogCmp(),