mirror of
https://github.com/wagoodman/dive
synced 2026-03-14 14:25:50 +01:00
refactor: улучшить обработку сообщений и оптимизировать код в различных компонентах
This commit is contained in:
parent
3d7953fca0
commit
db2639edf2
11 changed files with 48 additions and 54 deletions
|
|
@ -264,7 +264,6 @@ func (m *Model) recalculateLayout() {
|
|||
// Update implements tea.Model
|
||||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmds []tea.Cmd
|
||||
var handled bool // Track if message was already handled
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
|
|
@ -290,7 +289,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
cmds = append(cmds, cmd)
|
||||
}
|
||||
}
|
||||
handled = true
|
||||
|
||||
// Global key bindings
|
||||
switch msg.String() {
|
||||
|
|
@ -392,7 +390,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
m.panes[PaneTree] = newTree
|
||||
}
|
||||
m.updateTreeForCurrentLayer()
|
||||
handled = true
|
||||
|
||||
case filetreepane.NodeToggledMsg:
|
||||
// Forward message to tree pane to refresh its visibleNodes cache
|
||||
|
|
@ -403,14 +400,12 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
newPane, cmd := m.panes[PaneTree].Update(msg)
|
||||
m.panes[PaneTree] = newPane
|
||||
cmds = append(cmds, cmd)
|
||||
handled = true
|
||||
|
||||
case filetreepane.RefreshTreeContentMsg:
|
||||
// Request to refresh tree content
|
||||
// POLYMORPHISM: Send message through interface, no type assertion
|
||||
newPane, _ := m.panes[PaneTree].Update(filetreepane.UpdateViewModelMsg{TreeVM: m.treeVM})
|
||||
m.panes[PaneTree] = newPane
|
||||
handled = true
|
||||
|
||||
case tea.MouseMsg:
|
||||
// BUBBLEZONE: Check which pane was clicked using zone hit testing
|
||||
|
|
@ -455,7 +450,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
break
|
||||
}
|
||||
}
|
||||
handled = true
|
||||
|
||||
case tea.WindowSizeMsg:
|
||||
m.width = msg.Width
|
||||
|
|
@ -483,19 +477,15 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
layoutCmds = append(layoutCmds, cmd)
|
||||
}
|
||||
cmds = append(cmds, layoutCmds...)
|
||||
handled = true
|
||||
|
||||
default:
|
||||
// Forward all OTHER messages (e.g., tickMsg from CopiableValue timers)
|
||||
// to the active pane. This is critical for component internal timers to work.
|
||||
// Without this, messages from child components are lost.
|
||||
// IMPORTANT: Only forward if not already handled above to prevent double-processing
|
||||
if !handled {
|
||||
if activePane, ok := m.panes[m.activePane]; ok {
|
||||
updatedPane, cmd := activePane.Update(msg)
|
||||
m.panes[m.activePane] = updatedPane
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
if activePane, ok := m.panes[m.activePane]; ok {
|
||||
updatedPane, cmd := activePane.Update(msg)
|
||||
m.panes[m.activePane] = updatedPane
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -851,6 +841,10 @@ func (m Model) updateSearch(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
// Empty pattern - clear filter
|
||||
m.totalMatches = 0
|
||||
m.currentMatch = -1
|
||||
|
||||
// CRITICAL: Apply empty filter to reset UI state
|
||||
// This disables Flat mode, removes layer highlighting, and clears file highlighting
|
||||
m.applyFilter("")
|
||||
}
|
||||
|
||||
return m, cmd
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package components
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
|
@ -112,7 +113,7 @@ func (c CopiableValue) View() string {
|
|||
// Pad icon to match the original value width
|
||||
paddingNeeded := c.width - visualWidth
|
||||
if paddingNeeded > 0 {
|
||||
iconText = iconText + strings.Repeat(" ", paddingNeeded)
|
||||
iconText += strings.Repeat(" ", paddingNeeded)
|
||||
}
|
||||
}
|
||||
return lipgloss.NewStyle().
|
||||
|
|
@ -137,7 +138,7 @@ func (c CopiableValue) View() string {
|
|||
// Pad with spaces on the right to match exact width
|
||||
paddingNeeded := c.width - textWidth
|
||||
if paddingNeeded > 0 {
|
||||
text = text + strings.Repeat(" ", paddingNeeded)
|
||||
text += strings.Repeat(" ", paddingNeeded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -166,21 +167,22 @@ func (c CopiableValue) GetVisualWidth() int {
|
|||
func copyToClipboard(text string) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
var cmd *exec.Cmd
|
||||
ctx := context.Background()
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
cmd = exec.Command("pbcopy")
|
||||
cmd = exec.CommandContext(ctx, "pbcopy")
|
||||
case "linux":
|
||||
// Try xclip first, then wl-copy, then xsel
|
||||
if _, err := exec.LookPath("xclip"); err == nil {
|
||||
cmd = exec.Command("xclip", "-selection", "clipboard")
|
||||
cmd = exec.CommandContext(ctx, "xclip", "-selection", "clipboard")
|
||||
} else if _, err := exec.LookPath("wl-copy"); err == nil {
|
||||
cmd = exec.Command("wl-copy")
|
||||
cmd = exec.CommandContext(ctx, "wl-copy")
|
||||
} else if _, err := exec.LookPath("xsel"); err == nil {
|
||||
cmd = exec.Command("xsel", "--clipboard", "--input")
|
||||
cmd = exec.CommandContext(ctx, "xsel", "--clipboard", "--input")
|
||||
}
|
||||
case "windows":
|
||||
cmd = exec.Command("clip")
|
||||
cmd = exec.CommandContext(ctx, "clip")
|
||||
}
|
||||
|
||||
if cmd != nil {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// Package details provides the file details pane for displaying information about selected files.
|
||||
package details
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
[TestPane_View_WithTree - 1]
|
||||
┌─Current Layer Contents─────────────────────────┐
|
||||
│Name Size UID:GID│
|
||||
│├─ bin -│
|
||||
│├─ bin 1.1M -│
|
||||
││ ├─ [ 1.0M -│
|
||||
││ ├─ [[ 0 -│
|
||||
││ ├─ acpid 0 -│
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
[TestPane_View_Focused - 1]
|
||||
┌─Current Layer Contents─────────────────────────┐
|
||||
│Name Size UID:GID│
|
||||
│├─ bin -│
|
||||
│├─ bin 1.1M -│
|
||||
││ ├─ [ 1.0M -│
|
||||
││ ├─ [[ 0 -│
|
||||
││ ├─ acpid 0 -│
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
[TestPane_View_SmallHeight - 1]
|
||||
┌─Current Layer Contents─────────────────────────┐
|
||||
│Name Size UID:GID│
|
||||
│├─ bin -│
|
||||
│├─ bin 1.1M -│
|
||||
││ ├─ [ 1.0M -│
|
||||
││ ├─ [[ 0 -│
|
||||
││ ├─ acpid 0 -│
|
||||
|
|
@ -105,7 +105,7 @@
|
|||
[TestPane_View_LargeSize - 1]
|
||||
┌─Current Layer Contents───────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│Name Size UID:GID Permissions│
|
||||
│├─ bin - drwxr-xr-x│
|
||||
│├─ bin 1.1M - drwxr-xr-x│
|
||||
││ ├─ [ 1.0M - -rwxr-xr-x│
|
||||
││ ├─ [[ 0 - -rwxr-xr-x│
|
||||
││ ├─ acpid 0 - -rwxr-xr-x│
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
[TestPane_Update_WithLayoutMsg - 1]
|
||||
┌─Current Layer Contents─────────────────────────┐
|
||||
│Name Size UID:GID│
|
||||
│├─ bin -│
|
||||
│├─ bin 1.1M -│
|
||||
││ ├─ [ 1.0M -│
|
||||
││ ├─ [[ 0 -│
|
||||
││ ├─ acpid 0 -│
|
||||
|
|
|
|||
|
|
@ -62,8 +62,11 @@ func RenderRow(node *filetree.FileNode, prefix string, displayName string, isSel
|
|||
var sizeStr, uidGid, perm string
|
||||
|
||||
// Only compute strings if they will be shown (optimization)
|
||||
if showSize && !node.Data.FileInfo.IsDir() {
|
||||
size := node.Data.FileInfo.Size
|
||||
if showSize {
|
||||
// Use node.GetSize() for both files and directories
|
||||
// For files: returns the file size
|
||||
// For directories: recursively calculates total size of all children
|
||||
size := node.GetSize()
|
||||
if size >= 0 {
|
||||
sizeStr = utils.FormatSize(uint64(size))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package filetree
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
|
|
@ -355,7 +356,7 @@ func (p *Pane) Update(msg tea.Msg) (common.Pane, tea.Cmd) {
|
|||
p.copyNoticePath = msg.Path
|
||||
// copiedNodeIndex is already set by the right-click handler
|
||||
// Hide notification after 2 seconds
|
||||
return p, tea.Tick(2*time.Second, func(t time.Time) tea.Msg {
|
||||
return p, tea.Tick(2*time.Second, func(_ time.Time) tea.Msg {
|
||||
return HideCopyNoticeMsg{}
|
||||
})
|
||||
}
|
||||
|
|
@ -811,21 +812,22 @@ func (p *Pane) setExclusiveFilter(filterType string) {
|
|||
func copyPathToClipboard(path string) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
var cmd *exec.Cmd
|
||||
ctx := context.Background()
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
cmd = exec.Command("pbcopy")
|
||||
cmd = exec.CommandContext(ctx, "pbcopy")
|
||||
case "linux":
|
||||
// Try xclip first, then wl-copy, then xsel
|
||||
if _, err := exec.LookPath("xclip"); err == nil {
|
||||
cmd = exec.Command("xclip", "-selection", "clipboard")
|
||||
cmd = exec.CommandContext(ctx, "xclip", "-selection", "clipboard")
|
||||
} else if _, err := exec.LookPath("wl-copy"); err == nil {
|
||||
cmd = exec.Command("wl-copy")
|
||||
cmd = exec.CommandContext(ctx, "wl-copy")
|
||||
} else if _, err := exec.LookPath("xsel"); err == nil {
|
||||
cmd = exec.Command("xsel", "--clipboard", "--input")
|
||||
cmd = exec.CommandContext(ctx, "xsel", "--clipboard", "--input")
|
||||
}
|
||||
case "windows":
|
||||
cmd = exec.Command("clip")
|
||||
cmd = exec.CommandContext(ctx, "clip")
|
||||
}
|
||||
|
||||
if cmd != nil {
|
||||
|
|
|
|||
|
|
@ -179,11 +179,12 @@ func (m *Pane) generateContent() string {
|
|||
header.WriteString(styles.LayerHeaderStyle.Render("Image efficiency score:"))
|
||||
header.WriteString(" ")
|
||||
scoreStyle := styles.LayerValueStyle
|
||||
if stats.EfficiencyScore >= 90 {
|
||||
switch {
|
||||
case stats.EfficiencyScore >= 90:
|
||||
scoreStyle = scoreStyle.Foreground(styles.SuccessColor)
|
||||
} else if stats.EfficiencyScore >= 70 {
|
||||
case stats.EfficiencyScore >= 70:
|
||||
scoreStyle = scoreStyle.Foreground(styles.HighlightColor)
|
||||
} else {
|
||||
default:
|
||||
scoreStyle = scoreStyle.Foreground(styles.WarningColor)
|
||||
}
|
||||
header.WriteString(scoreStyle.Render(fmt.Sprintf("%.0f%%", stats.EfficiencyScore)))
|
||||
|
|
|
|||
|
|
@ -653,17 +653,8 @@ func (m *Pane) generateContent() string {
|
|||
matchStyle := lipgloss.NewStyle().
|
||||
Foreground(styles.HighlightColor).
|
||||
Bold(true)
|
||||
|
||||
// If this row is also selected, we need to be careful about styling
|
||||
// to avoid color conflicts with the selection background
|
||||
if i == m.layerIndex {
|
||||
// For selected row, keep the highlight color but it may blend with selection
|
||||
// The selection background (PanelBgColor) should work with yellow text
|
||||
prefix = matchStyle.Render(prefixStr)
|
||||
} else {
|
||||
// Normal row - just apply highlight
|
||||
prefix = matchStyle.Render(prefixStr)
|
||||
}
|
||||
// Apply highlight style (works for both selected and normal rows)
|
||||
prefix = matchStyle.Render(prefixStr)
|
||||
} else {
|
||||
// No matches - use normal styling
|
||||
if i == m.layerIndex {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// Package utils provides utility functions for formatting values used throughout the UI.
|
||||
package utils
|
||||
|
||||
import "fmt"
|
||||
|
|
|
|||
4
go.mod
4
go.mod
|
|
@ -3,6 +3,8 @@ module github.com/wagoodman/dive
|
|||
go 1.24.2
|
||||
|
||||
require (
|
||||
charm.land/bubbles/v2 v2.0.0-rc.1
|
||||
charm.land/bubbletea/v2 v2.0.0-rc.1.0.20251106192006-06c0cda318b3
|
||||
github.com/anchore/clio v0.0.0-20250401141128-4c1d6bd1e872
|
||||
github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722
|
||||
github.com/awesome-gocui/gocui v1.1.0
|
||||
|
|
@ -37,8 +39,6 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
charm.land/bubbles/v2 v2.0.0-rc.1 // indirect
|
||||
charm.land/bubbletea/v2 v2.0.0-rc.1.0.20251106192006-06c0cda318b3 // indirect
|
||||
charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106192539-4b304240aab7 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||
|
|
|
|||
7
go.sum
7
go.sum
|
|
@ -31,8 +31,8 @@ github.com/awesome-gocui/keybinding v1.0.1-0.20211011072933-86029037a63f/go.mod
|
|||
github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc/go.mod h1:tOy3o5Nf1bA17mnK4W41gD7PS3u4Cv0P0pqFcoWMy8s=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||
github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY=
|
||||
github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
|
|
@ -51,9 +51,8 @@ github.com/charmbracelet/x/ansi v0.11.3 h1:6DcVaqWI82BBVM/atTyq6yBoRLZFBsnoDoX9G
|
|||
github.com/charmbracelet/x/ansi v0.11.3/go.mod h1:yI7Zslym9tCJcedxz5+WBq+eUGMJT0bM06Fqy1/Y4dI=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
|
||||
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
|
||||
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
||||
github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue