mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-21 01:34:22 +01:00
Improve diff display with colored formatting in permission dialogs
- Add colored formatting for diff display (green for additions, red for removals) - Create a dedicated formatDiff function to handle diff styling - Restructure permission dialog render function for better organization - Apply custom styling to different line types in diffs 🤖 Generated with termai Co-Authored-By: termai <noreply@termai.io>
This commit is contained in:
@@ -65,6 +65,45 @@ type permissionDialogCmp struct {
|
|||||||
selectOption *huh.Select[string]
|
selectOption *huh.Select[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// formatDiff formats a diff string with colors for additions and deletions
|
||||||
|
func formatDiff(diffText string) string {
|
||||||
|
lines := strings.Split(diffText, "\n")
|
||||||
|
var formattedLines []string
|
||||||
|
|
||||||
|
// Define styles for different line types
|
||||||
|
addStyle := lipgloss.NewStyle().Foreground(styles.Green)
|
||||||
|
removeStyle := lipgloss.NewStyle().Foreground(styles.Red)
|
||||||
|
headerStyle := lipgloss.NewStyle().Bold(true).Foreground(styles.Blue)
|
||||||
|
contextStyle := lipgloss.NewStyle().Foreground(styles.SubText0)
|
||||||
|
|
||||||
|
// Process each line
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.HasPrefix(line, "+") {
|
||||||
|
formattedLines = append(formattedLines, addStyle.Render(line))
|
||||||
|
} else if strings.HasPrefix(line, "-") {
|
||||||
|
formattedLines = append(formattedLines, removeStyle.Render(line))
|
||||||
|
} else if strings.HasPrefix(line, "Changes:") || strings.HasPrefix(line, " ...") {
|
||||||
|
formattedLines = append(formattedLines, headerStyle.Render(line))
|
||||||
|
} else if strings.HasPrefix(line, " ") {
|
||||||
|
formattedLines = append(formattedLines, contextStyle.Render(line))
|
||||||
|
} else {
|
||||||
|
formattedLines = append(formattedLines, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all formatted lines
|
||||||
|
content := strings.Join(formattedLines, "\n")
|
||||||
|
|
||||||
|
// Create a bordered box for the content
|
||||||
|
contentStyle := lipgloss.NewStyle().
|
||||||
|
MarginTop(1).
|
||||||
|
Padding(0, 1).
|
||||||
|
Border(lipgloss.RoundedBorder()).
|
||||||
|
BorderForeground(styles.Flamingo)
|
||||||
|
|
||||||
|
return contentStyle.Render(content)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *permissionDialogCmp) Init() tea.Cmd {
|
func (p *permissionDialogCmp) Init() tea.Cmd {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -132,34 +171,24 @@ func (p *permissionDialogCmp) render() string {
|
|||||||
lipgloss.JoinHorizontal(lipgloss.Left, keyStyle.Render("Path:"), " ", valueStyle.Render(p.permission.Path)),
|
lipgloss.JoinHorizontal(lipgloss.Left, keyStyle.Render("Path:"), " ", valueStyle.Render(p.permission.Path)),
|
||||||
" ",
|
" ",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the header content first so it can be used in all cases
|
||||||
|
headerContent := lipgloss.NewStyle().Padding(0, 1).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...))
|
||||||
|
|
||||||
r, _ := glamour.NewTermRenderer(
|
r, _ := glamour.NewTermRenderer(
|
||||||
glamour.WithStyles(styles.CatppuccinMarkdownStyle()),
|
glamour.WithStyles(styles.CatppuccinMarkdownStyle()),
|
||||||
glamour.WithWordWrap(p.width-10),
|
glamour.WithWordWrap(p.width-10),
|
||||||
glamour.WithEmoji(),
|
glamour.WithEmoji(),
|
||||||
)
|
)
|
||||||
content := ""
|
|
||||||
|
// Handle different tool types
|
||||||
switch p.permission.ToolName {
|
switch p.permission.ToolName {
|
||||||
case tools.BashToolName:
|
case tools.BashToolName:
|
||||||
pr := p.permission.Params.(tools.BashPermissionsParams)
|
pr := p.permission.Params.(tools.BashPermissionsParams)
|
||||||
headerParts = append(headerParts, keyStyle.Render("Command:"))
|
headerParts = append(headerParts, keyStyle.Render("Command:"))
|
||||||
content = fmt.Sprintf("```bash\n%s\n```", pr.Command)
|
content := fmt.Sprintf("```bash\n%s\n```", pr.Command)
|
||||||
case tools.EditToolName:
|
|
||||||
pr := p.permission.Params.(tools.EditPermissionsParams)
|
|
||||||
headerParts = append(headerParts, keyStyle.Render("Update"))
|
|
||||||
content = fmt.Sprintf("```\n%s\n```", pr.Diff)
|
|
||||||
case tools.WriteToolName:
|
|
||||||
pr := p.permission.Params.(tools.WritePermissionsParams)
|
|
||||||
headerParts = append(headerParts, keyStyle.Render("Content"))
|
|
||||||
content = fmt.Sprintf("```\n%s\n```", pr.Content)
|
|
||||||
case tools.FetchToolName:
|
|
||||||
pr := p.permission.Params.(tools.FetchPermissionsParams)
|
|
||||||
headerParts = append(headerParts, keyStyle.Render("URL: "+pr.URL))
|
|
||||||
default:
|
|
||||||
content = p.permission.Description
|
|
||||||
}
|
|
||||||
|
|
||||||
renderedContent, _ := r.Render(content)
|
renderedContent, _ := r.Render(content)
|
||||||
headerContent := lipgloss.NewStyle().Padding(0, 1).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...))
|
|
||||||
p.contentViewPort.Width = p.width - 2 - 2
|
p.contentViewPort.Width = p.width - 2 - 2
|
||||||
|
|
||||||
// Calculate content height dynamically based on content
|
// Calculate content height dynamically based on content
|
||||||
@@ -168,8 +197,6 @@ func (p *permissionDialogCmp) render() string {
|
|||||||
minContentHeight := 3
|
minContentHeight := 3
|
||||||
maxContentHeight := p.height - lipgloss.Height(headerContent) - lipgloss.Height(form) - 2 - 2 - 1
|
maxContentHeight := p.height - lipgloss.Height(headerContent) - lipgloss.Height(form) - 2 - 2 - 1
|
||||||
|
|
||||||
// For bash commands, adjust height based on content length
|
|
||||||
if p.permission.ToolName == tools.BashToolName {
|
|
||||||
// Add some padding to the content lines
|
// Add some padding to the content lines
|
||||||
contentHeight := contentLines + 2
|
contentHeight := contentLines + 2
|
||||||
if contentHeight < minContentHeight {
|
if contentHeight < minContentHeight {
|
||||||
@@ -179,14 +206,10 @@ func (p *permissionDialogCmp) render() string {
|
|||||||
contentHeight = maxContentHeight
|
contentHeight = maxContentHeight
|
||||||
}
|
}
|
||||||
p.contentViewPort.Height = contentHeight
|
p.contentViewPort.Height = contentHeight
|
||||||
} else {
|
|
||||||
// For other content types, use the full available height
|
|
||||||
p.contentViewPort.Height = maxContentHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
p.contentViewPort.SetContent(renderedContent)
|
p.contentViewPort.SetContent(renderedContent)
|
||||||
|
|
||||||
// Make focus change more apparent with different border styles and colors
|
// Style the viewport
|
||||||
var contentBorder lipgloss.Border
|
var contentBorder lipgloss.Border
|
||||||
var borderColor lipgloss.TerminalColor
|
var borderColor lipgloss.TerminalColor
|
||||||
|
|
||||||
@@ -208,6 +231,60 @@ func (p *permissionDialogCmp) render() string {
|
|||||||
contentStyle = contentStyle.BorderBackground(styles.Surface0)
|
contentStyle = contentStyle.BorderBackground(styles.Surface0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contentFinal := contentStyle.Render(p.contentViewPort.View())
|
||||||
|
|
||||||
|
return lipgloss.JoinVertical(
|
||||||
|
lipgloss.Top,
|
||||||
|
headerContent,
|
||||||
|
contentFinal,
|
||||||
|
form,
|
||||||
|
)
|
||||||
|
|
||||||
|
case tools.EditToolName:
|
||||||
|
pr := p.permission.Params.(tools.EditPermissionsParams)
|
||||||
|
headerParts = append(headerParts, keyStyle.Render("Update"))
|
||||||
|
// Recreate header content with the updated headerParts
|
||||||
|
headerContent = lipgloss.NewStyle().Padding(0, 1).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...))
|
||||||
|
// Format the diff with colors instead of using markdown code block
|
||||||
|
formattedDiff := formatDiff(pr.Diff)
|
||||||
|
return lipgloss.JoinVertical(
|
||||||
|
lipgloss.Top,
|
||||||
|
headerContent,
|
||||||
|
formattedDiff,
|
||||||
|
form,
|
||||||
|
)
|
||||||
|
|
||||||
|
case tools.WriteToolName:
|
||||||
|
pr := p.permission.Params.(tools.WritePermissionsParams)
|
||||||
|
headerParts = append(headerParts, keyStyle.Render("Content"))
|
||||||
|
// Recreate header content with the updated headerParts
|
||||||
|
headerContent = lipgloss.NewStyle().Padding(0, 1).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...))
|
||||||
|
// Format the diff with colors instead of using markdown code block
|
||||||
|
formattedDiff := formatDiff(pr.Content)
|
||||||
|
return lipgloss.JoinVertical(
|
||||||
|
lipgloss.Top,
|
||||||
|
headerContent,
|
||||||
|
formattedDiff,
|
||||||
|
form,
|
||||||
|
)
|
||||||
|
|
||||||
|
case tools.FetchToolName:
|
||||||
|
pr := p.permission.Params.(tools.FetchPermissionsParams)
|
||||||
|
headerParts = append(headerParts, keyStyle.Render("URL: "+pr.URL))
|
||||||
|
content := p.permission.Description
|
||||||
|
|
||||||
|
renderedContent, _ := r.Render(content)
|
||||||
|
p.contentViewPort.Width = p.width - 2 - 2
|
||||||
|
p.contentViewPort.Height = p.height - lipgloss.Height(headerContent) - lipgloss.Height(form) - 2 - 2 - 1
|
||||||
|
p.contentViewPort.SetContent(renderedContent)
|
||||||
|
|
||||||
|
// Style the viewport
|
||||||
|
contentStyle := lipgloss.NewStyle().
|
||||||
|
MarginTop(1).
|
||||||
|
Padding(0, 1).
|
||||||
|
Border(lipgloss.RoundedBorder()).
|
||||||
|
BorderForeground(styles.Flamingo)
|
||||||
|
|
||||||
contentFinal := contentStyle.Render(p.contentViewPort.View())
|
contentFinal := contentStyle.Render(p.contentViewPort.View())
|
||||||
if renderedContent == "" {
|
if renderedContent == "" {
|
||||||
contentFinal = ""
|
contentFinal = ""
|
||||||
@@ -219,6 +296,34 @@ func (p *permissionDialogCmp) render() string {
|
|||||||
contentFinal,
|
contentFinal,
|
||||||
form,
|
form,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
default:
|
||||||
|
content := p.permission.Description
|
||||||
|
|
||||||
|
renderedContent, _ := r.Render(content)
|
||||||
|
p.contentViewPort.Width = p.width - 2 - 2
|
||||||
|
p.contentViewPort.Height = p.height - lipgloss.Height(headerContent) - lipgloss.Height(form) - 2 - 2 - 1
|
||||||
|
p.contentViewPort.SetContent(renderedContent)
|
||||||
|
|
||||||
|
// Style the viewport
|
||||||
|
contentStyle := lipgloss.NewStyle().
|
||||||
|
MarginTop(1).
|
||||||
|
Padding(0, 1).
|
||||||
|
Border(lipgloss.RoundedBorder()).
|
||||||
|
BorderForeground(styles.Flamingo)
|
||||||
|
|
||||||
|
contentFinal := contentStyle.Render(p.contentViewPort.View())
|
||||||
|
if renderedContent == "" {
|
||||||
|
contentFinal = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return lipgloss.JoinVertical(
|
||||||
|
lipgloss.Top,
|
||||||
|
headerContent,
|
||||||
|
contentFinal,
|
||||||
|
form,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *permissionDialogCmp) View() string {
|
func (p *permissionDialogCmp) View() string {
|
||||||
|
|||||||
Reference in New Issue
Block a user