summaryrefslogtreecommitdiff
path: root/internal/ui/input_helpers.go
blob: d1fdad6de28f73a1c87c07f9d967eef63d433c84 (plain)
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
124
125
126
127
128
129
package ui

import (
	"fmt"
	"strconv"

	tea "charm.land/bubbletea/v2"
	"github.com/charmbracelet/x/ansi"

	"codeberg.org/snonux/tasksamurai/internal/task"
)

// handleBlinkingState handles input when a task is blinking
func (m *Model) handleBlinkingState(msg tea.Msg) (tea.Model, tea.Cmd) {
	if _, ok := msg.(tea.KeyPressMsg); ok {
		if m.showUltra {
			return m.handleUltraBlinkingState(msg.(tea.KeyPressMsg))
		}

		// Only allow navigation while blinking.
		prevRow := m.tbl.Cursor()
		prevCol := m.tbl.ColumnCursor()
		var cmd tea.Cmd
		m.tbl, cmd = m.tbl.Update(msg)
		if prevRow != m.tbl.Cursor() || prevCol != m.tbl.ColumnCursor() {
			m.updateSelectionHighlight(prevRow, m.tbl.Cursor(), prevCol, m.tbl.ColumnCursor())
		}
		return m, cmd
	}
	return m, nil
}

func (m *Model) handleUltraBlinkingState(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
	switch msg.String() {
	case "j", "down":
		m.ultraMoveCursor(1)
	case "k", "up":
		m.ultraMoveCursor(-1)
	case "pgdn", "pgdown", "space":
		m.ultraMoveCursor(m.ultraVisibleCount())
	case "pgup", "b":
		m.ultraMoveCursor(-m.ultraVisibleCount())
	case "g", "home":
		m.ultraGoHome()
	case "G", "end":
		m.ultraGoEnd()
	}
	return m, nil
}

// handleEditingModes checks if we're in any editing mode and handles it
func (m *Model) handleEditingModes(msg tea.KeyPressMsg) (handled bool, model tea.Model, cmd tea.Cmd) {
	switch {
	case m.annotating:
		model, cmd = m.handleAnnotationMode(msg)
		return true, model, cmd
	case m.descEditing:
		model, cmd = m.handleDescriptionMode(msg)
		return true, model, cmd
	case m.tagsEditing:
		model, cmd = m.handleTagsMode(msg)
		return true, model, cmd
	case m.dueEditing:
		model, cmd = m.handleDueEditMode(msg)
		return true, model, cmd
	case m.recurEditing:
		model, cmd = m.handleRecurrenceMode(msg)
		return true, model, cmd
	case m.projEditing:
		model, cmd = m.handleProjectMode(msg)
		return true, model, cmd
	case m.prioritySelecting:
		model, cmd = m.handlePriorityMode(msg)
		return true, model, cmd
	case m.filterEditing:
		model, cmd = m.handleFilterMode(msg)
		return true, model, cmd
	case m.addingTask:
		model, cmd = m.handleAddTaskMode(msg)
		return true, model, cmd
	case m.searching:
		model, cmd = m.handleSearchMode(msg)
		return true, model, cmd
	case m.shellActive:
		model, cmd = m.handleShellMode(msg)
		return true, model, cmd
	case m.helpSearching:
		model, cmd = m.handleHelpSearchMode(msg)
		return true, model, cmd
	}
	return false, m, nil
}

// getSelectedTaskID extracts the task ID from the selected row
func (m *Model) getSelectedTaskID() (int, error) {
	row := m.tbl.SelectedRow()
	if row == nil {
		return 0, fmt.Errorf("no row selected")
	}
	idStr := ansi.Strip(row[1])
	return strconv.Atoi(idStr)
}

// getTaskAtCursor returns the task at the current cursor position
func (m *Model) getTaskAtCursor() *task.Task {
	cursor := m.tbl.Cursor()
	if cursor < 0 || cursor >= len(m.tasks) {
		return nil
	}
	return &m.tasks[cursor]
}

// getTaskForOpenURL returns the task that should be used by the open-URL
// hotkey, honoring the active view's highlighted task.
func (m *Model) getTaskForOpenURL() *task.Task {
	if m.showTaskDetail && m.currentTaskDetail != nil {
		return m.currentTaskDetail
	}

	if m.showUltra {
		tasks := m.ultraTaskList()
		if m.ultraCursor < 0 || m.ultraCursor >= len(tasks) {
			return nil
		}
		return &tasks[m.ultraCursor]
	}

	return m.getTaskAtCursor()
}