@@ -70,6 +70,7 @@ type Permissions struct {
7070 // Diff view state.
7171 diffSplitMode *bool // nil means use default based on width
7272 defaultDiffSplitMode bool // default split mode based on width
73+ diffXOffset int // horizontal scroll offset for diff view
7374 unifiedDiffContent string
7475 splitDiffContent string
7576
@@ -259,12 +260,31 @@ func (p *Permissions) HandleMsg(msg tea.Msg) Action {
259260 case key.Matches(msg, p.keyMap.ScrollUp):
260261 p.viewport, _ = p.viewport.Update(msg)
261262 case key.Matches(msg, p.keyMap.ScrollLeft):
262− p.viewport, _ = p.viewport.Update(msg)
263+ if p.hasDiffView() {
264+ p.scrollLeft()
265+ } else {
266+ p.viewport, _ = p.viewport.Update(msg)
267+ }
263268 case key.Matches(msg, p.keyMap.ScrollRight):
264− p.viewport, _ = p.viewport.Update(msg)
269+ if p.hasDiffView() {
270+ p.scrollRight()
271+ } else {
272+ p.viewport, _ = p.viewport.Update(msg)
273+ }
265274 }
266275 case tea.MouseWheelMsg:
267− p.viewport, _ = p.viewport.Update(msg)
276+ if p.hasDiffView() {
277+ switch msg.Button {
278+ case tea.MouseWheelLeft:
279+ p.scrollLeft()
280+ case tea.MouseWheelRight:
281+ p.scrollRight()
282+ default:
283+ p.viewport, _ = p.viewport.Update(msg)
284+ }
285+ } else {
286+ p.viewport, _ = p.viewport.Update(msg)
287+ }
268288 default:
269289 // Pass unhandled keys to viewport for non-diff content scrolling.
270290 if !p.hasDiffView() {
@@ -309,6 +329,18 @@ func (p *Permissions) isSplitMode() bool {
309329 return p.defaultDiffSplitMode
310330}
311331
332+const horizontalScrollStep = 5
333+
334+func (p *Permissions) scrollLeft() {
335+ p.diffXOffset = max(0, p.diffXOffset-horizontalScrollStep)
336+ p.viewportDirty = true
337+}
338+
339+func (p *Permissions) scrollRight() {
340+ p.diffXOffset += horizontalScrollStep
341+ p.viewportDirty = true
342+}
343+
312344// Draw implements [Dialog].
313345func (p *Permissions) Draw(scr uv.Screen, area uv.Rectangle) *tea.Cursor {
314346 t := p.com.Styles
@@ -558,10 +590,7 @@ func (p *Permissions) renderDiff(filePath, oldContent, newContent string, conten
558590 formatter := common.DiffFormatter(p.com.Styles).
559591 Before(fsext.PrettyPath(filePath), oldContent).
560592 After(fsext.PrettyPath(filePath), newContent).
561− // TODO: Allow horizontal scrolling instead of cropping. However, the
562− // diffview currently would only background color the width of the
563− // content. If the viewport is wider than the content, the rest of the
564− // line would not be colored properly.
593+ XOffset(p.diffXOffset).
565594 Width(contentWidth)
566595
567596 var result string