Skip to content

Commit 080cd74

Browse files
feat: implement core application model, add Lua engine support, and enable tag filtering with jump-to-top binding
1 parent 9bac7b1 commit 080cd74

6 files changed

Lines changed: 78 additions & 47 deletions

File tree

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.2.4]
9+
10+
### Added
11+
12+
* **Vim Navigation**: Added support for `gg` in Vim Mode to instantly jump to the top of the task list, complementing the existing `G` shortcut for bottom navigation.
13+
14+
### Fixed
15+
16+
* **Help Footer Bug**: Resolved a bug where the "Show Help Footer" setting (in both `config.toml` and the settings menu) was being ignored. The footer now correctly hides help keybinding pills when disabled, providing more vertical space for task lists while still retaining critical action prompts (like delete/quit confirmation) for improved usability.
17+
18+
### Changed
19+
20+
* **Keybinding Refinement**: Removed the legacy hardcoded `g` shortcut for plugin reloading in the main list view, as it conflicted with Vim mode navigation. Plugin management remains accessible via the dedicated plugin menu and command palette.
21+
822
## [1.2.3]
923

1024
### Added

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ When enabled, the following classic Vim keys are activated for list navigation:
299299
- `j`: Move selection down
300300
- `k`: Move selection up
301301
- `G`: Jump to the bottom of the list
302+
- `gg`: Jump to the top of the list
302303

303304
*Note: Standard arrow keys, `pgup`/`pgdown`, and `home`/`end` remain functional regardless of this setting.*
304305

VERSION.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.2.3
1+
1.2.4

internal/app/model.go

Lines changed: 40 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -855,18 +855,6 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
855855
return m, m.viewTransitionTickCmd()
856856
}
857857

