-
Notifications
You must be signed in to change notification settings - Fork 3
Add search function within patch viewer #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ package tui | |
| import ( | ||
| "fmt" | ||
| "log" | ||
| "regexp" | ||
| "strconv" | ||
| "strings" | ||
| "time" | ||
|
|
@@ -150,6 +151,12 @@ type compareSide struct { | |
| ver string // "v1", "v2", etc. | ||
| } | ||
|
|
||
| type searchMatch struct { | ||
| lineIdx int | ||
| start int | ||
| end int | ||
| } | ||
|
|
||
| func highlightAnimTickCmd() tea.Cmd { | ||
| return tea.Tick( | ||
| time.Duration(highlightAnimInterval)*time.Millisecond, | ||
|
|
@@ -215,18 +222,25 @@ type Model struct { | |
| renderBuf strings.Builder // reused by renderMainView each frame | ||
| gradientBuf strings.Builder // reused by renderGradientRow each frame | ||
|
|
||
| viewMode viewMode | ||
| viewingPatchID int | ||
| viewingCoverID int | ||
| viewComments []CommentInfo | ||
| viewCommentIdx int // -1 = patch/cover, 0+ = comment | ||
| viewSourceLines map[string]bool | ||
| viewportLines []string | ||
| viewportLoading bool | ||
| viewportOffset int | ||
| viewExpanded bool | ||
| listPrefix string | ||
| delegateNames map[string]string | ||
| viewMode viewMode | ||
| viewingPatchID int | ||
| viewingCoverID int | ||
| viewComments []CommentInfo | ||
| viewCommentIdx int // -1 = patch/cover, 0+ = comment | ||
| viewSourceLines map[string]bool | ||
| viewportLines []string | ||
| viewportLoading bool | ||
| viewportOffset int | ||
| viewExpanded bool | ||
| searching bool | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| searchText string | ||
| searchRegex *regexp.Regexp | ||
| searchMatches []searchMatch | ||
| searchIdx int | ||
| searchHistory []string | ||
| searchHistoryIdx int // -1 = typing new query, 0+ = browsing history | ||
| listPrefix string | ||
| delegateNames map[string]string | ||
|
|
||
| compare [2]compareSide | ||
| compareCount int // 0, 1, or 2 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,10 +69,10 @@ func (m *Model) renderPatchView() string { | |
| end = total | ||
| } | ||
|
|
||
| // Assemble exactly `visible` lines separated by newlines. | ||
| lines := make([]string, visible) | ||
| for i := 0; i < end-start; i++ { | ||
| lines[i] = m.viewportLines[start+i] | ||
| lineIdx := start + i | ||
| lines[i] = m.highlightLineIfMatched(m.viewportLines[lineIdx], lineIdx) | ||
| } | ||
| body := strings.Join(lines, "\n") | ||
|
|
||
|
|
@@ -85,47 +85,55 @@ func (m *Model) renderPatchView() string { | |
| bright, desc, sep := m.helpStyles() | ||
|
|
||
| var status string | ||
| expandKey := func(hb *strings.Builder) { | ||
| hb.WriteString(helpSepStr(sep)) | ||
| if m.viewExpanded { | ||
| hb.WriteString(helpKey(bright, desc, "e", "collapse")) | ||
| } else { | ||
| hb.WriteString(helpKey(bright, desc, "e", "expand")) | ||
| } | ||
| } | ||
| if len(m.viewComments) > 0 { | ||
| var hb strings.Builder | ||
| hb.WriteString(sep.Render(" ")) | ||
| hb.WriteString(bright.Render("←/→")) | ||
| expandKey(&hb) | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(bright.Render("↑/↓") + | ||
| sep.Render(" ") + bright.Render("pgup/dn")) | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(bright.Render("esc")) | ||
| if m.logConsole { | ||
|
|
||
| if m.searching { | ||
| status = m.renderSearchInputHelp(bright, desc, sep) | ||
| } else { | ||
| expandKey := func(hb *strings.Builder) { | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(helpKey(bright, desc, "tab", "log")) | ||
| if m.viewExpanded { | ||
| hb.WriteString(helpKey(bright, desc, "e", "collapse")) | ||
| } else { | ||
| hb.WriteString(helpKey(bright, desc, "e", "expand")) | ||
| } | ||
| } | ||
| hb.WriteString(desc.Render(fmt.Sprintf(" %d%%", pct))) | ||
| helpText := hb.String() | ||
| barWidth := m.width - lipgloss.Width(helpText) | ||
| commentBar := m.renderCommentBar(barWidth) | ||
| status = commentBar + helpText | ||
| } else { | ||
| var hb strings.Builder | ||
| expandKey(&hb) | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(bright.Render("↑/↓") + | ||
| sep.Render(" ") + bright.Render("pgup/dn")) | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(helpKey(bright, desc, "esc", "back")) | ||
| if m.logConsole { | ||
|
|
||
| if len(m.viewComments) > 0 { | ||
| var hb strings.Builder | ||
| hb.WriteString(sep.Render(" ")) | ||
| hb.WriteString(bright.Render("←/→")) | ||
| expandKey(&hb) | ||
| hb.WriteString(m.renderSearchKeyHelp(bright, desc, sep)) | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(helpKey(bright, desc, "tab", "log")) | ||
| hb.WriteString(bright.Render("↑/↓") + | ||
| sep.Render(" ") + bright.Render("pgup/dn")) | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(bright.Render("esc")) | ||
| if m.logConsole { | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(helpKey(bright, desc, "tab", "log")) | ||
| } | ||
| hb.WriteString(desc.Render(fmt.Sprintf(" %d%%", pct))) | ||
| helpText := hb.String() | ||
| barWidth := m.width - lipgloss.Width(helpText) | ||
| commentBar := m.renderCommentBar(barWidth) | ||
| status = commentBar + helpText | ||
| } else { | ||
| var hb strings.Builder | ||
| expandKey(&hb) | ||
| hb.WriteString(m.renderSearchKeyHelp(bright, desc, sep)) | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(bright.Render("↑/↓") + | ||
| sep.Render(" ") + bright.Render("pgup/dn")) | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(helpKey(bright, desc, "esc", "back")) | ||
| if m.logConsole { | ||
| hb.WriteString(helpSepStr(sep)) | ||
| hb.WriteString(helpKey(bright, desc, "tab", "log")) | ||
| } | ||
| hb.WriteString(desc.Render(fmt.Sprintf(" %d%%", pct))) | ||
| status = hb.String() | ||
| } | ||
| hb.WriteString(desc.Render(fmt.Sprintf(" %d%%", pct))) | ||
| status = hb.String() | ||
| } | ||
|
|
||
| var statusLine string | ||
|
|
@@ -172,6 +180,10 @@ func (m *Model) renderCompareView() string { | |
| compareDiffKind(m.compare[0].kinds, idx)) | ||
| right = comparePadLine(right, rightWidth, | ||
| compareDiffKind(m.compare[1].kinds, idx)) | ||
|
|
||
| left = m.highlightLineIfMatched(left, idx) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, if the match is only on one side (left or right) but not on the other we'll try to highlight on both sides and fail for the side that doesn't have the match. But does that mean that we'd also potentially scroll incorrectly? Shouldn't the searchMatches be part of the Which means, shouldn't we have a let's call it
Maybe that will also remove the need for the slightly unnatural |
||
| right = m.highlightLineIfMatched(right, idx) | ||
|
|
||
| lines[i] = left + sep + right | ||
| } | ||
| body := strings.Join(lines, "\n") | ||
|
|
@@ -183,29 +195,36 @@ func (m *Model) renderCompareView() string { | |
| } | ||
|
|
||
| bright, desc, sepS := m.helpStyles() | ||
| var hb strings.Builder | ||
| labelL := comparePositionLabel( | ||
| m.compare[0].idx, len(m.compare[0].patches), m.compare[0].ver) | ||
| labelR := comparePositionLabel( | ||
| m.compare[1].idx, len(m.compare[1].patches), m.compare[1].ver) | ||
| hb.WriteString(desc.Render(labelL + " vs " + labelR)) | ||
| hb.WriteString(helpSepStr(sepS)) | ||
| hb.WriteString(bright.Render("←/→")) | ||
| hb.WriteString(helpSepStr(sepS)) | ||
| hb.WriteString(helpKey(bright, desc, "1/2+←/→", "single")) | ||
| hb.WriteString(helpSepStr(sepS)) | ||
| if m.viewExpanded { | ||
| hb.WriteString(helpKey(bright, desc, "e", "collapse")) | ||
|
|
||
| var helpText string | ||
| if m.searching { | ||
| helpText = m.renderSearchInputHelp(bright, desc, sepS) | ||
| } else { | ||
| hb.WriteString(helpKey(bright, desc, "e", "expand")) | ||
| } | ||
| hb.WriteString(helpSepStr(sepS)) | ||
| hb.WriteString(bright.Render("↑/↓") + | ||
| sepS.Render(" ") + bright.Render("pgup/dn")) | ||
| hb.WriteString(helpSepStr(sepS)) | ||
| hb.WriteString(helpKey(bright, desc, "esc", "back")) | ||
| hb.WriteString(desc.Render(fmt.Sprintf(" %d%%", pct))) | ||
| helpText := hb.String() | ||
| var hb strings.Builder | ||
| labelL := comparePositionLabel( | ||
| m.compare[0].idx, len(m.compare[0].patches), m.compare[0].ver) | ||
| labelR := comparePositionLabel( | ||
| m.compare[1].idx, len(m.compare[1].patches), m.compare[1].ver) | ||
| hb.WriteString(desc.Render(labelL + " vs " + labelR)) | ||
| hb.WriteString(helpSepStr(sepS)) | ||
| hb.WriteString(bright.Render("←/→")) | ||
| hb.WriteString(helpSepStr(sepS)) | ||
| hb.WriteString(helpKey(bright, desc, "1/2+←/→", "single")) | ||
| hb.WriteString(helpSepStr(sepS)) | ||
| if m.viewExpanded { | ||
| hb.WriteString(helpKey(bright, desc, "e", "collapse")) | ||
| } else { | ||
| hb.WriteString(helpKey(bright, desc, "e", "expand")) | ||
| } | ||
| hb.WriteString(m.renderSearchKeyHelp(bright, desc, sepS)) | ||
| hb.WriteString(helpSepStr(sepS)) | ||
| hb.WriteString(bright.Render("↑/↓") + | ||
| sepS.Render(" ") + bright.Render("pgup/dn")) | ||
| hb.WriteString(helpSepStr(sepS)) | ||
| hb.WriteString(helpKey(bright, desc, "esc", "back")) | ||
| hb.WriteString(desc.Render(fmt.Sprintf(" %d%%", pct))) | ||
| helpText = hb.String() | ||
| } | ||
|
|
||
| var statusLine string | ||
| msg, spinning := m.Status.Active() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Should all this search related state be part of a separate group of fields, lower. I mean, it applies to the compare mode too and that has its own separate section of fields.