@@ -65,6 +65,45 @@ type permissionDialogCmp struct {
65 selectOption *huh.Select[string]
65 selectOption *huh.Select[string]
68+// formatDiff formats a diff string with colors for additions and deletions
69+func formatDiff(diffText string) string {
70+ lines := strings.Split(diffText, "\n")
71+ var formattedLines []string
73+ // Define styles for different line types
74+ addStyle := lipgloss.NewStyle().Foreground(styles.Green)
75+ removeStyle := lipgloss.NewStyle().Foreground(styles.Red)
76+ headerStyle := lipgloss.NewStyle().Bold(true).Foreground(styles.Blue)
77+ contextStyle := lipgloss.NewStyle().Foreground(styles.SubText0)
80+ for _, line := range lines {
81+ if strings.HasPrefix(line, "+") {
82+ formattedLines = append(formattedLines, addStyle.Render(line))
83+ } else if strings.HasPrefix(line, "-") {
84+ formattedLines = append(formattedLines, removeStyle.Render(line))
85+ } else if strings.HasPrefix(line, "Changes:") || strings.HasPrefix(line, " ...") {
86+ formattedLines = append(formattedLines, headerStyle.Render(line))
87+ } else if strings.HasPrefix(line, " ") {
88+ formattedLines = append(formattedLines, contextStyle.Render(line))
90+ formattedLines = append(formattedLines, line)
94+ // Join all formatted lines
95+ content := strings.Join(formattedLines, "\n")
97+ // Create a bordered box for the content
98+ contentStyle := lipgloss.NewStyle().
101+ Border(lipgloss.RoundedBorder()).
102+ BorderForeground(styles.Flamingo)
104+ return contentStyle.Render(content)
68func (p *permissionDialogCmp) Init() tea.Cmd {
107func (p *permissionDialogCmp) Init() tea.Cmd {
69 return nil
108 return nil
@@ -132,93 +171,159 @@ func (p *permissionDialogCmp) render() string {
132 lipgloss.JoinHorizontal(lipgloss.Left, keyStyle.Render("Path:"), " ", valueStyle.Render(p.permission.Path)),
171 lipgloss.JoinHorizontal(lipgloss.Left, keyStyle.Render("Path:"), " ", valueStyle.Render(p.permission.Path)),
175+ // Create the header content first so it can be used in all cases
176+ headerContent := lipgloss.NewStyle().Padding(0, 1).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...))
135 r, _ := glamour.NewTermRenderer(
178 r, _ := glamour.NewTermRenderer(
136 glamour.WithStyles(styles.CatppuccinMarkdownStyle()),
179 glamour.WithStyles(styles.CatppuccinMarkdownStyle()),
137 glamour.WithWordWrap(p.width-10),
180 glamour.WithWordWrap(p.width-10),
138 glamour.WithEmoji(),
181 glamour.WithEmoji(),
184+ // Handle different tool types
141 switch p.permission.ToolName {
185 switch p.permission.ToolName {
142 case tools.BashToolName:
186 case tools.BashToolName:
143 pr := p.permission.Params.(tools.BashPermissionsParams)
187 pr := p.permission.Params.(tools.BashPermissionsParams)
144 headerParts = append(headerParts, keyStyle.Render("Command:"))
188 headerParts = append(headerParts, keyStyle.Render("Command:"))
145− content = fmt.Sprintf("```bash\n%s\n```", pr.Command)
189+ content := fmt.Sprintf("```bash\n%s\n```", pr.Command)
191+ renderedContent, _ := r.Render(content)
192+ p.contentViewPort.Width = p.width - 2 - 2
194+ // Calculate content height dynamically based on content
195+ contentLines := len(strings.Split(renderedContent, "\n"))
196+ // Set a reasonable min/max for the viewport height
197+ minContentHeight := 3
198+ maxContentHeight := p.height - lipgloss.Height(headerContent) - lipgloss.Height(form) - 2 - 2 - 1
200+ // Add some padding to the content lines
201+ contentHeight := contentLines + 2
202+ if contentHeight < minContentHeight {
203+ contentHeight = minContentHeight
205+ if contentHeight > maxContentHeight {
206+ contentHeight = maxContentHeight
208+ p.contentViewPort.Height = contentHeight
210+ p.contentViewPort.SetContent(renderedContent)
212+ // Style the viewport
213+ var contentBorder lipgloss.Border
214+ var borderColor lipgloss.TerminalColor
216+ if p.isViewportFocus {
217+ contentBorder = lipgloss.DoubleBorder()
218+ borderColor = styles.Blue
220+ contentBorder = lipgloss.RoundedBorder()
221+ borderColor = styles.Flamingo
224+ contentStyle := lipgloss.NewStyle().
227+ Border(contentBorder).
228+ BorderForeground(borderColor)
230+ if p.isViewportFocus {
231+ contentStyle = contentStyle.BorderBackground(styles.Surface0)
234+ contentFinal := contentStyle.Render(p.contentViewPort.View())
236+ return lipgloss.JoinVertical(
146 case tools.EditToolName:
243 case tools.EditToolName:
147 pr := p.permission.Params.(tools.EditPermissionsParams)
244 pr := p.permission.Params.(tools.EditPermissionsParams)
148 headerParts = append(headerParts, keyStyle.Render("Update"))
245 headerParts = append(headerParts, keyStyle.Render("Update"))
149− content = fmt.Sprintf("```\n%s\n```", pr.Diff)
246+ // Recreate header content with the updated headerParts
247+ headerContent = lipgloss.NewStyle().Padding(0, 1).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...))
248+ // Format the diff with colors instead of using markdown code block
249+ formattedDiff := formatDiff(pr.Diff)
250+ return lipgloss.JoinVertical(
150 case tools.WriteToolName:
257 case tools.WriteToolName:
151 pr := p.permission.Params.(tools.WritePermissionsParams)
258 pr := p.permission.Params.(tools.WritePermissionsParams)
152 headerParts = append(headerParts, keyStyle.Render("Content"))
259 headerParts = append(headerParts, keyStyle.Render("Content"))
153− content = fmt.Sprintf("```\n%s\n```", pr.Content)
260+ // Recreate header content with the updated headerParts
261+ headerContent = lipgloss.NewStyle().Padding(0, 1).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...))
262+ // Format the diff with colors instead of using markdown code block
263+ formattedDiff := formatDiff(pr.Content)
264+ return lipgloss.JoinVertical(
154 case tools.FetchToolName:
271 case tools.FetchToolName:
155 pr := p.permission.Params.(tools.FetchPermissionsParams)
272 pr := p.permission.Params.(tools.FetchPermissionsParams)
156 headerParts = append(headerParts, keyStyle.Render("URL: "+pr.URL))
273 headerParts = append(headerParts, keyStyle.Render("URL: "+pr.URL))
158− content = p.permission.Description
274+ content := p.permission.Description
161− renderedContent, _ := r.Render(content)
276+ renderedContent, _ := r.Render(content)
162− headerContent := lipgloss.NewStyle().Padding(0, 1).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...))
163− p.contentViewPort.Width = p.width - 2 - 2
277+ p.contentViewPort.Width = p.width - 2 - 2
165− // Calculate content height dynamically based on content
166− contentLines := len(strings.Split(renderedContent, "\n"))
167− // Set a reasonable min/max for the viewport height
168− minContentHeight := 3
169− maxContentHeight := p.height - lipgloss.Height(headerContent) - lipgloss.Height(form) - 2 - 2 - 1
278+ p.contentViewPort.Height = p.height - lipgloss.Height(headerContent) - lipgloss.Height(form) - 2 - 2 - 1
170−
279+ p.contentViewPort.SetContent(renderedContent)
171− // For bash commands, adjust height based on content length
280+
172− if p.permission.ToolName == tools.BashToolName {
281+ // Style the viewport
173− // Add some padding to the content lines
282+ contentStyle := lipgloss.NewStyle().
174− contentHeight := contentLines + 2
283+ MarginTop(1).
175− if contentHeight < minContentHeight {
284+ Padding(0, 1).
176− contentHeight = minContentHeight
285+ Border(lipgloss.RoundedBorder()).
286+ BorderForeground(styles.Flamingo)
288+ contentFinal := contentStyle.Render(p.contentViewPort.View())
289+ if renderedContent == "" {
178− if contentHeight > maxContentHeight {
292+
179− contentHeight = maxContentHeight
293+ return lipgloss.JoinVertical(
301+ content := p.permission.Description
303+ renderedContent, _ := r.Render(content)
304+ p.contentViewPort.Width = p.width - 2 - 2
305+ p.contentViewPort.Height = p.height - lipgloss.Height(headerContent) - lipgloss.Height(form) - 2 - 2 - 1
306+ p.contentViewPort.SetContent(renderedContent)
308+ // Style the viewport
309+ contentStyle := lipgloss.NewStyle().
312+ Border(lipgloss.RoundedBorder()).
313+ BorderForeground(styles.Flamingo)
315+ contentFinal := contentStyle.Render(p.contentViewPort.View())
316+ if renderedContent == "" {
181− p.contentViewPort.Height = contentHeight
319+
182− } else {
320+ return lipgloss.JoinVertical(
183− // For other content types, use the full available height
321+ lipgloss.Top,
184− p.contentViewPort.Height = maxContentHeight
322+ headerContent,
187− p.contentViewPort.SetContent(renderedContent)
189− // Make focus change more apparent with different border styles and colors
190− var contentBorder lipgloss.Border
191− var borderColor lipgloss.TerminalColor
193− if p.isViewportFocus {
194− contentBorder = lipgloss.DoubleBorder()
195− borderColor = styles.Blue
197− contentBorder = lipgloss.RoundedBorder()
198− borderColor = styles.Flamingo
201− contentStyle := lipgloss.NewStyle().
204− Border(contentBorder).
205− BorderForeground(borderColor)
207− if p.isViewportFocus {
208− contentStyle = contentStyle.BorderBackground(styles.Surface0)
211− contentFinal := contentStyle.Render(p.contentViewPort.View())
212− if renderedContent == "" {
216− return lipgloss.JoinVertical(
224func (p *permissionDialogCmp) View() string {
329func (p *permissionDialogCmp) View() string {