858-
// Plugin reload - single character keybinding only valid in ModeList
859-
if km.String() == "g" && m.mode == ModeList {
860-
if m.plugHost != nil {
861-
_ = m.plugHost.LoadAll()
862-
m.rebuildViews()
863-
m.rebuildPaletteIndex()
864-
m.statusText = "Plugins reloaded"
865-
m.isErr = false
866-
return m, m.loadTasksCmd()
867-
}
868-
}
869-
870858
if m.mode == ModeList {
871859
// Dynamic view switching (1-9)
872860
if len(km.String()) == 1 && km.String() >= "1" && km.String() <= "9" {
@@ -1343,6 +1331,7 @@ func (m *Model) renderFooter() string {
13431331
}
13441332

13451333
left := ""
1334+
// Critical prompts are always shown regardless of ShowHelp setting
13461335
switch m.mode {
13471336
case ModeConfirmDelete:
13481337
delLeft := lipgloss.NewStyle().Foreground(m.s.Theme.Bad).Background(m.s.Theme.Bg).Render("")
@@ -1356,40 +1345,46 @@ func (m *Model) renderFooter() string {
13561345
left = " " + quitPill + " " + makePill("y/enter confirm") + sep + makePill("n/esc cancel")
13571346
case ModeTagFilter:
13581347
left = " " + makePill("enter apply") + sep + makePill("esc cancel") + sep + makePill("ctrl+u clear")
1359-
case ModeDetail:
1360-
items := []string{
1361-
makePill(fk(m.km.Back) + " " + styles.IconBack + "back"),
1362-
makePill(fk(m.km.EditTask) + " " + styles.IconEdit + "edit"),
1363-
makePill(fk(m.km.Palette) + " " + styles.IconPalette + "palette"),
1364-
makePill(fk(m.km.Help) + " " + styles.IconHelp + "help"),
1365-
makePill(fk(m.km.Issues) + " " + styles.IconIssues + "issues"),
1366-
makePill(fk(m.km.Discussions) + " " + styles.IconDiscuss + "discussions"),
1367-
makePill(fk(m.km.Changelog) + " " + styles.IconChangelog + "changelog"),
1368-
}
1369-
left = " " + strings.Join(items, sep)
1370-
case ModeEditor:
1371-
left = " " + makePill("ctrl+s save") + sep + makePill("esc cancel") + sep + makePill("tab nav")
1372-
case ModePalette:
1373-
left = " " + makePill("enter select") + sep + makePill("esc/p cancel") + sep + makePill(styles.IconUp+styles.IconDown+" nav")
1374-
case ModeHelp:
1375-
left = " " + makePill("esc/q/"+fk(m.km.Help)+" cancel")
1376-
case ModeThemeMenu:
1377-
left = " " + makePill("enter select") + sep + makePill("esc/q/"+fk(m.km.CycleTheme)+" cancel") + sep + makePill(styles.IconUp+styles.IconDown+" nav")
1378-
case ModeSettings:
1379-
left = " " + makePill("esc/ctrl+s close") + sep + makePill("enter toggle") + sep + makePill(styles.IconUp+styles.IconDown+" nav")
1380-
case ModePluginMenu:
1381-
left = " " + makePill("enter detail") + sep + makePill("u uninstall") + sep + makePill("o open") + sep + makePill("r reload") + sep + makePill("p/"+fk(m.km.ManagePlugins)+" cancel")
13821348
default:
1383-
items := []string{
1384-
makePill(fk(m.km.Palette) + " " + styles.IconPalette + "palette"),
1385-
makePill(fk(m.km.NewTask) + " " + styles.IconNew + "new"),
1386-
makePill("f " + styles.IconTag + "tag"),
1387-
makePill(fk(m.km.ToggleStrike) + " " + styles.IconStrike + "done"),
1388-
makePill(fk(m.km.DeleteTask) + " " + styles.IconDelete + "delete"),
1389-
makePill(fk(m.km.Settings) + " settings"),
1390-
makePill(fk(m.km.Help) + " " + styles.IconHelp + "help"),
1391-
}
1392-
left = " " + strings.Join(items, sep)
1349+
// Only show help pills if ShowHelp is enabled in config
1350+
if m.cfg.App.ShowHelp {
1351+
switch m.mode {
1352+
case ModeDetail:
1353+
items := []string{
1354+
makePill(fk(m.km.Back) + " " + styles.IconBack + "back"),
1355+
makePill(fk(m.km.EditTask) + " " + styles.IconEdit + "edit"),
1356+
makePill(fk(m.km.Palette) + " " + styles.IconPalette + "palette"),
1357+
makePill(fk(m.km.Help) + " " + styles.IconHelp + "help"),
1358+
makePill(fk(m.km.Issues) + " " + styles.IconIssues + "issues"),
1359+
makePill(fk(m.km.Discussions) + " " + styles.IconDiscuss + "discussions"),
1360+
makePill(fk(m.km.Changelog) + " " + styles.IconChangelog + "changelog"),
1361+
}
1362+
left = " " + strings.Join(items, sep)
1363+
case ModeEditor:
1364+
left = " " + makePill("ctrl+s save") + sep + makePill("esc cancel") + sep + makePill("tab nav")
1365+
case ModePalette:
1366+
left = " " + makePill("enter select") + sep + makePill("esc/p cancel") + sep + makePill(styles.IconUp+styles.IconDown+" nav")
1367+
case ModeHelp:
1368+
left = " " + makePill("esc/q/"+fk(m.km.Help)+" cancel")
1369+
case ModeThemeMenu:
1370+
left = " " + makePill("enter select") + sep + makePill("esc/q/"+fk(m.km.CycleTheme)+" cancel") + sep + makePill(styles.IconUp+styles.IconDown+" nav")
1371+
case ModeSettings:
1372+
left = " " + makePill("esc/ctrl+s close") + sep + makePill("enter toggle") + sep + makePill(styles.IconUp+styles.IconDown+" nav")
1373+
case ModePluginMenu:
1374+
left = " " + makePill("enter detail") + sep + makePill("u uninstall") + sep + makePill("o open") + sep + makePill("r reload") + sep + makePill("p/"+fk(m.km.ManagePlugins)+" cancel")
1375+
default:
1376+
items := []string{
1377+
makePill(fk(m.km.Palette) + " " + styles.IconPalette + "palette"),
1378+
makePill(fk(m.km.NewTask) + " " + styles.IconNew + "new"),
1379+
makePill("f " + styles.IconTag + "tag"),
1380+
makePill(fk(m.km.ToggleStrike) + " " + styles.IconStrike + "done"),
1381+
makePill(fk(m.km.DeleteTask) + " " + styles.IconDelete + "delete"),
1382+
makePill(fk(m.km.Settings) + " settings"),
1383+
makePill(fk(m.km.Help) + " " + styles.IconHelp + "help"),
1384+
}
1385+
left = " " + strings.Join(items, sep)
1386+
}
1387+
}
13931388
}
13941389

13951390
right := ""

internal/lua/engine.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func (e *Engine) SetupKairoAPI(L *lua.LState) {
5555
L.SetField(kairo, "notify", L.NewFunction(e.luaNotify))
5656

5757
// Meta
58-
L.SetField(kairo, "version", lua.LString("1.2.3"))
58+
L.SetField(kairo, "version", lua.LString("1.2.4"))
5959

6060
// Set as global
6161
L.SetGlobal("kairo", kairo)

internal/ui/tasklist/model.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ type Model struct {
4141

4242
DeletingTaskID string
4343
DeleteProgress float64
44+
45+
lastKey string // For tracking key sequences like 'gg'
4446
}
4547

4648
func New(s styles.Styles, vimMode bool, km keymap.Keymap) Model {
@@ -90,38 +92,57 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
9092
case tea.KeyMsg:
9193
switch x.String() {
9294
case "up", "k":
95+
m.lastKey = ""
9396
if x.String() == "k" && !m.vimMode {
9497
break
9598
}
9699
if m.sel > 0 {
97100
m.sel--
98101
}
99102
case "down", "j":
103+
m.lastKey = ""
100104
if x.String() == "j" && !m.vimMode {
101105
break
102106
}
103107
if m.sel < len(m.tasks)-1 {
104108
m.sel++
105109
}
106110
case "pgup":
111+
m.lastKey = ""
107112
m.sel -= max(1, m.height-4)
108113
if m.sel < 0 {
109114
m.sel = 0
110115
}
111116
case "pgdown":
117+
m.lastKey = ""
112118
m.sel += max(1, m.height-4)
113119
if m.sel > len(m.tasks)-1 {
114120
m.sel = len(m.tasks) - 1
115121
}
116122
case "home":
123+
m.lastKey = ""
117124
m.sel = 0
118125
case "end", "G":
126+
m.lastKey = ""
119127
if x.String() == "G" && !m.vimMode {
120128
break
121129
}
122130
if len(m.tasks) > 0 {
123131
m.sel = len(m.tasks) - 1
124132
}
133+
case "g":
134+
if !m.vimMode {
135+
break
136+
}
137+
if m.lastKey == "g" {
138+
m.sel = 0
139+
m.lastKey = ""
140+
} else {
141+
m.lastKey = "g"
142+
return m, nil // Don't reset lastKey yet
143+
}
144+
default:
145+
m.lastKey = ""
125146
}
126147
}
127148
return m, nil

0 commit comments

Comments
 (0)