on main help sign in
Merge branch 'main' of github.com:charmbracelet/opencode-internal
commite41dddf0ecacd2341ba8c655dd0898840c4f91c0 authorKujtim Hoxha <kujtimii.h@gmail.com> dateTue 17 Jun 2025, 10:18 (1 year ago) parenta011b865def756
364 files changed+6025−551
go.mod+3−2 go.sum+4−4 internal/exp/diffview/Taskfile.yaml+102 internal/exp/diffview/chroma.go+52 internal/exp/diffview/diffview.go+681 internal/exp/diffview/diffview_test.go+300 internal/exp/diffview/split.go+74 internal/exp/diffview/style.go+124 internal/exp/diffview/testdata/TestDefault.after+10 internal/exp/diffview/testdata/TestDefault.before+9 internal/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/DarkMode.golden+16 internal/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/LightMode.golden+16 internal/exp/diffview/testdata/TestDiffView/Split/Default/DarkMode.golden+7 internal/exp/diffview/testdata/TestDiffView/Split/Default/LightMode.golden+7 internal/exp/diffview/testdata/TestDiffView/Split/LargeWidth/DarkMode.golden+15 internal/exp/diffview/testdata/TestDiffView/Split/LargeWidth/LightMode.golden+15 internal/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/DarkMode.golden+15 internal/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/LightMode.golden+15 internal/exp/diffview/testdata/TestDiffView/Split/Narrow/DarkMode.golden+4 internal/exp/diffview/testdata/TestDiffView/Split/Narrow/LightMode.golden+4 internal/exp/diffview/testdata/TestDiffView/Split/NoLineNumbers/DarkMode.golden+7 internal/exp/diffview/testdata/TestDiffView/Split/NoLineNumbers/LightMode.golden+7 internal/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/DarkMode.golden+15 internal/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/LightMode.golden+15 internal/exp/diffview/testdata/TestDiffView/Split/SmallWidth/DarkMode.golden+15 internal/exp/diffview/testdata/TestDiffView/Split/SmallWidth/LightMode.golden+15 internal/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/DarkMode.golden+17 internal/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/LightMode.golden+17 internal/exp/diffview/testdata/TestDiffView/Unified/Default/DarkMode.golden+8 internal/exp/diffview/testdata/TestDiffView/Unified/Default/LightMode.golden+8 internal/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/DarkMode.golden+16 internal/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/LightMode.golden+16 internal/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/DarkMode.golden+16 internal/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/LightMode.golden+16 internal/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden+7 internal/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden+7 internal/exp/diffview/testdata/TestDiffView/Unified/NoLineNumbers/DarkMode.golden+8 internal/exp/diffview/testdata/TestDiffView/Unified/NoLineNumbers/LightMode.golden+8 internal/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/DarkMode.golden+16 internal/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/LightMode.golden+16 internal/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/DarkMode.golden+16 internal/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/LightMode.golden+16 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf001.golden+1 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf002.golden+2 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf003.golden+3 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf004.golden+4 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf005.golden+5 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf006.golden+6 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf007.golden+7 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf008.golden+8 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf009.golden+9 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf010.golden+10 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf011.golden+11 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf012.golden+12 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf013.golden+13 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf014.golden+14 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf015.golden+15 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf016.golden+16 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf017.golden+17 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf018.golden+18 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf019.golden+19 internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf020.golden+20 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf001.golden+1 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf002.golden+2 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf003.golden+3 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf004.golden+4 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf005.golden+5 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf006.golden+6 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf007.golden+7 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf008.golden+8 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf009.golden+9 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf010.golden+10 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf011.golden+11 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf012.golden+12 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf013.golden+13 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf014.golden+14 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf015.golden+15 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf016.golden+16 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf017.golden+17 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf018.golden+18 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf019.golden+19 internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf020.golden+20 internal/exp/diffview/testdata/TestDiffViewTabs/Split.golden+15 internal/exp/diffview/testdata/TestDiffViewTabs/Unified.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf001.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf002.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf003.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf004.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf005.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf006.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf007.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf008.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf009.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf010.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf011.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf012.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf013.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf014.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf015.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf016.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf017.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf018.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf019.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf020.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf021.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf022.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf023.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf024.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf025.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf026.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf027.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf028.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf029.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf030.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf031.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf032.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf033.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf034.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf035.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf036.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf037.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf038.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf039.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf040.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf041.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf042.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf043.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf044.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf045.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf046.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf047.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf048.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf049.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf050.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf051.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf052.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf053.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf054.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf055.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf056.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf057.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf058.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf059.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf060.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf061.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf062.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf063.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf064.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf065.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf066.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf067.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf068.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf069.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf070.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf071.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf072.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf073.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf074.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf075.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf076.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf077.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf078.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf079.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf080.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf081.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf082.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf083.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf084.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf085.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf086.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf087.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf088.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf089.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf090.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf091.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf092.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf093.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf094.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf095.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf096.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf097.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf098.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf099.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf100.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf101.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf102.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf103.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf104.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf105.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf106.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf107.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf108.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf109.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf110.golden+15 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf001.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf002.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf003.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf004.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf005.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf006.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf007.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf008.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf009.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf010.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf011.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf012.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf013.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf014.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf015.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf016.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf017.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf018.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf019.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf020.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf021.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf022.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf023.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf024.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf025.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf026.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf027.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf028.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf029.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf030.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf031.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf032.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf033.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf034.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf035.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf036.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf037.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf038.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf039.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf040.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf041.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf042.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf043.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf044.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf045.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf046.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf047.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf048.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf049.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf050.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf051.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf052.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf053.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf054.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf055.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf056.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf057.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf058.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf059.golden+16 internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf060.golden+16 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf00.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf01.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf02.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf03.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf04.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf05.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf06.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf07.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf08.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf09.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf10.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf11.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf12.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf13.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf14.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf15.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf16.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf17.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf18.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf19.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf20.golden+7 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf00.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf01.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf02.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf03.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf04.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf05.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf06.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf07.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf08.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf09.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf10.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf11.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf12.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf13.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf14.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf15.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf16.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf17.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf18.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf19.golden+8 internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf20.golden+8 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf00.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf01.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf02.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf03.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf04.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf05.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf06.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf07.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf08.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf09.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf10.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf11.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf12.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf13.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf14.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf15.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf16.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf00.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf01.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf02.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf03.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf04.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf05.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf06.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf07.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf08.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf09.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf10.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf11.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf12.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf13.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf14.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf15.golden+5 internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf16.golden+5 internal/exp/diffview/testdata/TestMultipleHunks.after+15 internal/exp/diffview/testdata/TestMultipleHunks.before+13 internal/exp/diffview/testdata/TestNarrow.after+3 internal/exp/diffview/testdata/TestNarrow.before+3 internal/exp/diffview/testdata/TestTabs.after+15 internal/exp/diffview/testdata/TestTabs.before+13 internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLines/Content.golden+11 internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLines/JSON.golden+40 internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusOne/Content.golden+12 internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusOne/JSON.golden+44 internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusTwo/Content.golden+13 internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusTwo/JSON.golden+48 internal/exp/diffview/testdata/TestUdiff/Unified.golden+11 internal/exp/diffview/udiff_test.go+92 internal/exp/diffview/util.go+39 internal/exp/diffview/util_test.go+27 internal/fileutil/fileutil.go+24 internal/llm/agent/tools.go−1 internal/llm/tools/edit.go+31−23 internal/llm/tools/fetch.go+12−6 internal/llm/tools/grep.go+47 internal/llm/tools/patch.go−372 internal/llm/tools/shell/comparison_test.go−29 internal/llm/tools/shell/shell_test.go−25 internal/llm/tools/sourcegraph.go+13−6 internal/lsp/watcher/watcher.go+25−9 internal/tui/components/chat/messages/renderer.go+7−39 internal/tui/components/chat/sidebar/sidebar.go+135−8 internal/tui/components/core/helpers.go+19−5 internal/tui/components/dialogs/commands/commands.go+2−1 internal/tui/components/dialogs/init/init.go+2−1 internal/tui/components/dialogs/permissions/permissions.go+6−19 internal/tui/page/chat/chat.go+1−1 todos.md+1
go.mod+3−2
@@ -9,7 +9,7 @@ require (
99 github.com/PuerkitoBio/goquery v1.9.2
1010 github.com/alecthomas/chroma/v2 v2.15.0
1111 github.com/anthropics/anthropic-sdk-go v1.4.0
12− github.com/aymanbagabas/go-udiff v0.2.0
12+ github.com/aymanbagabas/go-udiff v0.3.1
1313 github.com/bmatcuk/doublestar/v4 v4.8.1
1414 github.com/charlievieth/fastwalk v1.0.11
1515 github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250607113720-eb5e1cf3b09e
@@ -18,6 +18,7 @@ require (
1818 github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1.0.20250523195325-2d1af06b557c
1919 github.com/charmbracelet/x/ansi v0.9.3-0.20250602153603-fb931ed90413
2020 github.com/charmbracelet/x/exp/charmtone v0.0.0-20250530202730-6ba1785cd7b9
21+ github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a
2122 github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec
2223 github.com/fsnotify/fsnotify v1.8.0
2324 github.com/go-logfmt/logfmt v0.6.0
@@ -65,7 +66,7 @@ require (
6566 github.com/aymerick/douceur v0.2.0 // indirect
6667 github.com/charmbracelet/colorprofile v0.3.1 // indirect
6768 github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa // indirect
68− github.com/charmbracelet/x/exp/slice v0.0.0-20250528180458-2d5d6cb84620
69+ github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef
6970 github.com/charmbracelet/x/input v0.3.5-0.20250509021451-13796e822d86 // indirect
7071 github.com/charmbracelet/x/term v0.2.1 // indirect
7172 github.com/charmbracelet/x/windows v0.2.1 // indirect
go.sum+4−4
@@ -60,8 +60,8 @@ github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
6060github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
6161github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
6262github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
63−github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
64−github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
63+github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY=
64+github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E=
6565github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
6666github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
6767github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
@@ -86,8 +86,8 @@ github.com/charmbracelet/x/exp/charmtone v0.0.0-20250530202730-6ba1785cd7b9 h1:f
8686github.com/charmbracelet/x/exp/charmtone v0.0.0-20250530202730-6ba1785cd7b9/go.mod h1:vr+xCFylsPYq2qSz+n5/jItjcK2/PgrKFMTI7VRR6CI=
8787github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a h1:FsHEJ52OC4VuTzU8t+n5frMjLvpYWEznSr/u8tnkCYw=
8888github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
89−github.com/charmbracelet/x/exp/slice v0.0.0-20250528180458-2d5d6cb84620 h1:/PN4jqP3ki9NvtHRrYZ9ewCutKZB6DK8frTW+Dj/MWs=
90−github.com/charmbracelet/x/exp/slice v0.0.0-20250528180458-2d5d6cb84620/go.mod h1:vI5nDVMWi6veaYH+0Fmvpbe/+cv/iJfMntdh+N0+Tms=
89+github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef h1:v7qwsZ2OxzlwvpKwz8dtZXp7fIJlcDEUOyFBNE4fz4Q=
90+github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef/go.mod h1:vI5nDVMWi6veaYH+0Fmvpbe/+cv/iJfMntdh+N0+Tms=
9191github.com/charmbracelet/x/input v0.3.5-0.20250509021451-13796e822d86 h1:BxAEmOBIDajkgao3EsbBxKQCYvgYPGdT62WASLvtf4Y=
9292github.com/charmbracelet/x/input v0.3.5-0.20250509021451-13796e822d86/go.mod h1:62Rp/6EtTxoeJDSdtpA3tJp3y3ZRpsiekBSje+K8htA=
9393github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
internal/exp/diffview/Taskfile.yamlnew file+102
@@ -0,0 +1,102 @@
1+version: "3"
2+
3+tasks:
4+ test:
5+ desc: Run tests
6+ cmds:
7+ - go test ./... {{.CLI_ARGS}}
8+
9+ test:update:
10+ desc: Run tests and update golden files
11+ cmds:
12+ - go test ./... -update {{.CLI_ARGS}}
13+
14+ test:print:
15+ desc: Print golden files for debugging
16+ method: none
17+ sources:
18+ - ./testdata/TestDiffView/**/*.golden
19+ cmds:
20+ - for: sources
21+ cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}}
22+ silent: true
23+
24+ test:print:width:unified:
25+ desc: Print golden files for debugging
26+ method: none
27+ sources:
28+ - ./testdata/TestDiffViewWidth/Unified/*.golden
29+ cmds:
30+ - for: sources
31+ cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}}
32+ silent: true
33+
34+ test:print:width:split:
35+ desc: Print golden files for debugging
36+ method: none
37+ sources:
38+ - ./testdata/TestDiffViewWidth/Split/*.golden
39+ cmds:
40+ - for: sources
41+ cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}}
42+ silent: true
43+
44+ test:print:height:unified:
45+ desc: Print golden files for debugging
46+ method: none
47+ sources:
48+ - ./testdata/TestDiffViewHeight/Unified/*.golden
49+ cmds:
50+ - for: sources
51+ cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}}
52+ silent: true
53+
54+ test:print:height:split:
55+ desc: Print golden files for debugging
56+ method: none
57+ sources:
58+ - ./testdata/TestDiffViewHeight/Split/*.golden
59+ cmds:
60+ - for: sources
61+ cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}}
62+ silent: true
63+
64+ test:print:xoffset:unified:
65+ desc: Print golden files for debugging
66+ method: none
67+ sources:
68+ - ./testdata/TestDiffViewXOffset/Unified/*.golden
69+ cmds:
70+ - for: sources
71+ cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}}
72+ silent: true
73+
74+ test:print:xoffset:split:
75+ desc: Print golden files for debugging
76+ method: none
77+ sources:
78+ - ./testdata/TestDiffViewXOffset/Split/*.golden
79+ cmds:
80+ - for: sources
81+ cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}}
82+ silent: true
83+
84+ test:print:yoffset:unified:
85+ desc: Print golden files for debugging
86+ method: none
87+ sources:
88+ - ./testdata/TestDiffViewYOffset/Unified/*.golden
89+ cmds:
90+ - for: sources
91+ cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}}
92+ silent: true
93+
94+ test:print:yoffset:split:
95+ desc: Print golden files for debugging
96+ method: none
97+ sources:
98+ - ./testdata/TestDiffViewYOffset/Split/*.golden
99+ cmds:
100+ - for: sources
101+ cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}}
102+ silent: true
internal/exp/diffview/chroma.gonew file+52
@@ -0,0 +1,52 @@
1+package diffview
2+
3+import (
4+ "fmt"
5+ "image/color"
6+ "io"
7+
8+ "github.com/alecthomas/chroma/v2"
9+ "github.com/charmbracelet/lipgloss/v2"
10+)
11+
12+var _ chroma.Formatter = chromaFormatter{}
13+
14+// chromaFormatter is a custom formatter for Chroma that uses Lip Gloss for
15+// foreground styling, while keeping a forced background color.
16+type chromaFormatter struct {
17+ bgColor color.Color
18+}
19+
20+// Format implements the chroma.Formatter interface.
21+func (c chromaFormatter) Format(w io.Writer, style *chroma.Style, it chroma.Iterator) error {
22+ for token := it(); token != chroma.EOF; token = it() {
23+ entry := style.Get(token.Type)
24+ if entry.IsZero() {
25+ if _, err := fmt.Fprint(w, token.Value); err != nil {
26+ return err
27+ }
28+ continue
29+ }
30+
31+ s := lipgloss.NewStyle().
32+ Background(c.bgColor)
33+
34+ if entry.Bold == chroma.Yes {
35+ s = s.Bold(true)
36+ }
37+ if entry.Underline == chroma.Yes {
38+ s = s.Underline(true)
39+ }
40+ if entry.Italic == chroma.Yes {
41+ s = s.Italic(true)
42+ }
43+ if entry.Colour.IsSet() {
44+ s = s.Foreground(lipgloss.Color(entry.Colour.String()))
45+ }
46+
47+ if _, err := fmt.Fprint(w, s.Render(token.Value)); err != nil {
48+ return err
49+ }
50+ }
51+ return nil
52+}
internal/exp/diffview/diffview.gonew file+681
@@ -0,0 +1,681 @@
1+package diffview
2+
3+import (
4+ "fmt"
5+ "image/color"
6+ "strconv"
7+ "strings"
8+
9+ "github.com/alecthomas/chroma/v2"
10+ "github.com/alecthomas/chroma/v2/lexers"
11+ "github.com/aymanbagabas/go-udiff"
12+ "github.com/aymanbagabas/go-udiff/myers"
13+ "github.com/charmbracelet/lipgloss/v2"
14+ "github.com/charmbracelet/x/ansi"
15+)
16+
17+const (
18+ leadingSymbolsSize = 2
19+ lineNumPadding = 1
20+)
21+
22+type file struct {
23+ path string
24+ content string
25+}
26+
27+type layout int
28+
29+const (
30+ layoutUnified layout = iota + 1
31+ layoutSplit
32+)
33+
34+// DiffView represents a view for displaying differences between two files.
35+type DiffView struct {
36+ layout layout
37+ before file
38+ after file
39+ contextLines int
40+ lineNumbers bool
41+ highlight bool
42+ height int
43+ width int
44+ xOffset int
45+ yOffset int
46+ style Style
47+ tabWidth int
48+ chromaStyle *chroma.Style
49+
50+ isComputed bool
51+ err error
52+ unified udiff.UnifiedDiff
53+ edits []udiff.Edit
54+
55+ splitHunks []splitHunk
56+
57+ codeWidth int
58+ fullCodeWidth int // with leading symbols
59+ extraColOnAfter bool // add extra column on after panel
60+ beforeNumDigits int
61+ afterNumDigits int
62+}
63+
64+// New creates a new DiffView with default settings.
65+func New() *DiffView {
66+ dv := &DiffView{
67+ layout: layoutUnified,
68+ contextLines: udiff.DefaultContextLines,
69+ lineNumbers: true,
70+ tabWidth: 8,
71+ }
72+ dv.style = DefaultDarkStyle()
73+ return dv
74+}
75+
76+// Unified sets the layout of the DiffView to unified.
77+func (dv *DiffView) Unified() *DiffView {
78+ dv.layout = layoutUnified
79+ return dv
80+}
81+
82+// Split sets the layout of the DiffView to split (side-by-side).
83+func (dv *DiffView) Split() *DiffView {
84+ dv.layout = layoutSplit
85+ return dv
86+}
87+
88+// Before sets the "before" file for the DiffView.
89+func (dv *DiffView) Before(path, content string) *DiffView {
90+ dv.before = file{path: path, content: content}
91+ return dv
92+}
93+
94+// After sets the "after" file for the DiffView.
95+func (dv *DiffView) After(path, content string) *DiffView {
96+ dv.after = file{path: path, content: content}
97+ return dv
98+}
99+
100+// ContextLines sets the number of context lines for the DiffView.
101+func (dv *DiffView) ContextLines(contextLines int) *DiffView {
102+ dv.contextLines = contextLines
103+ return dv
104+}
105+
106+// Style sets the style for the DiffView.
107+func (dv *DiffView) Style(style Style) *DiffView {
108+ dv.style = style
109+ return dv
110+}
111+
112+// LineNumbers sets whether to display line numbers in the DiffView.
113+func (dv *DiffView) LineNumbers(lineNumbers bool) *DiffView {
114+ dv.lineNumbers = lineNumbers
115+ return dv
116+}
117+
118+// SyntaxHightlight sets whether to enable syntax highlighting in the DiffView.
119+func (dv *DiffView) SyntaxHightlight(highlight bool) *DiffView {
120+ dv.highlight = highlight
121+ return dv
122+}
123+
124+// Height sets the height of the DiffView.
125+func (dv *DiffView) Height(height int) *DiffView {
126+ dv.height = height
127+ return dv
128+}
129+
130+// Width sets the width of the DiffView.
131+func (dv *DiffView) Width(width int) *DiffView {
132+ dv.width = width
133+ return dv
134+}
135+
136+// XOffset sets the horizontal offset for the DiffView.
137+func (dv *DiffView) XOffset(xOffset int) *DiffView {
138+ dv.xOffset = xOffset
139+ return dv
140+}
141+
142+// YOffset sets the vertical offset for the DiffView.
143+func (dv *DiffView) YOffset(yOffset int) *DiffView {
144+ dv.yOffset = yOffset
145+ return dv
146+}
147+
148+// TabWidth sets the tab width. Only relevant for code that contains tabs, like
149+// Go code.
150+func (dv *DiffView) TabWidth(tabWidth int) *DiffView {
151+ dv.tabWidth = tabWidth
152+ return dv
153+}
154+
155+// ChromaStyle sets the chroma style for syntax highlighting.
156+// If nil, no syntax highlighting will be applied.
157+func (dv *DiffView) ChromaStyle(style *chroma.Style) *DiffView {
158+ dv.chromaStyle = style
159+ return dv
160+}
161+
162+// String returns the string representation of the DiffView.
163+func (dv *DiffView) String() string {
164+ dv.replaceTabs()
165+ if err := dv.computeDiff(); err != nil {
166+ return err.Error()
167+ }
168+ dv.convertDiffToSplit()
169+ dv.adjustStyles()
170+ dv.detectNumDigits()
171+
172+ if dv.width <= 0 {
173+ dv.detectCodeWidth()
174+ } else {
175+ dv.resizeCodeWidth()
176+ }
177+
178+ style := lipgloss.NewStyle()
179+ if dv.width > 0 {
180+ style = style.MaxWidth(dv.width)
181+ }
182+ if dv.height > 0 {
183+ style = style.MaxHeight(dv.height)
184+ }
185+
186+ switch dv.layout {
187+ case layoutUnified:
188+ return style.Render(strings.TrimSuffix(dv.renderUnified(), "\n"))
189+ case layoutSplit:
190+ return style.Render(strings.TrimSuffix(dv.renderSplit(), "\n"))
191+ default:
192+ panic("unknown diffview layout")
193+ }
194+}
195+
196+// replaceTabs replaces tabs in the before and after file contents with spaces
197+// according to the specified tab width.
198+func (dv *DiffView) replaceTabs() {
199+ spaces := strings.Repeat(" ", dv.tabWidth)
200+ dv.before.content = strings.ReplaceAll(dv.before.content, "\t", spaces)
201+ dv.after.content = strings.ReplaceAll(dv.after.content, "\t", spaces)
202+}
203+
204+// computeDiff computes the differences between the "before" and "after" files.
205+func (dv *DiffView) computeDiff() error {
206+ if dv.isComputed {
207+ return dv.err
208+ }
209+ dv.isComputed = true
210+ dv.edits = myers.ComputeEdits( //nolint:staticcheck
211+ dv.before.content,
212+ dv.after.content,
213+ )
214+ dv.unified, dv.err = udiff.ToUnifiedDiff(
215+ dv.before.path,
216+ dv.after.path,
217+ dv.before.content,
218+ dv.edits,
219+ dv.contextLines,
220+ )
221+ return dv.err
222+}
223+
224+// convertDiffToSplit converts the unified diff to a split diff if the layout is
225+// set to split.
226+func (dv *DiffView) convertDiffToSplit() {
227+ if dv.layout != layoutSplit {
228+ return
229+ }
230+
231+ dv.splitHunks = make([]splitHunk, len(dv.unified.Hunks))
232+ for i, h := range dv.unified.Hunks {
233+ dv.splitHunks[i] = hunkToSplit(h)
234+ }
235+}
236+
237+// adjustStyles adjusts adds padding and alignment to the styles.
238+func (dv *DiffView) adjustStyles() {
239+ setPadding := func(s lipgloss.Style) lipgloss.Style {
240+ return s.Padding(0, lineNumPadding).Align(lipgloss.Right)
241+ }
242+ dv.style.MissingLine.LineNumber = setPadding(dv.style.MissingLine.LineNumber)
243+ dv.style.DividerLine.LineNumber = setPadding(dv.style.DividerLine.LineNumber)
244+ dv.style.EqualLine.LineNumber = setPadding(dv.style.EqualLine.LineNumber)
245+ dv.style.InsertLine.LineNumber = setPadding(dv.style.InsertLine.LineNumber)
246+ dv.style.DeleteLine.LineNumber = setPadding(dv.style.DeleteLine.LineNumber)
247+}
248+
249+// detectNumDigits calculates the maximum number of digits needed for before and
250+// after line numbers.
251+func (dv *DiffView) detectNumDigits() {
252+ dv.beforeNumDigits = 0
253+ dv.afterNumDigits = 0
254+
255+ for _, h := range dv.unified.Hunks {
256+ dv.beforeNumDigits = max(dv.beforeNumDigits, len(strconv.Itoa(h.FromLine+len(h.Lines))))
257+ dv.afterNumDigits = max(dv.afterNumDigits, len(strconv.Itoa(h.ToLine+len(h.Lines))))
258+ }
259+}
260+
261+// detectCodeWidth calculates the maximum width of code lines in the diff view.
262+func (dv *DiffView) detectCodeWidth() {
263+ switch dv.layout {
264+ case layoutUnified:
265+ dv.detectUnifiedCodeWidth()
266+ case layoutSplit:
267+ dv.detectSplitCodeWidth()
268+ }
269+ dv.fullCodeWidth = dv.codeWidth + leadingSymbolsSize
270+}
271+
272+// detectUnifiedCodeWidth calculates the maximum width of code lines in a
273+// unified diff.
274+func (dv *DiffView) detectUnifiedCodeWidth() {
275+ dv.codeWidth = 0
276+
277+ for _, h := range dv.unified.Hunks {
278+ shownLines := ansi.StringWidth(dv.hunkLineFor(h))
279+
280+ for _, l := range h.Lines {
281+ lineWidth := ansi.StringWidth(strings.TrimSuffix(l.Content, "\n")) + 1
282+ dv.codeWidth = max(dv.codeWidth, lineWidth, shownLines)
283+ }
284+ }
285+}
286+
287+// detectSplitCodeWidth calculates the maximum width of code lines in a
288+// split diff.
289+func (dv *DiffView) detectSplitCodeWidth() {
290+ dv.codeWidth = 0
291+
292+ for i, h := range dv.splitHunks {
293+ shownLines := ansi.StringWidth(dv.hunkLineFor(dv.unified.Hunks[i]))
294+
295+ for _, l := range h.lines {
296+ if l.before != nil {
297+ codeWidth := ansi.StringWidth(strings.TrimSuffix(l.before.Content, "\n")) + 1
298+ dv.codeWidth = max(dv.codeWidth, codeWidth, shownLines)
299+ }
300+ if l.after != nil {
301+ codeWidth := ansi.StringWidth(strings.TrimSuffix(l.after.Content, "\n")) + 1
302+ dv.codeWidth = max(dv.codeWidth, codeWidth, shownLines)
303+ }
304+ }
305+ }
306+}
307+
308+// resizeCodeWidth resizes the code width to fit within the specified width.
309+func (dv *DiffView) resizeCodeWidth() {
310+ fullNumWidth := dv.beforeNumDigits + dv.afterNumDigits
311+ fullNumWidth += lineNumPadding * 4 // left and right padding for both line numbers
312+
313+ switch dv.layout {
314+ case layoutUnified:
315+ dv.codeWidth = dv.width - fullNumWidth - leadingSymbolsSize
316+ case layoutSplit:
317+ remainingWidth := dv.width - fullNumWidth - leadingSymbolsSize*2
318+ dv.codeWidth = remainingWidth / 2
319+ dv.extraColOnAfter = isOdd(remainingWidth)
320+ }
321+
322+ dv.fullCodeWidth = dv.codeWidth + leadingSymbolsSize
323+}
324+
325+// renderUnified renders the unified diff view as a string.
326+func (dv *DiffView) renderUnified() string {
327+ var b strings.Builder
328+
329+ fullContentStyle := lipgloss.NewStyle().MaxWidth(dv.fullCodeWidth)
330+ printedLines := -dv.yOffset
331+
332+ write := func(s string) {
333+ if printedLines >= 0 {
334+ b.WriteString(s)
335+ }
336+ }
337+
338+outer:
339+ for i, h := range dv.unified.Hunks {
340+ ls := dv.style.DividerLine
341+ if dv.lineNumbers {
342+ write(ls.LineNumber.Render(pad("…", dv.beforeNumDigits)))
343+ write(ls.LineNumber.Render(pad("…", dv.afterNumDigits)))
344+ }
345+ content := ansi.Truncate(dv.hunkLineFor(h), dv.fullCodeWidth, "…")
346+ write(ls.Code.Width(dv.fullCodeWidth).Render(content))
347+ write("\n")
348+ printedLines++
349+
350+ beforeLine := h.FromLine
351+ afterLine := h.ToLine
352+
353+ for j, l := range h.Lines {
354+ // print ellipis if we don't have enough space to print the rest of the diff
355+ hasReachedHeight := dv.height > 0 && printedLines+1 == dv.height
356+ isLastHunk := i+1 == len(dv.unified.Hunks)
357+ isLastLine := j+1 == len(h.Lines)
358+ if hasReachedHeight && (!isLastHunk || !isLastLine) {
359+ ls := dv.lineStyleForType(l.Kind)
360+ if dv.lineNumbers {
361+ write(ls.LineNumber.Render(pad("…", dv.beforeNumDigits)))
362+ write(ls.LineNumber.Render(pad("…", dv.afterNumDigits)))
363+ }
364+ write(fullContentStyle.Render(
365+ ls.Code.Width(dv.fullCodeWidth).Render(" …"),
366+ ))
367+ write("\n")
368+ break outer
369+ }
370+
371+ getContent := func(ls LineStyle) string {
372+ content := strings.TrimSuffix(l.Content, "\n")
373+ content = dv.hightlightCode(content, ls.Code.GetBackground())
374+ content = ansi.GraphemeWidth.Cut(content, dv.xOffset, len(content))
375+ content = ansi.Truncate(content, dv.codeWidth, "…")
376+ return content
377+ }
378+
379+ leadingEllipsis := dv.xOffset > 0 && strings.TrimSpace(content) != ""
380+
381+ switch l.Kind {
382+ case udiff.Equal:
383+ ls := dv.style.EqualLine
384+ content := getContent(ls)
385+ if dv.lineNumbers {
386+ write(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
387+ write(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
388+ }
389+ write(fullContentStyle.Render(
390+ ls.Code.Width(dv.fullCodeWidth).Render(ternary(leadingEllipsis, " …", " ") + content),
391+ ))
392+ beforeLine++
393+ afterLine++
394+ case udiff.Insert:
395+ ls := dv.style.InsertLine
396+ content := getContent(ls)
397+ if dv.lineNumbers {
398+ write(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits)))
399+ write(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
400+ }
401+ write(fullContentStyle.Render(
402+ ls.Symbol.Render(ternary(leadingEllipsis, "+…", "+ ")) +
403+ ls.Code.Width(dv.codeWidth).Render(content),
404+ ))
405+ afterLine++
406+ case udiff.Delete:
407+ ls := dv.style.DeleteLine
408+ content := getContent(ls)
409+ if dv.lineNumbers {
410+ write(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
411+ write(ls.LineNumber.Render(pad(" ", dv.afterNumDigits)))
412+ }
413+ write(fullContentStyle.Render(
414+ ls.Symbol.Render(ternary(leadingEllipsis, "-…", "- ")) +
415+ ls.Code.Width(dv.codeWidth).Render(content),
416+ ))
417+ beforeLine++
418+ }
419+ write("\n")
420+
421+ printedLines++
422+ }
423+ }
424+
425+ for printedLines < dv.height {
426+ ls := dv.style.MissingLine
427+ if dv.lineNumbers {
428+ write(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits)))
429+ write(ls.LineNumber.Render(pad(" ", dv.afterNumDigits)))
430+ }
431+ write(ls.Code.Width(dv.fullCodeWidth).Render(" "))
432+ write("\n")
433+ printedLines++
434+ }
435+
436+ return b.String()
437+}
438+
439+// renderSplit renders the split (side-by-side) diff view as a string.
440+func (dv *DiffView) renderSplit() string {
441+ var b strings.Builder
442+
443+ beforeFullContentStyle := lipgloss.NewStyle().MaxWidth(dv.fullCodeWidth)
444+ afterFullContentStyle := lipgloss.NewStyle().MaxWidth(dv.fullCodeWidth + btoi(dv.extraColOnAfter))
445+ printedLines := -dv.yOffset
446+
447+ write := func(s string) {
448+ if printedLines >= 0 {
449+ b.WriteString(s)
450+ }
451+ }
452+
453+outer:
454+ for i, h := range dv.splitHunks {
455+ ls := dv.style.DividerLine
456+ if dv.lineNumbers {
457+ write(ls.LineNumber.Render(pad("…", dv.beforeNumDigits)))
458+ }
459+ content := ansi.Truncate(dv.hunkLineFor(dv.unified.Hunks[i]), dv.fullCodeWidth, "…")
460+ write(ls.Code.Width(dv.fullCodeWidth).Render(content))
461+ if dv.lineNumbers {
462+ write(ls.LineNumber.Render(pad("…", dv.afterNumDigits)))
463+ }
464+ write(ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" "))
465+ write("\n")
466+ printedLines++
467+
468+ beforeLine := h.fromLine
469+ afterLine := h.toLine
470+
471+ for j, l := range h.lines {
472+ // print ellipis if we don't have enough space to print the rest of the diff
473+ hasReachedHeight := dv.height > 0 && printedLines+1 == dv.height
474+ isLastHunk := i+1 == len(dv.unified.Hunks)
475+ isLastLine := j+1 == len(h.lines)
476+ if hasReachedHeight && (!isLastHunk || !isLastLine) {
477+ ls := dv.style.MissingLine
478+ if l.before != nil {
479+ ls = dv.lineStyleForType(l.before.Kind)
480+ }
481+ if dv.lineNumbers {
482+ write(ls.LineNumber.Render(pad("…", dv.beforeNumDigits)))
483+ }
484+ write(beforeFullContentStyle.Render(
485+ ls.Code.Width(dv.fullCodeWidth).Render(" …"),
486+ ))
487+ ls = dv.style.MissingLine
488+ if l.after != nil {
489+ ls = dv.lineStyleForType(l.after.Kind)
490+ }
491+ if dv.lineNumbers {
492+ write(ls.LineNumber.Render(pad("…", dv.afterNumDigits)))
493+ }
494+ write(afterFullContentStyle.Render(
495+ ls.Code.Width(dv.fullCodeWidth).Render(" …"),
496+ ))
497+ write("\n")
498+ break outer
499+ }
500+
501+ getContent := func(content string, ls LineStyle) string {
502+ content = strings.TrimSuffix(content, "\n")
503+ content = dv.hightlightCode(content, ls.Code.GetBackground())
504+ content = ansi.GraphemeWidth.Cut(content, dv.xOffset, len(content))
505+ content = ansi.Truncate(content, dv.codeWidth, "…")
506+ return content
507+ }
508+ getLeadingEllipsis := func(content string) bool {
509+ return dv.xOffset > 0 && strings.TrimSpace(content) != ""
510+ }
511+
512+ switch {
513+ case l.before == nil:
514+ ls := dv.style.MissingLine
515+ if dv.lineNumbers {
516+ write(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits)))
517+ }
518+ write(beforeFullContentStyle.Render(
519+ ls.Code.Width(dv.fullCodeWidth).Render(" "),
520+ ))
521+ case l.before.Kind == udiff.Equal:
522+ ls := dv.style.EqualLine
523+ content := getContent(l.before.Content, ls)
524+ leadingEllipsis := getLeadingEllipsis(content)
525+ if dv.lineNumbers {
526+ write(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
527+ }
528+ write(beforeFullContentStyle.Render(
529+ ls.Code.Width(dv.fullCodeWidth).Render(ternary(leadingEllipsis, " …", " ") + content),
530+ ))
531+ beforeLine++
532+ case l.before.Kind == udiff.Delete:
533+ ls := dv.style.DeleteLine
534+ content := getContent(l.before.Content, ls)
535+ leadingEllipsis := getLeadingEllipsis(content)
536+ if dv.lineNumbers {
537+ write(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
538+ }
539+ write(beforeFullContentStyle.Render(
540+ ls.Symbol.Render(ternary(leadingEllipsis, "-…", "- ")) +
541+ ls.Code.Width(dv.codeWidth).Render(content),
542+ ))
543+ beforeLine++
544+ }
545+
546+ switch {
547+ case l.after == nil:
548+ ls := dv.style.MissingLine
549+ if dv.lineNumbers {
550+ write(ls.LineNumber.Render(pad(" ", dv.afterNumDigits)))
551+ }
552+ write(afterFullContentStyle.Render(
553+ ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" "),
554+ ))
555+ case l.after.Kind == udiff.Equal:
556+ ls := dv.style.EqualLine
557+ content := getContent(l.after.Content, ls)
558+ leadingEllipsis := getLeadingEllipsis(content)
559+ if dv.lineNumbers {
560+ write(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
561+ }
562+ write(afterFullContentStyle.Render(
563+ ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(ternary(leadingEllipsis, " …", " ") + content),
564+ ))
565+ afterLine++
566+ case l.after.Kind == udiff.Insert:
567+ ls := dv.style.InsertLine
568+ content := getContent(l.after.Content, ls)
569+ leadingEllipsis := getLeadingEllipsis(content)
570+ if dv.lineNumbers {
571+ write(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
572+ }
573+ write(afterFullContentStyle.Render(
574+ ls.Symbol.Render(ternary(leadingEllipsis, "+…", "+ ")) +
575+ ls.Code.Width(dv.codeWidth+btoi(dv.extraColOnAfter)).Render(content),
576+ ))
577+ afterLine++
578+ }
579+
580+ write("\n")
581+
582+ printedLines++
583+ }
584+ }
585+
586+ for printedLines < dv.height {
587+ ls := dv.style.MissingLine
588+ if dv.lineNumbers {
589+ write(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits)))
590+ }
591+ write(ls.Code.Width(dv.fullCodeWidth).Render(" "))
592+ if dv.lineNumbers {
593+ write(ls.LineNumber.Render(pad(" ", dv.afterNumDigits)))
594+ }
595+ write(ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" "))
596+ write("\n")
597+ printedLines++
598+ }
599+
600+ return b.String()
601+}
602+
603+// hunkLineFor formats the header line for a hunk in the unified diff view.
604+func (dv *DiffView) hunkLineFor(h *udiff.Hunk) string {
605+ beforeShownLines, afterShownLines := dv.hunkShownLines(h)
606+
607+ return fmt.Sprintf(
608+ " @@ -%d,%d +%d,%d @@ ",
609+ h.FromLine,
610+ beforeShownLines,
611+ h.ToLine,
612+ afterShownLines,
613+ )
614+}
615+
616+// hunkShownLines calculates the number of lines shown in a hunk for both before
617+// and after versions.
618+func (dv *DiffView) hunkShownLines(h *udiff.Hunk) (before, after int) {
619+ for _, l := range h.Lines {
620+ switch l.Kind {
621+ case udiff.Equal:
622+ before++
623+ after++
624+ case udiff.Insert:
625+ after++
626+ case udiff.Delete:
627+ before++
628+ }
629+ }
630+ return
631+}
632+
633+func (dv *DiffView) lineStyleForType(t udiff.OpKind) LineStyle {
634+ switch t {
635+ case udiff.Equal:
636+ return dv.style.EqualLine
637+ case udiff.Insert:
638+ return dv.style.InsertLine
639+ case udiff.Delete:
640+ return dv.style.DeleteLine
641+ default:
642+ return dv.style.MissingLine
643+ }
644+}
645+
646+func (dv *DiffView) hightlightCode(source string, bgColor color.Color) string {
647+ if dv.chromaStyle == nil {
648+ return source
649+ }
650+
651+ l := dv.getChromaLexer(source)
652+ f := dv.getChromaFormatter(bgColor)
653+
654+ it, err := l.Tokenise(nil, source)
655+ if err != nil {
656+ return source
657+ }
658+
659+ var b strings.Builder
660+ if err := f.Format(&b, dv.chromaStyle, it); err != nil {
661+ return source
662+ }
663+ return b.String()
664+}
665+
666+func (dv *DiffView) getChromaLexer(source string) chroma.Lexer {
667+ l := lexers.Match(dv.before.path)
668+ if l == nil {
669+ l = lexers.Analyse(source)
670+ }
671+ if l == nil {
672+ l = lexers.Fallback
673+ }
674+ return chroma.Coalesce(l)
675+}
676+
677+func (dv *DiffView) getChromaFormatter(gbColor color.Color) chroma.Formatter {
678+ return chromaFormatter{
679+ bgColor: gbColor,
680+ }
681+}
internal/exp/diffview/diffview_test.gonew file+300
@@ -0,0 +1,300 @@
1+package diffview_test
2+
3+import (
4+ _ "embed"
5+ "fmt"
6+ "strings"
7+ "testing"
8+
9+ "github.com/alecthomas/chroma/v2/styles"
10+ "github.com/charmbracelet/crush/internal/exp/diffview"
11+ "github.com/charmbracelet/x/ansi"
12+ "github.com/charmbracelet/x/exp/golden"
13+)
14+
15+//go:embed testdata/TestDefault.before
16+var TestDefaultBefore string
17+
18+//go:embed testdata/TestDefault.after
19+var TestDefaultAfter string
20+
21+//go:embed testdata/TestMultipleHunks.before
22+var TestMultipleHunksBefore string
23+
24+//go:embed testdata/TestMultipleHunks.after
25+var TestMultipleHunksAfter string
26+
27+//go:embed testdata/TestNarrow.before
28+var TestNarrowBefore string
29+
30+//go:embed testdata/TestNarrow.after
31+var TestNarrowAfter string
32+
33+//go:embed testdata/TestTabs.before
34+var TestTabsBefore string
35+
36+//go:embed testdata/TestTabs.after
37+var TestTabsAfter string
38+
39+type (
40+ TestFunc func(dv *diffview.DiffView) *diffview.DiffView
41+ TestFuncs map[string]TestFunc
42+)
43+
44+var (
45+ UnifiedFunc = func(dv *diffview.DiffView) *diffview.DiffView {
46+ return dv.Unified()
47+ }
48+ SplitFunc = func(dv *diffview.DiffView) *diffview.DiffView {
49+ return dv.Split()
50+ }
51+
52+ DefaultFunc = func(dv *diffview.DiffView) *diffview.DiffView {
53+ return dv.
54+ Before("main.go", TestDefaultBefore).
55+ After("main.go", TestDefaultAfter)
56+ }
57+ NoLineNumbersFunc = func(dv *diffview.DiffView) *diffview.DiffView {
58+ return dv.
59+ Before("main.go", TestDefaultBefore).
60+ After("main.go", TestDefaultAfter).
61+ LineNumbers(false)
62+ }
63+ MultipleHunksFunc = func(dv *diffview.DiffView) *diffview.DiffView {
64+ return dv.
65+ Before("main.go", TestMultipleHunksBefore).
66+ After("main.go", TestMultipleHunksAfter)
67+ }
68+ CustomContextLinesFunc = func(dv *diffview.DiffView) *diffview.DiffView {
69+ return dv.
70+ Before("main.go", TestMultipleHunksBefore).
71+ After("main.go", TestMultipleHunksAfter).
72+ ContextLines(4)
73+ }
74+ NarrowFunc = func(dv *diffview.DiffView) *diffview.DiffView {
75+ return dv.
76+ Before("text.txt", TestNarrowBefore).
77+ After("text.txt", TestNarrowAfter)
78+ }
79+ SmallWidthFunc = func(dv *diffview.DiffView) *diffview.DiffView {
80+ return dv.
81+ Before("main.go", TestMultipleHunksBefore).
82+ After("main.go", TestMultipleHunksAfter).
83+ Width(40)
84+ }
85+ LargeWidthFunc = func(dv *diffview.DiffView) *diffview.DiffView {
86+ return dv.
87+ Before("main.go", TestMultipleHunksBefore).
88+ After("main.go", TestMultipleHunksAfter).
89+ Width(120)
90+ }
91+ NoSyntaxHighlightFunc = func(dv *diffview.DiffView) *diffview.DiffView {
92+ return dv.
93+ Before("main.go", TestMultipleHunksBefore).
94+ After("main.go", TestMultipleHunksAfter).
95+ ChromaStyle(nil)
96+ }
97+
98+ LightModeFunc = func(dv *diffview.DiffView) *diffview.DiffView {
99+ return dv.
100+ Style(diffview.DefaultLightStyle()).
101+ ChromaStyle(styles.Get("catppuccin-latte"))
102+ }
103+ DarkModeFunc = func(dv *diffview.DiffView) *diffview.DiffView {
104+ return dv.
105+ Style(diffview.DefaultDarkStyle()).
106+ ChromaStyle(styles.Get("catppuccin-macchiato"))
107+ }
108+
109+ LayoutFuncs = TestFuncs{
110+ "Unified": UnifiedFunc,
111+ "Split": SplitFunc,
112+ }
113+ BehaviorFuncs = TestFuncs{
114+ "Default": DefaultFunc,
115+ "NoLineNumbers": NoLineNumbersFunc,
116+ "MultipleHunks": MultipleHunksFunc,
117+ "CustomContextLines": CustomContextLinesFunc,
118+ "Narrow": NarrowFunc,
119+ "SmallWidth": SmallWidthFunc,
120+ "LargeWidth": LargeWidthFunc,
121+ "NoSyntaxHighlight": NoSyntaxHighlightFunc,
122+ }
123+ ThemeFuncs = TestFuncs{
124+ "LightMode": LightModeFunc,
125+ "DarkMode": DarkModeFunc,
126+ }
127+)
128+
129+func TestDiffView(t *testing.T) {
130+ for layoutName, layoutFunc := range LayoutFuncs {
131+ t.Run(layoutName, func(t *testing.T) {
132+ for behaviorName, behaviorFunc := range BehaviorFuncs {
133+ t.Run(behaviorName, func(t *testing.T) {
134+ for themeName, themeFunc := range ThemeFuncs {
135+ t.Run(themeName, func(t *testing.T) {
136+ t.Parallel()
137+
138+ dv := diffview.New()
139+ dv = layoutFunc(dv)
140+ dv = themeFunc(dv)
141+ dv = behaviorFunc(dv)
142+
143+ output := dv.String()
144+ golden.RequireEqual(t, []byte(output))
145+
146+ switch behaviorName {
147+ case "SmallWidth":
148+ assertLineWidth(t, 40, output)
149+ case "LargeWidth":
150+ assertLineWidth(t, 120, output)
151+ }
152+ })
153+ }
154+ })
155+ }
156+ })
157+ }
158+}
159+
160+func TestDiffViewTabs(t *testing.T) {
161+ for layoutName, layoutFunc := range LayoutFuncs {
162+ t.Run(layoutName, func(t *testing.T) {
163+ t.Parallel()
164+
165+ dv := diffview.New().
166+ Before("main.go", TestTabsBefore).
167+ After("main.go", TestTabsAfter).
168+ Style(diffview.DefaultLightStyle()).
169+ ChromaStyle(styles.Get("catppuccin-latte"))
170+ dv = layoutFunc(dv)
171+
172+ output := dv.String()
173+ golden.RequireEqual(t, []byte(output))
174+ })
175+ }
176+}
177+
178+func TestDiffViewWidth(t *testing.T) {
179+ for layoutName, layoutFunc := range LayoutFuncs {
180+ t.Run(layoutName, func(t *testing.T) {
181+ for width := 1; width <= 110; width++ {
182+ if layoutName == "Unified" && width > 60 {
183+ continue
184+ }
185+
186+ t.Run(fmt.Sprintf("WidthOf%03d", width), func(t *testing.T) {
187+ t.Parallel()
188+
189+ dv := diffview.New().
190+ Before("main.go", TestMultipleHunksBefore).
191+ After("main.go", TestMultipleHunksAfter).
192+ Width(width).
193+ Style(diffview.DefaultLightStyle()).
194+ ChromaStyle(styles.Get("catppuccin-latte"))
195+ dv = layoutFunc(dv)
196+
197+ output := dv.String()
198+ golden.RequireEqual(t, []byte(output))
199+
200+ assertLineWidth(t, width, output)
201+ })
202+ }
203+ })
204+ }
205+}
206+
207+func TestDiffViewHeight(t *testing.T) {
208+ for layoutName, layoutFunc := range LayoutFuncs {
209+ t.Run(layoutName, func(t *testing.T) {
210+ for height := 1; height <= 20; height++ {
211+ t.Run(fmt.Sprintf("HeightOf%03d", height), func(t *testing.T) {
212+ t.Parallel()
213+
214+ dv := diffview.New().
215+ Before("main.go", TestMultipleHunksBefore).
216+ After("main.go", TestMultipleHunksAfter).
217+ Height(height).
218+ Style(diffview.DefaultLightStyle()).
219+ ChromaStyle(styles.Get("catppuccin-latte"))
220+ dv = layoutFunc(dv)
221+
222+ output := dv.String()
223+ golden.RequireEqual(t, []byte(output))
224+
225+ assertHeight(t, height, output)
226+ })
227+ }
228+ })
229+ }
230+}
231+
232+func TestDiffViewXOffset(t *testing.T) {
233+ for layoutName, layoutFunc := range LayoutFuncs {
234+ t.Run(layoutName, func(t *testing.T) {
235+ for xOffset := range 21 {
236+ t.Run(fmt.Sprintf("XOffsetOf%02d", xOffset), func(t *testing.T) {
237+ t.Parallel()
238+
239+ dv := diffview.New().
240+ Before("main.go", TestDefaultBefore).
241+ After("main.go", TestDefaultAfter).
242+ Style(diffview.DefaultLightStyle()).
243+ ChromaStyle(styles.Get("catppuccin-latte")).
244+ Width(60).
245+ XOffset(xOffset)
246+ dv = layoutFunc(dv)
247+
248+ output := dv.String()
249+ golden.RequireEqual(t, []byte(output))
250+
251+ assertLineWidth(t, 60, output)
252+ })
253+ }
254+ })
255+ }
256+}
257+
258+func TestDiffViewYOffset(t *testing.T) {
259+ for layoutName, layoutFunc := range LayoutFuncs {
260+ t.Run(layoutName, func(t *testing.T) {
261+ for yOffset := range 17 {
262+ t.Run(fmt.Sprintf("YOffsetOf%02d", yOffset), func(t *testing.T) {
263+ t.Parallel()
264+
265+ dv := diffview.New().
266+ Before("main.go", TestMultipleHunksBefore).
267+ After("main.go", TestMultipleHunksAfter).
268+ Style(diffview.DefaultLightStyle()).
269+ ChromaStyle(styles.Get("catppuccin-latte")).
270+ Height(5).
271+ YOffset(yOffset)
272+ dv = layoutFunc(dv)
273+
274+ output := dv.String()
275+ golden.RequireEqual(t, []byte(output))
276+
277+ assertHeight(t, 5, output)
278+ })
279+ }
280+ })
281+ }
282+}
283+
284+func assertLineWidth(t *testing.T, expected int, output string) {
285+ var lineWidth int
286+ for line := range strings.SplitSeq(output, "\n") {
287+ lineWidth = max(lineWidth, ansi.StringWidth(line))
288+ }
289+ if lineWidth != expected {
290+ t.Errorf("expected output width to be == %d, got %d", expected, lineWidth)
291+ }
292+}
293+
294+func assertHeight(t *testing.T, expected int, output string) {
295+ output = strings.TrimSuffix(output, "\n")
296+ lines := strings.Count(output, "\n") + 1
297+ if lines != expected {
298+ t.Errorf("expected output height to be == %d, got %d", expected, lines)
299+ }
300+}
internal/exp/diffview/split.gonew file+74
@@ -0,0 +1,74 @@
1+package diffview
2+
3+import (
4+ "slices"
5+
6+ "github.com/aymanbagabas/go-udiff"
7+ "github.com/charmbracelet/x/exp/slice"
8+)
9+
10+type splitHunk struct {
11+ fromLine int
12+ toLine int
13+ lines []*splitLine
14+}
15+
16+type splitLine struct {
17+ before *udiff.Line
18+ after *udiff.Line
19+}
20+
21+func hunkToSplit(h *udiff.Hunk) (sh splitHunk) {
22+ lines := slices.Clone(h.Lines)
23+ sh = splitHunk{
24+ fromLine: h.FromLine,
25+ toLine: h.ToLine,
26+ lines: make([]*splitLine, 0, len(lines)),
27+ }
28+
29+ for {
30+ var ul udiff.Line
31+ var ok bool
32+ ul, lines, ok = slice.Shift(lines)
33+ if !ok {
34+ break
35+ }
36+
37+ var sl splitLine
38+
39+ switch ul.Kind {
40+
41+ // For equal lines, add as is
42+ case udiff.Equal:
43+ sl.before = &ul
44+ sl.after = &ul
45+
46+ // For inserted lines, set after and keep before as nil
47+ case udiff.Insert:
48+ sl.before = nil
49+ sl.after = &ul
50+
51+ // For deleted lines, set before and loop over the next lines
52+ // searching for the equivalent after line.
53+ case udiff.Delete:
54+ sl.before = &ul
55+
56+ inner:
57+ for i, l := range lines {
58+ switch l.Kind {
59+ case udiff.Insert:
60+ var ll udiff.Line
61+ ll, lines, _ = slice.DeleteAt(lines, i)
62+ sl.after = &ll
63+ break inner
64+ case udiff.Equal:
65+ break inner
66+ }
67+ }
68+ }
69+
70+ sh.lines = append(sh.lines, &sl)
71+ }
72+
73+ return
74+}
internal/exp/diffview/style.gonew file+124
@@ -0,0 +1,124 @@
1+package diffview
2+
3+import (
4+ "github.com/charmbracelet/lipgloss/v2"
5+ "github.com/charmbracelet/x/exp/charmtone"
6+)
7+
8+// LineStyle defines the styles for a given line type in the diff view.
9+type LineStyle struct {
10+ LineNumber lipgloss.Style
11+ Symbol lipgloss.Style
12+ Code lipgloss.Style
13+}
14+
15+// Style defines the overall style for the diff view, including styles for
16+// different line types such as divider, missing, equal, insert, and delete
17+// lines.
18+type Style struct {
19+ DividerLine LineStyle
20+ MissingLine LineStyle
21+ EqualLine LineStyle
22+ InsertLine LineStyle
23+ DeleteLine LineStyle
24+}
25+
26+// DefaultLightStyle provides a default light theme style for the diff view.
27+func DefaultLightStyle() Style {
28+ return Style{
29+ DividerLine: LineStyle{
30+ LineNumber: lipgloss.NewStyle().
31+ Foreground(charmtone.Iron).
32+ Background(charmtone.Thunder),
33+ Code: lipgloss.NewStyle().
34+ Foreground(charmtone.Oyster).
35+ Background(charmtone.Anchovy),
36+ },
37+ MissingLine: LineStyle{
38+ LineNumber: lipgloss.NewStyle().
39+ Background(charmtone.Ash),
40+ Code: lipgloss.NewStyle().
41+ Background(charmtone.Ash),
42+ },
43+ EqualLine: LineStyle{
44+ LineNumber: lipgloss.NewStyle().
45+ Foreground(charmtone.Charcoal).
46+ Background(charmtone.Ash),
47+ Code: lipgloss.NewStyle().
48+ Foreground(charmtone.Pepper).
49+ Background(charmtone.Salt),
50+ },
51+ InsertLine: LineStyle{
52+ LineNumber: lipgloss.NewStyle().
53+ Foreground(charmtone.Turtle).
54+ Background(lipgloss.Color("#c8e6c9")),
55+ Symbol: lipgloss.NewStyle().
56+ Foreground(charmtone.Turtle).
57+ Background(lipgloss.Color("#e8f5e9")),
58+ Code: lipgloss.NewStyle().
59+ Foreground(charmtone.Pepper).
60+ Background(lipgloss.Color("#e8f5e9")),
61+ },
62+ DeleteLine: LineStyle{
63+ LineNumber: lipgloss.NewStyle().
64+ Foreground(charmtone.Cherry).
65+ Background(lipgloss.Color("#ffcdd2")),
66+ Symbol: lipgloss.NewStyle().
67+ Foreground(charmtone.Cherry).
68+ Background(lipgloss.Color("#ffebee")),
69+ Code: lipgloss.NewStyle().
70+ Foreground(charmtone.Pepper).
71+ Background(lipgloss.Color("#ffebee")),
72+ },
73+ }
74+}
75+
76+// DefaultDarkStyle provides a default dark theme style for the diff view.
77+func DefaultDarkStyle() Style {
78+ return Style{
79+ DividerLine: LineStyle{
80+ LineNumber: lipgloss.NewStyle().
81+ Foreground(charmtone.Smoke).
82+ Background(charmtone.Sapphire),
83+ Code: lipgloss.NewStyle().
84+ Foreground(charmtone.Smoke).
85+ Background(charmtone.Ox),
86+ },
87+ MissingLine: LineStyle{
88+ LineNumber: lipgloss.NewStyle().
89+ Background(charmtone.Charcoal),
90+ Code: lipgloss.NewStyle().
91+ Background(charmtone.Charcoal),
92+ },
93+ EqualLine: LineStyle{
94+ LineNumber: lipgloss.NewStyle().
95+ Foreground(charmtone.Ash).
96+ Background(charmtone.Charcoal),
97+ Code: lipgloss.NewStyle().
98+ Foreground(charmtone.Salt).
99+ Background(charmtone.Pepper),
100+ },
101+ InsertLine: LineStyle{
102+ LineNumber: lipgloss.NewStyle().
103+ Foreground(charmtone.Turtle).
104+ Background(lipgloss.Color("#293229")),
105+ Symbol: lipgloss.NewStyle().
106+ Foreground(charmtone.Turtle).
107+ Background(lipgloss.Color("#303a30")),
108+ Code: lipgloss.NewStyle().
109+ Foreground(charmtone.Salt).
110+ Background(lipgloss.Color("#303a30")),
111+ },
112+ DeleteLine: LineStyle{
113+ LineNumber: lipgloss.NewStyle().
114+ Foreground(charmtone.Cherry).
115+ Background(lipgloss.Color("#332929")),
116+ Symbol: lipgloss.NewStyle().
117+ Foreground(charmtone.Cherry).
118+ Background(lipgloss.Color("#3a3030")),
119+ Code: lipgloss.NewStyle().
120+ Foreground(charmtone.Salt).
121+ Background(lipgloss.Color("#3a3030")),
122+ },
123+ }
124+}
internal/exp/diffview/testdata/TestDefault.afternew file+10
@@ -0,0 +1,10 @@
1+package main
2+
3+import (
4+ "fmt"
5+)
6+
7+func main() {
8+ content := "Hello, world!"
9+ fmt.Println(content)
10+}
internal/exp/diffview/testdata/TestDefault.beforenew file+9
@@ -0,0 +1,9 @@
1+package main
2+
3+import (
4+ "fmt"
5+)
6+
7+func main() {
8+ fmt.Println("Hello, world!")
9+}
internal/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/DarkMode.goldennew file+16
@@ -0,0 +1,16 @@
1+  …  @@ -1,13 +1,15 @@    …   
2+  1  package main   1  package main 
3+  2     2   
4+  3  import (   3  import ( 
5+  4   "fmt"   4   "fmt" 
6+       5 +  "strings" 
7+  5  )   6  ) 
8+  6     7   
9+  7  func main() {   8  func main() { 
10+  8   fmt.Println(getContent())   9   fmt.Println(getContent()) 
11+  9  }  10  } 
12+ 10    11   
13+ 11  func getContent() string {  12  func getContent() string { 
14+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
15+      14 +  return content 
16+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/LightMode.goldennew file+16
@@ -0,0 +1,16 @@
1+  …  @@ -1,13 +1,15 @@    …   
2+  1  package main   1  package main 
3+  2     2   
4+  3  import (   3  import ( 
5+  4   "fmt"   4   "fmt" 
6+       5 +  "strings" 
7+  5  )   6  ) 
8+  6     7   
9+  7  func main() {   8  func main() { 
10+  8   fmt.Println(getContent())   9   fmt.Println(getContent()) 
11+  9  }  10  } 
12+ 10    11   
13+ 11  func getContent() string {  12  func getContent() string { 
14+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
15+      14 +  return content 
16+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffView/Split/Default/DarkMode.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  )   5  ) 
3+  6     6   
4+  7  func main() {   7  func main() { 
5+  8 -  fmt.Println("Hello, world!")   8 +  content := "Hello, world!" 
6+       9 +  fmt.Println(content) 
7+  9  }  10  } 
internal/exp/diffview/testdata/TestDiffView/Split/Default/LightMode.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  )   5  ) 
3+  6     6   
4+  7  func main() {   7  func main() { 
5+  8 -  fmt.Println("Hello, world!")   8 +  content := "Hello, world!" 
6+       9 +  fmt.Println(content) 
7+  9  }  10  } 
internal/exp/diffview/testdata/TestDiffView/Split/LargeWidth/DarkMode.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffView/Split/LargeWidth/LightMode.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/DarkMode.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/LightMode.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffView/Split/Narrow/DarkMode.goldennew file+4
@@ -0,0 +1,4 @@
1+ …  @@ -1,3 +1,3 @@   …   
2+ 1 - a  1 + d 
3+ 2 - b  2 + e 
4+ 3 - c  3 + f 
internal/exp/diffview/testdata/TestDiffView/Split/Narrow/LightMode.goldennew file+4
@@ -0,0 +1,4 @@
1+ …  @@ -1,3 +1,3 @@   …   
2+ 1 - a  1 + d 
3+ 2 - b  2 + e 
4+ 3 - c  3 + f 
internal/exp/diffview/testdata/TestDiffView/Split/NoLineNumbers/DarkMode.goldennew file+7
@@ -0,0 +1,7 @@
1+ @@ -5,5 +5,6 @@    
2+ )  ) 
3+    
4+ func main() {  func main() { 
5+-  fmt.Println("Hello, world!") +  content := "Hello, world!" 
6+  +  fmt.Println(content) 
7+ }  } 
internal/exp/diffview/testdata/TestDiffView/Split/NoLineNumbers/LightMode.goldennew file+7
@@ -0,0 +1,7 @@
1+ @@ -5,5 +5,6 @@    
2+ )  ) 
3+    
4+ func main() {  func main() { 
5+-  fmt.Println("Hello, world!") +  content := "Hello, world!" 
6+  +  fmt.Println(content) 
7+ }  } 
internal/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/DarkMode.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4  "fmt"   4  "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/LightMode.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4  "fmt"   4  "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffView/Split/SmallWidth/DarkMode.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 …  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getConte… 12  func getConte…
13+ 12 -  return "H… 13 +  content :…
14+      14 +  return co…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffView/Split/SmallWidth/LightMode.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 …  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getConte… 12  func getConte…
13+ 12 -  return "H… 13 +  content :…
14+      14 +  return co…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/DarkMode.goldennew file+17
@@ -0,0 +1,17 @@
1+  …   …  @@ -1,13 +1,15 @@  
2+  1   1  package main 
3+  2   2   
4+  3   3  import ( 
5+  4   4   "fmt" 
6+     5 +  "strings" 
7+  5   6  ) 
8+  6   7   
9+  7   8  func main() { 
10+  8   9   fmt.Println(getContent()) 
11+  9  10  } 
12+ 10  11   
13+ 11  12  func getContent() string { 
14+ 12    -  return "Hello, world!" 
15+    13 +  content := strings.ToUpper("Hello, World!") 
16+    14 +  return content 
17+ 13  15  } 
internal/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/LightMode.goldennew file+17
@@ -0,0 +1,17 @@
1+  …   …  @@ -1,13 +1,15 @@  
2+  1   1  package main 
3+  2   2   
4+  3   3  import ( 
5+  4   4   "fmt" 
6+     5 +  "strings" 
7+  5   6  ) 
8+  6   7   
9+  7   8  func main() { 
10+  8   9   fmt.Println(getContent()) 
11+  9  10  } 
12+ 10  11   
13+ 11  12  func getContent() string { 
14+ 12    -  return "Hello, world!" 
15+    13 +  content := strings.ToUpper("Hello, World!") 
16+    14 +  return content 
17+ 13  15  } 
internal/exp/diffview/testdata/TestDiffView/Unified/Default/DarkMode.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  ) 
3+  6   6   
4+  7   7  func main() { 
5+  8    -  fmt.Println("Hello, world!") 
6+     8 +  content := "Hello, world!" 
7+     9 +  fmt.Println(content) 
8+  9  10  } 
internal/exp/diffview/testdata/TestDiffView/Unified/Default/LightMode.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  ) 
3+  6   6   
4+  7   7  func main() { 
5+  8    -  fmt.Println("Hello, world!") 
6+     8 +  content := "Hello, world!" 
7+     9 +  fmt.Println(content) 
8+  9  10  } 
internal/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/DarkMode.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/LightMode.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/DarkMode.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/LightMode.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.goldennew file+7
@@ -0,0 +1,7 @@
1+ …  …  @@ -1,3 +1,3 @@  
2+ 1    - a 
3+ 2    - b 
4+ 3    - c 
5+    1 + d 
6+    2 + e 
7+    3 + f 
internal/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.goldennew file+7
@@ -0,0 +1,7 @@
1+ …  …  @@ -1,3 +1,3 @@  
2+ 1    - a 
3+ 2    - b 
4+ 3    - c 
5+    1 + d 
6+    2 + e 
7+    3 + f 
internal/exp/diffview/testdata/TestDiffView/Unified/NoLineNumbers/DarkMode.goldennew file+8
@@ -0,0 +1,8 @@
1+ @@ -5,5 +5,6 @@  
2+ ) 
3+  
4+ func main() { 
5+-  fmt.Println("Hello, world!") 
6++  content := "Hello, world!" 
7++  fmt.Println(content) 
8+ } 
internal/exp/diffview/testdata/TestDiffView/Unified/NoLineNumbers/LightMode.goldennew file+8
@@ -0,0 +1,8 @@
1+ @@ -5,5 +5,6 @@  
2+ ) 
3+  
4+ func main() { 
5+-  fmt.Println("Hello, world!") 
6++  content := "Hello, world!" 
7++  fmt.Println(content) 
8+ } 
internal/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/DarkMode.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4  "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/LightMode.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4  "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/DarkMode.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUppe…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/LightMode.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUppe…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf001.goldennew file+1
@@ -0,0 +1 @@
1+  …  @@ -2,6 +2,7 @@    …   
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf002.goldennew file+2
@@ -0,0 +1,2 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf003.goldennew file+3
@@ -0,0 +1,3 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf004.goldennew file+4
@@ -0,0 +1,4 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf005.goldennew file+5
@@ -0,0 +1,5 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf006.goldennew file+6
@@ -0,0 +1,6 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf007.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf008.goldennew file+8
@@ -0,0 +1,8 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf009.goldennew file+9
@@ -0,0 +1,9 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf010.goldennew file+10
@@ -0,0 +1,10 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf011.goldennew file+11
@@ -0,0 +1,11 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf012.goldennew file+12
@@ -0,0 +1,12 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf013.goldennew file+13
@@ -0,0 +1,13 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf014.goldennew file+14
@@ -0,0 +1,14 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf015.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf016.goldennew file+16
@@ -0,0 +1,16 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
16+          
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf017.goldennew file+17
@@ -0,0 +1,17 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
16+          
17+          
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf018.goldennew file+18
@@ -0,0 +1,18 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
16+          
17+          
18+          
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf019.goldennew file+19
@@ -0,0 +1,19 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
16+          
17+          
18+          
19+          
internal/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf020.goldennew file+20
@@ -0,0 +1,20 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
16+          
17+          
18+          
19+          
20+          
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf001.goldennew file+1
@@ -0,0 +1 @@
1+  …   …  @@ -2,6 +2,7 @@  
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf002.goldennew file+2
@@ -0,0 +1,2 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf003.goldennew file+3
@@ -0,0 +1,3 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf004.goldennew file+4
@@ -0,0 +1,4 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf005.goldennew file+5
@@ -0,0 +1,5 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf006.goldennew file+6
@@ -0,0 +1,6 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf007.goldennew file+7
@@ -0,0 +1,7 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf008.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf009.goldennew file+9
@@ -0,0 +1,9 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf010.goldennew file+10
@@ -0,0 +1,10 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf011.goldennew file+11
@@ -0,0 +1,11 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf012.goldennew file+12
@@ -0,0 +1,12 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf013.goldennew file+13
@@ -0,0 +1,13 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf014.goldennew file+14
@@ -0,0 +1,14 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf015.goldennew file+15
@@ -0,0 +1,15 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf016.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf017.goldennew file+17
@@ -0,0 +1,17 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
17+        
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf018.goldennew file+18
@@ -0,0 +1,18 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
17+        
18+        
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf019.goldennew file+19
@@ -0,0 +1,19 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
17+        
18+        
19+        
internal/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf020.goldennew file+20
@@ -0,0 +1,20 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
17+        
18+        
19+        
20+        
internal/exp/diffview/testdata/TestDiffViewTabs/Split.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewTabs/Unified.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf001.goldennew file+15
@@ -0,0 +1,15 @@
1+ 
2+ 
3+ 
4+ 
5+ 
6+ 
7+ 
8+ 
9+ 
10+ 
11+ 
12+ 
13+ 
14+ 
15+ 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf002.goldennew file+15
@@ -0,0 +1,15 @@
1+  
2+  
3+  
4+  
5+  
6+  
7+  
8+  
9+  
10+  
11+ 1
12+ 1
13+ 1
14+  
15+ 1
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf003.goldennew file+15
@@ -0,0 +1,15 @@
1+  …
2+  2
3+  3
4+  4
5+  
6+  5
7+  6
8+  7
9+  …
10+  9
11+ 10
12+ 11
13+ 12
14+  
15+ 13
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf004.goldennew file+15
@@ -0,0 +1,15 @@
1+  … 
2+  2 
3+  3 
4+  4 
5+   
6+  5 
7+  6 
8+  7 
9+  … 
10+  9 
11+ 10 
12+ 11 
13+ 12 
14+   
15+ 13 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf005.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  
2+  2  
3+  3  
4+  4  
5+    
6+  5  
7+  6  
8+  7  
9+  …  
10+  9  
11+ 10  
12+ 11  
13+ 12 -
14+    
15+ 13  
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf006.goldennew file+15
@@ -0,0 +1,15 @@
1+  …   
2+  2  
3+  3  
4+  4  
5+    
6+  5  
7+  6  
8+  7  
9+  …   
10+  9  
11+ 10  
12+ 11  
13+ 12 - 
14+    
15+ 13  
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf007.goldennew file+15
@@ -0,0 +1,15 @@
1+  …   …
2+  2   
3+  3   
4+  4   
5+     
6+  5   
7+  6   
8+  7   
9+  …   …
10+  9   
11+ 10   
12+ 11   
13+ 12 -  
14+     
15+ 13   
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf008.goldennew file+15
@@ -0,0 +1,15 @@
1+  …   … 
2+  2    
3+  3    
4+  4    
5+      
6+  5    
7+  6    
8+  7    
9+  …   … 
10+  9   1
11+ 10   1
12+ 11   1
13+ 12 -  1
14+     1
15+ 13   1
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf009.goldennew file+15
@@ -0,0 +1,15 @@
1+  … …  … 
2+  2    2 
3+  3    3 
4+  4    4 
5+      5 
6+  5    6 
7+  6    7 
8+  7    8 
9+  … …  … 
10+  9   10 
11+ 10   11 
12+ 11   12 
13+ 12 - 13 
14+     14 
15+ 13   15 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf010.goldennew file+15
@@ -0,0 +1,15 @@
1+  … …  …  
2+  2    2  
3+  3    3  
4+  4    4  
5+      5 +
6+  5    6  
7+  6    7  
8+  7    8  
9+  … …  …  
10+  9   10  
11+ 10   11  
12+ 11   12  
13+ 12 - 13 +
14+     14 +
15+ 13   15  
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf011.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  …  …  
2+  2    2  
3+  3    3  
4+  4    4  
5+      5 +
6+  5    6  
7+  6    7  
8+  7    8  
9+  …  …  …  
10+  9   10  
11+ 10   11  
12+ 11   12  
13+ 12 -  13 +
14+     14 +
15+ 13   15  
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf012.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  …  …   
2+  2    2  
3+  3    3  
4+  4    4  
5+      5 + 
6+  5    6  
7+  6    7  
8+  7    8  
9+  …  …  …   
10+  9   10  
11+ 10   11  
12+ 11   12  
13+ 12 -  13 + 
14+     14 + 
15+ 13   15  
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf013.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  …  …   
2+  2    2   
3+  3    3   
4+  4    4   
5+      5 +  
6+  5    6   
7+  6    7   
8+  7    8   
9+  …  …  …   
10+  9   10   
11+ 10   11   
12+ 11   12   
13+ 12 -  13 +  
14+     14 +  
15+ 13   15   
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf014.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  …  …   
2+  2     2   
3+  3  …  3  …
4+  4  …  4  …
5+       5 + …
6+  5  )  6  )
7+  6     7   
8+  7  …  8  …
9+  …  …  …   
10+  9  } 10  }
11+ 10    11   
12+ 11  … 12  …
13+ 12 - … 13 + …
14+      14 + …
15+ 13  } 15  }
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf015.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  …  …   
2+  2     2   
3+  3  …  3  … 
4+  4  …  4  … 
5+       5 + … 
6+  5  )  6  ) 
7+  6     7   
8+  7  …  8  … 
9+  …  …  …   
10+  9  } 10  } 
11+ 10    11   
12+ 11  … 12  … 
13+ 12 - … 13 + … 
14+      14 + … 
15+ 13  } 15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf016.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @…  …   
2+  2     2   
3+  3  i…  3  i…
4+  4   …  4   …
5+       5 +  …
6+  5  )   6  ) 
7+  6     7   
8+  7  f…  8  f…
9+  …  @…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  f… 12  f…
13+ 12 -  … 13 +  …
14+      14 +  …
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf017.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @…  …   
2+  2     2   
3+  3  i…  3  i… 
4+  4   …  4   … 
5+       5 +  … 
6+  5  )   6  ) 
7+  6     7   
8+  7  f…  8  f… 
9+  …  @…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  f… 12  f… 
13+ 12 -  … 13 +  … 
14+      14 +  … 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf018.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@…  …   
2+  2     2   
3+  3  im…  3  im…
4+  4   …  4   …
5+       5 +  …
6+  5  )   6  ) 
7+  6     7   
8+  7  fu…  8  fu…
9+  …  @@…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  fu… 12  fu…
13+ 12 -  … 13 +  …
14+      14 +  …
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf019.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@…  …   
2+  2     2   
3+  3  im…  3  im… 
4+  4   …  4   … 
5+       5 +  … 
6+  5  )   6  ) 
7+  6     7   
8+  7  fu…  8  fu… 
9+  …  @@…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  fu… 12  fu… 
13+ 12 -  … 13 +  … 
14+      14 +  … 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf020.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ …  …   
2+  2     2   
3+  3  imp…  3  imp…
4+  4   …  4   …
5+       5 +  …
6+  5  )   6  ) 
7+  6     7   
8+  7  fun…  8  fun…
9+  …  @@ …  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  fun… 12  fun…
13+ 12 -  … 13 +  …
14+      14 +  …
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf021.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ …  …   
2+  2     2   
3+  3  imp…  3  imp… 
4+  4   …  4   … 
5+       5 +  … 
6+  5  )   6  ) 
7+  6     7   
8+  7  fun…  8  fun… 
9+  …  @@ …  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  fun… 12  fun… 
13+ 12 -  … 13 +  … 
14+      14 +  … 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf022.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -…  …   
2+  2     2   
3+  3  impo…  3  impo…
4+  4   …  4   …
5+       5 +  …
6+  5  )   6  ) 
7+  6     7   
8+  7  func…  8  func…
9+  …  @@ -…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func… 12  func…
13+ 12 -  … 13 +  …
14+      14 +  …
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf023.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -…  …   
2+  2     2   
3+  3  impo…  3  impo… 
4+  4   …  4   … 
5+       5 +  … 
6+  5  )   6  ) 
7+  6     7   
8+  7  func…  8  func… 
9+  …  @@ -…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func… 12  func… 
13+ 12 -  … 13 +  … 
14+      14 +  … 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf024.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2…  …   
2+  2     2   
3+  3  impor…  3  impor…
4+  4   "…  4   "…
5+       5 +  "…
6+  5  )   6  ) 
7+  6     7   
8+  7  func …  8  func …
9+  …  @@ -9…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func … 12  func …
13+ 12 -  r… 13 +  c…
14+      14 +  r…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf025.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2…  …   
2+  2     2   
3+  3  impor…  3  impor… 
4+  4   "…  4   "… 
5+       5 +  "… 
6+  5  )   6  ) 
7+  6     7   
8+  7  func …  8  func … 
9+  …  @@ -9…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func … 12  func … 
13+ 12 -  r… 13 +  c… 
14+      14 +  r… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf026.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,…  …   
2+  2     2   
3+  3  import…  3  import…
4+  4   "f…  4   "f…
5+       5 +  "s…
6+  5  )   6  ) 
7+  6     7   
8+  7  func m…  8  func m…
9+  …  @@ -9,…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func g… 12  func g…
13+ 12 -  re… 13 +  co…
14+      14 +  re…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf027.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,…  …   
2+  2     2   
3+  3  import…  3  import… 
4+  4   "f…  4   "f… 
5+       5 +  "s… 
6+  5  )   6  ) 
7+  6     7   
8+  7  func m…  8  func m… 
9+  …  @@ -9,…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func g… 12  func g… 
13+ 12 -  re… 13 +  co… 
14+      14 +  re… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf028.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6…  …   
2+  2     2   
3+  3  import (  3  import (
4+  4   "fm…  4   "fm…
5+       5 +  "st…
6+  5  )   6  ) 
7+  6     7   
8+  7  func ma…  8  func ma…
9+  …  @@ -9,5…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func ge… 12  func ge…
13+ 12 -  ret… 13 +  con…
14+      14 +  ret…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf029.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6…  …   
2+  2     2   
3+  3  import (  3  import ( 
4+  4   "fm…  4   "fm… 
5+       5 +  "st… 
6+  5  )   6  ) 
7+  6     7   
8+  7  func ma…  8  func ma… 
9+  …  @@ -9,5…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func ge… 12  func ge… 
13+ 12 -  ret… 13 +  con… 
14+      14 +  ret… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf030.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 …  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"  4   "fmt"
5+       5 +  "str…
6+  5  )   6  ) 
7+  6     7   
8+  7  func mai…  8  func mai…
9+  …  @@ -9,5 …  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func get… 12  func get…
13+ 12 -  retu… 13 +  cont…
14+      14 +  retu…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf031.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 …  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"  4   "fmt" 
5+       5 +  "str… 
6+  5  )   6  ) 
7+  6     7   
8+  7  func mai…  8  func mai… 
9+  …  @@ -9,5 …  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func get… 12  func get… 
13+ 12 -  retu… 13 +  cont… 
14+      14 +  retu… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf032.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +…  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "stri…
6+  5  )   6  ) 
7+  6     7   
8+  7  func main…  8  func main…
9+  …  @@ -9,5 +…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getC… 12  func getC…
13+ 12 -  retur… 13 +  conte…
14+      14 +  retur…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf033.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +…  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "stri… 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main…  8  func main… 
9+  …  @@ -9,5 +…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getC… 12  func getC… 
13+ 12 -  retur… 13 +  conte… 
14+      14 +  retur… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf034.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2…  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strin…
6+  5  )   6  ) 
7+  6     7   
8+  7  func main(…  8  func main(…
9+  …  @@ -9,5 +1…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getCo… 12  func getCo…
13+ 12 -  return… 13 +  conten…
14+      14 +  return…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf035.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2…  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strin… 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main(…  8  func main(… 
9+  …  @@ -9,5 +1…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getCo… 12  func getCo… 
13+ 12 -  return… 13 +  conten… 
14+      14 +  return… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf036.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,…  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "string…
6+  5  )   6  ) 
7+  6     7   
8+  7  func main()…  8  func main()…
9+  …  @@ -9,5 +10…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getCon… 12  func getCon…
13+ 12 -  return … 13 +  content…
14+      14 +  return …
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf037.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,…  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "string… 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main()…  8  func main()… 
9+  …  @@ -9,5 +10…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getCon… 12  func getCon… 
13+ 12 -  return … 13 +  content… 
14+      14 +  return … 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf038.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7…  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings"
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {  8  func main() {
9+  …  @@ -9,5 +10,…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getCont… 12  func getCont…
13+ 12 -  return "… 13 +  content …
14+      14 +  return c…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf039.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7…  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {  8  func main() { 
9+  …  @@ -9,5 +10,…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getCont… 12  func getCont… 
13+ 12 -  return "… 13 +  content … 
14+      14 +  return c… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf040.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 …  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getConte… 12  func getConte…
13+ 12 -  return "H… 13 +  content :…
14+      14 +  return co…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf041.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 …  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getConte… 12  func getConte… 
13+ 12 -  return "H… 13 +  content :… 
14+      14 +  return co… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf042.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @…  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 …  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getConten… 12  func getConten…
13+ 12 -  return "He… 13 +  content :=…
14+      14 +  return con…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf043.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @…  …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 …  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getConten… 12  func getConten… 
13+ 12 -  return "He… 13 +  content :=… 
14+      14 +  return con… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf044.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@   …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent… 12  func getContent…
13+ 12 -  return "Hel… 13 +  content := …
14+      14 +  return cont…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf045.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@   …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @…  …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent… 12  func getContent… 
13+ 12 -  return "Hel… 13 +  content := … 
14+      14 +  return cont… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf046.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@   …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent(… 12  func getContent(…
13+ 12 -  return "Hell… 13 +  content := s…
14+      14 +  return conte…
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf047.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@   …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent(… 12  func getContent(… 
13+ 12 -  return "Hell… 13 +  content := s… 
14+      14 +  return conte… 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf048.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent()… 12  func getContent()…
13+ 12 -  return "Hello… 13 +  content := st…
14+      14 +  return content
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf049.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent()… 12  func getContent()… 
13+ 12 -  return "Hello… 13 +  content := st… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf050.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() … 12  func getContent() …
13+ 12 -  return "Hello,… 13 +  content := str…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf051.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() … 12  func getContent() … 
13+ 12 -  return "Hello,… 13 +  content := str… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf052.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() s… 12  func getContent() s…
13+ 12 -  return "Hello, … 13 +  content := stri…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf053.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() s… 12  func getContent() s… 
13+ 12 -  return "Hello, … 13 +  content := stri… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf054.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() st… 12  func getContent() st…
13+ 12 -  return "Hello, w… 13 +  content := strin…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf055.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() st… 12  func getContent() st… 
13+ 12 -  return "Hello, w… 13 +  content := strin… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf056.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() str… 12  func getContent() str…
13+ 12 -  return "Hello, wo… 13 +  content := string…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf057.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() str… 12  func getContent() str… 
13+ 12 -  return "Hello, wo… 13 +  content := string… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf058.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() stri… 12  func getContent() stri…
13+ 12 -  return "Hello, wor… 13 +  content := strings…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf059.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() stri… 12  func getContent() stri… 
13+ 12 -  return "Hello, wor… 13 +  content := strings… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf060.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() strin… 12  func getContent() strin…
13+ 12 -  return "Hello, worl… 13 +  content := strings.…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf061.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() strin… 12  func getContent() strin… 
13+ 12 -  return "Hello, worl… 13 +  content := strings.… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf062.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string… 12  func getContent() string…
13+ 12 -  return "Hello, world… 13 +  content := strings.T…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf063.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string… 12  func getContent() string… 
13+ 12 -  return "Hello, world… 13 +  content := strings.T… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf064.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string { 12  func getContent() string {
13+ 12 -  return "Hello, world!" 13 +  content := strings.To…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf065.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string { 12  func getContent() string { 
13+ 12 -  return "Hello, world!" 13 +  content := strings.To… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf066.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToU…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf067.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToU… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf068.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUp…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf069.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUp… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf070.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpp…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf071.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpp… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf072.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUppe…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf073.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUppe… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf074.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf075.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf076.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper(…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf077.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper(… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf078.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf079.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf080.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("H…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf081.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("H… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf082.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("He…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf083.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("He… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf084.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hel…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf085.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hel… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf086.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hell…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf087.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hell… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf088.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf089.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf090.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello,…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf091.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello,… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf092.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, …
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf093.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, … 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf094.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, W…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf095.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, W… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf096.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wo…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf097.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wo… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf098.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wor…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf099.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wor… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf100.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Worl…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf101.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Worl… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf102.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf103.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf104.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!…
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf105.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!… 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf106.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf107.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf108.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf109.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf110.goldennew file+15
@@ -0,0 +1,15 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+       5 +  "strings" 
6+  5  )   6  ) 
7+  6     7   
8+  7  func main() {   8  func main() { 
9+  …  @@ -9,5 +10,6 @@    …   
10+  9  }  10  } 
11+ 10    11   
12+ 11  func getContent() string {  12  func getContent() string { 
13+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
14+      14 +  return content 
15+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf001.goldennew file+16
@@ -0,0 +1,16 @@
1+ 
2+ 
3+ 
4+ 
5+ 
6+ 
7+ 
8+ 
9+ 
10+ 
11+ 
12+ 
13+ 
14+ 
15+ 
16+ 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf002.goldennew file+16
@@ -0,0 +1,16 @@
1+  
2+  
3+  
4+  
5+  
6+  
7+  
8+  
9+  
10+  
11+ 1
12+ 1
13+ 1
14+  
15+  
16+ 1
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf003.goldennew file+16
@@ -0,0 +1,16 @@
1+  …
2+  2
3+  3
4+  4
5+  
6+  5
7+  6
8+  7
9+  …
10+  9
11+ 10
12+ 11
13+ 12
14+  
15+  
16+ 13
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf004.goldennew file+16
@@ -0,0 +1,16 @@
1+  … 
2+  2 
3+  3 
4+  4 
5+   
6+  5 
7+  6 
8+  7 
9+  … 
10+  9 
11+ 10 
12+ 11 
13+ 12 
14+   
15+   
16+ 13 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf005.goldennew file+16
@@ -0,0 +1,16 @@
1+  …  
2+  2  
3+  3  
4+  4  
5+    
6+  5  
7+  6  
8+  7  
9+  …  
10+  9  
11+ 10  
12+ 11  
13+ 12  
14+    
15+    
16+ 13  
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf006.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   
2+  2   
3+  3   
4+  4   
5+     
6+  5   
7+  6   
8+  7   
9+  …   
10+  9  1
11+ 10  1
12+ 11  1
13+ 12   
14+    1
15+    1
16+ 13  1
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf007.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …
2+  2   2
3+  3   3
4+  4   4
5+     5
6+  5   6
7+  6   7
8+  7   8
9+  …   …
10+  9  10
11+ 10  11
12+ 11  12
13+ 12   
14+    13
15+    14
16+ 13  15
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf008.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   … 
2+  2   2 
3+  3   3 
4+  4   4 
5+     5 
6+  5   6 
7+  6   7 
8+  7   8 
9+  …   … 
10+  9  10 
11+ 10  11 
12+ 11  12 
13+ 12    
14+    13 
15+    14 
16+ 13  15 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf009.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   … …
2+  2   2  
3+  3   3  
4+  4   4  
5+     5 +
6+  5   6  
7+  6   7  
8+  7   8  
9+  …   … …
10+  9  10  
11+ 10  11  
12+ 11  12  
13+ 12    -
14+    13 +
15+    14 +
16+ 13  15  
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf010.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  …
2+  2   2  
3+  3   3  
4+  4   4  
5+     5 + 
6+  5   6  
7+  6   7  
8+  7   8  
9+  …   …  …
10+  9  10  
11+ 10  11  
12+ 11  12  
13+ 12    - 
14+    13 + 
15+    14 + 
16+ 13  15  
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf011.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  …
2+  2   2   
3+  3   3  …
4+  4   4  …
5+     5 + …
6+  5   6  )
7+  6   7   
8+  7   8  …
9+  …   …  …
10+  9  10  }
11+ 10  11   
12+ 11  12  …
13+ 12    - …
14+    13 + …
15+    14 + …
16+ 13  15  }
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf012.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @…
2+  2   2   
3+  3   3  i…
4+  4   4   …
5+     5 +  …
6+  5   6  ) 
7+  6   7   
8+  7   8  f…
9+  …   …  @…
10+  9  10  } 
11+ 10  11   
12+ 11  12  f…
13+ 12    -  …
14+    13 +  …
15+    14 +  …
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf013.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@…
2+  2   2   
3+  3   3  im…
4+  4   4   …
5+     5 +  …
6+  5   6  ) 
7+  6   7   
8+  7   8  fu…
9+  …   …  @@…
10+  9  10  } 
11+ 10  11   
12+ 11  12  fu…
13+ 12    -  …
14+    13 +  …
15+    14 +  …
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf014.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ …
2+  2   2   
3+  3   3  imp…
4+  4   4   …
5+     5 +  …
6+  5   6  ) 
7+  6   7   
8+  7   8  fun…
9+  …   …  @@ …
10+  9  10  } 
11+ 10  11   
12+ 11  12  fun…
13+ 12    -  …
14+    13 +  …
15+    14 +  …
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf015.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -…
2+  2   2   
3+  3   3  impo…
4+  4   4   …
5+     5 +  …
6+  5   6  ) 
7+  6   7   
8+  7   8  func…
9+  …   …  @@ -…
10+  9  10  } 
11+ 10  11   
12+ 11  12  func…
13+ 12    -  …
14+    13 +  …
15+    14 +  …
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf016.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2…
2+  2   2   
3+  3   3  impor…
4+  4   4   "…
5+     5 +  "…
6+  5   6  ) 
7+  6   7   
8+  7   8  func …
9+  …   …  @@ -9…
10+  9  10  } 
11+ 10  11   
12+ 11  12  func …
13+ 12    -  r…
14+    13 +  c…
15+    14 +  r…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf017.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,…
2+  2   2   
3+  3   3  import…
4+  4   4   "f…
5+     5 +  "s…
6+  5   6  ) 
7+  6   7   
8+  7   8  func m…
9+  …   …  @@ -9,…
10+  9  10  } 
11+ 10  11   
12+ 11  12  func g…
13+ 12    -  re…
14+    13 +  co…
15+    14 +  re…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf018.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6…
2+  2   2   
3+  3   3  import (
4+  4   4   "fm…
5+     5 +  "st…
6+  5   6  ) 
7+  6   7   
8+  7   8  func ma…
9+  …   …  @@ -9,5…
10+  9  10  } 
11+ 10  11   
12+ 11  12  func ge…
13+ 12    -  ret…
14+    13 +  con…
15+    14 +  ret…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf019.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 …
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt"
5+     5 +  "str…
6+  5   6  ) 
7+  6   7   
8+  7   8  func mai…
9+  …   …  @@ -9,5 …
10+  9  10  } 
11+ 10  11   
12+ 11  12  func get…
13+ 12    -  retu…
14+    13 +  cont…
15+    14 +  retu…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf020.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +…
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "stri…
6+  5   6  ) 
7+  6   7   
8+  7   8  func main…
9+  …   …  @@ -9,5 +…
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getC…
13+ 12    -  retur…
14+    13 +  conte…
15+    14 +  retur…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf021.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2…
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strin…
6+  5   6  ) 
7+  6   7   
8+  7   8  func main(…
9+  …   …  @@ -9,5 +1…
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getCo…
13+ 12    -  return…
14+    13 +  conten…
15+    14 +  return…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf022.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,…
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "string…
6+  5   6  ) 
7+  6   7   
8+  7   8  func main()…
9+  …   …  @@ -9,5 +10…
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getCon…
13+ 12    -  return …
14+    13 +  content…
15+    14 +  return …
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf023.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7…
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings"
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() {
9+  …   …  @@ -9,5 +10,…
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getCont…
13+ 12    -  return "…
14+    13 +  content …
15+    14 +  return c…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf024.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 …
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6…
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getConte…
13+ 12    -  return "H…
14+    13 +  content :…
15+    14 +  return co…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf025.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @…
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 …
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getConten…
13+ 12    -  return "He…
14+    13 +  content :=…
15+    14 +  return con…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf026.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@ 
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @…
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent…
13+ 12    -  return "Hel…
14+    13 +  content := …
15+    14 +  return cont…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf027.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@ 
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent(…
13+ 12    -  return "Hell…
14+    13 +  content := s…
15+    14 +  return conte…
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf028.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent()…
13+ 12    -  return "Hello…
14+    13 +  content := st…
15+    14 +  return content
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf029.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() …
13+ 12    -  return "Hello,…
14+    13 +  content := str…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf030.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() s…
13+ 12    -  return "Hello, …
14+    13 +  content := stri…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf031.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() st…
13+ 12    -  return "Hello, w…
14+    13 +  content := strin…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf032.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() str…
13+ 12    -  return "Hello, wo…
14+    13 +  content := string…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf033.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() stri…
13+ 12    -  return "Hello, wor…
14+    13 +  content := strings…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf034.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() strin…
13+ 12    -  return "Hello, worl…
14+    13 +  content := strings.…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf035.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string…
13+ 12    -  return "Hello, world…
14+    13 +  content := strings.T…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf036.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string {
13+ 12    -  return "Hello, world!"
14+    13 +  content := strings.To…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf037.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToU…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf038.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUp…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf039.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpp…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf040.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUppe…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf041.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf042.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper(…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf043.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf044.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("H…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf045.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("He…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf046.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hel…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf047.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hell…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf048.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf049.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello,…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf050.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, …
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf051.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, W…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf052.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, Wo…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf053.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, Wor…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf054.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, Worl…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf055.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf056.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!…
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf057.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!")
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf058.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf059.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf060.goldennew file+16
@@ -0,0 +1,16 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+     5 +  "strings" 
6+  5   6  ) 
7+  6   7   
8+  7   8  func main() { 
9+  …   …  @@ -9,5 +10,6 @@  
10+  9  10  } 
11+ 10  11   
12+ 11  12  func getContent() string { 
13+ 12    -  return "Hello, world!" 
14+    13 +  content := strings.ToUpper("Hello, World!") 
15+    14 +  return content 
16+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf00.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  )   5  ) 
3+  6     6   
4+  7  func main() {   7  func main() { 
5+  8 -  fmt.Println("Hello,…  8 +  content := "Hello, …
6+       9 +  fmt.Println(content)
7+  9  }  10  } 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf01.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …unc main() {   7  …unc main() { 
5+  8 -… fmt.Println("Hello, …  8 +… content := "Hello, w…
6+       9 +… fmt.Println(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf02.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …nc main() {   7  …nc main() { 
5+  8 -… fmt.Println("Hello, w…  8 +… content := "Hello, wo…
6+       9 +… fmt.Println(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf03.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …c main() {   7  …c main() { 
5+  8 -… fmt.Println("Hello, wo…  8 +… content := "Hello, wor…
6+       9 +… fmt.Println(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf04.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  … main() {   7  … main() { 
5+  8 -…fmt.Println("Hello, wor…  8 +…content := "Hello, worl…
6+       9 +…fmt.Println(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf05.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …main() {   7  …main() { 
5+  8 -…mt.Println("Hello, worl…  8 +…ontent := "Hello, world…
6+       9 +…mt.Println(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf06.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …ain() {   7  …ain() { 
5+  8 -…t.Println("Hello, world…  8 +…ntent := "Hello, world!"
6+       9 +…t.Println(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf07.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …in() {   7  …in() { 
5+  8 -….Println("Hello, world!…  8 +…tent := "Hello, world!" 
6+       9 +….Println(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf08.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …n() {   7  …n() { 
5+  8 -…Println("Hello, world!")  8 +…ent := "Hello, world!" 
6+       9 +…Println(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf09.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …() {   7  …() { 
5+  8 -…rintln("Hello, world!")   8 +…nt := "Hello, world!" 
6+       9 +…rintln(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf10.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …) {   7  …) { 
5+  8 -…intln("Hello, world!")   8 +…t := "Hello, world!" 
6+       9 +…intln(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf11.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  … {   7  … { 
5+  8 -…ntln("Hello, world!")   8 +… := "Hello, world!" 
6+       9 +…ntln(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf12.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …{   7  …{ 
5+  8 -…tln("Hello, world!")   8 +…:= "Hello, world!" 
6+       9 +…tln(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf13.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …   7  … 
5+  8 -…ln("Hello, world!")   8 +…= "Hello, world!" 
6+       9 +…ln(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf14.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …   7  … 
5+  8 -…n("Hello, world!")   8 +… "Hello, world!" 
6+       9 +…n(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf15.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …   7  … 
5+  8 -…("Hello, world!")   8 +…"Hello, world!" 
6+       9 +…(content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf16.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …   7  … 
5+  8 -…"Hello, world!")   8 +…Hello, world!" 
6+       9 +…content) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf17.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …   7  … 
5+  8 -…Hello, world!")   8 +…ello, world!" 
6+       9 +…ontent) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf18.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …   7  … 
5+  8 -…ello, world!")   8 +…llo, world!" 
6+       9 +…ntent) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf19.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …   7  … 
5+  8 -…llo, world!")   8 +…lo, world!" 
6+       9 +…tent) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf20.goldennew file+7
@@ -0,0 +1,7 @@
1+  …  @@ -5,5 +5,6 @@    …   
2+  5  …   5  … 
3+  6     6   
4+  7  …   7  … 
5+  8 -…lo, world!")   8 +…o, world!" 
6+       9 +…ent) 
7+  9  …  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf00.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  ) 
3+  6   6   
4+  7   7  func main() { 
5+  8    -  fmt.Println("Hello, world!") 
6+     8 +  content := "Hello, world!" 
7+     9 +  fmt.Println(content) 
8+  9  10  } 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf01.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  …unc main() { 
5+  8    -… fmt.Println("Hello, world!") 
6+     8 +… content := "Hello, world!" 
7+     9 +… fmt.Println(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf02.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  …nc main() { 
5+  8    -… fmt.Println("Hello, world!") 
6+     8 +… content := "Hello, world!" 
7+     9 +… fmt.Println(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf03.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  …c main() { 
5+  8    -… fmt.Println("Hello, world!") 
6+     8 +… content := "Hello, world!" 
7+     9 +… fmt.Println(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf04.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  … main() { 
5+  8    -…fmt.Println("Hello, world!") 
6+     8 +…content := "Hello, world!" 
7+     9 +…fmt.Println(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf05.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  …main() { 
5+  8    -…mt.Println("Hello, world!") 
6+     8 +…ontent := "Hello, world!" 
7+     9 +…mt.Println(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf06.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  …ain() { 
5+  8    -…t.Println("Hello, world!") 
6+     8 +…ntent := "Hello, world!" 
7+     9 +…t.Println(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf07.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  …in() { 
5+  8    -….Println("Hello, world!") 
6+     8 +…tent := "Hello, world!" 
7+     9 +….Println(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf08.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  …n() { 
5+  8    -…Println("Hello, world!") 
6+     8 +…ent := "Hello, world!" 
7+     9 +…Println(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf09.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  …() { 
5+  8    -…rintln("Hello, world!") 
6+     8 +…nt := "Hello, world!" 
7+     9 +…rintln(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf10.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  …) { 
5+  8    -…intln("Hello, world!") 
6+     8 +…t := "Hello, world!" 
7+     9 +…intln(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf11.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  … { 
5+  8    -…ntln("Hello, world!") 
6+     8 +… := "Hello, world!" 
7+     9 +…ntln(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf12.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  …{ 
5+  8    -…tln("Hello, world!") 
6+     8 +…:= "Hello, world!" 
7+     9 +…tln(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf13.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  … 
5+  8    -…ln("Hello, world!") 
6+     8 +…= "Hello, world!" 
7+     9 +…ln(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf14.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  … 
5+  8    -…n("Hello, world!") 
6+     8 +… "Hello, world!" 
7+     9 +…n(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf15.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  … 
5+  8    -…("Hello, world!") 
6+     8 +…"Hello, world!" 
7+     9 +…(content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf16.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  … 
5+  8    -…"Hello, world!") 
6+     8 +…Hello, world!" 
7+     9 +…content) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf17.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  … 
5+  8    -…Hello, world!") 
6+     8 +…ello, world!" 
7+     9 +…ontent) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf18.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  … 
5+  8    -…ello, world!") 
6+     8 +…llo, world!" 
7+     9 +…ntent) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf19.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  … 
5+  8    -…llo, world!") 
6+     8 +…lo, world!" 
7+     9 +…tent) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf20.goldennew file+8
@@ -0,0 +1,8 @@
1+  …   …  @@ -5,5 +5,6 @@  
2+  5   5  … 
3+  6   6  … 
4+  7   7  … 
5+  8    -…lo, world!") 
6+     8 +…o, world!" 
7+     9 +…ent) 
8+  9  10  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf00.goldennew file+5
@@ -0,0 +1,5 @@
1+  …  @@ -2,6 +2,7 @@    …   
2+  2     2   
3+  3  import (   3  import ( 
4+  4   "fmt"   4   "fmt" 
5+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf01.goldennew file+5
@@ -0,0 +1,5 @@
1+  2     2   
2+  3  import (   3  import ( 
3+  4   "fmt"   4   "fmt" 
4+       5 +  "strings" 
5+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf02.goldennew file+5
@@ -0,0 +1,5 @@
1+  3  import (   3  import ( 
2+  4   "fmt"   4   "fmt" 
3+       5 +  "strings" 
4+  5  )   6  ) 
5+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf03.goldennew file+5
@@ -0,0 +1,5 @@
1+  4   "fmt"   4   "fmt" 
2+       5 +  "strings" 
3+  5  )   6  ) 
4+  6     7   
5+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf04.goldennew file+5
@@ -0,0 +1,5 @@
1+       5 +  "strings" 
2+  5  )   6  ) 
3+  6     7   
4+  7  func main() {   8  func main() { 
5+  …  @@ -9,5 +10,6 @@    …   
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf05.goldennew file+5
@@ -0,0 +1,5 @@
1+  5  )   6  ) 
2+  6     7   
3+  7  func main() {   8  func main() { 
4+  …  @@ -9,5 +10,6 @@    …   
5+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf06.goldennew file+5
@@ -0,0 +1,5 @@
1+  6     7   
2+  7  func main() {   8  func main() { 
3+  …  @@ -9,5 +10,6 @@    …   
4+  9  }  10  } 
5+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf07.goldennew file+5
@@ -0,0 +1,5 @@
1+  7  func main() {   8  func main() { 
2+  …  @@ -9,5 +10,6 @@    …   
3+  9  }  10  } 
4+ 10    11   
5+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf08.goldennew file+5
@@ -0,0 +1,5 @@
1+  …  @@ -9,5 +10,6 @@    …   
2+  9  }  10  } 
3+ 10    11   
4+ 11  func getContent() string {  12  func getContent() string { 
5+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf09.goldennew file+5
@@ -0,0 +1,5 @@
1+  9  }  10  } 
2+ 10    11   
3+ 11  func getContent() string {  12  func getContent() string { 
4+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
5+  …  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf10.goldennew file+5
@@ -0,0 +1,5 @@
1+ 10    11   
2+ 11  func getContent() string {  12  func getContent() string { 
3+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
4+      14 +  return content 
5+ 13  }  15  } 
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf11.goldennew file+5
@@ -0,0 +1,5 @@
1+ 11  func getContent() string {  12  func getContent() string { 
2+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
3+      14 +  return content 
4+ 13  }  15  } 
5+          
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf12.goldennew file+5
@@ -0,0 +1,5 @@
1+ 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") 
2+      14 +  return content 
3+ 13  }  15  } 
4+          
5+          
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf13.goldennew file+5
@@ -0,0 +1,5 @@
1+      14 +  return content 
2+ 13  }  15  } 
3+          
4+          
5+          
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf14.goldennew file+5
@@ -0,0 +1,5 @@
1+ 13  }  15  } 
2+          
3+          
4+          
5+          
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf15.goldennew file+5
@@ -0,0 +1,5 @@
1+          
2+          
3+          
4+          
5+          
internal/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf16.goldennew file+5
@@ -0,0 +1,5 @@
1+          
2+          
3+          
4+          
5+          
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf00.goldennew file+5
@@ -0,0 +1,5 @@
1+  …   …  @@ -2,6 +2,7 @@  
2+  2   2   
3+  3   3  import ( 
4+  4   4   "fmt" 
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf01.goldennew file+5
@@ -0,0 +1,5 @@
1+  2   2   
2+  3   3  import ( 
3+  4   4   "fmt" 
4+     5 +  "strings" 
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf02.goldennew file+5
@@ -0,0 +1,5 @@
1+  3   3  import ( 
2+  4   4   "fmt" 
3+     5 +  "strings" 
4+  5   6  ) 
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf03.goldennew file+5
@@ -0,0 +1,5 @@
1+  4   4   "fmt" 
2+     5 +  "strings" 
3+  5   6  ) 
4+  6   7   
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf04.goldennew file+5
@@ -0,0 +1,5 @@
1+     5 +  "strings" 
2+  5   6  ) 
3+  6   7   
4+  7   8  func main() { 
5+  …   …  @@ -9,5 +10,6 @@  
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf05.goldennew file+5
@@ -0,0 +1,5 @@
1+  5   6  ) 
2+  6   7   
3+  7   8  func main() { 
4+  …   …  @@ -9,5 +10,6 @@  
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf06.goldennew file+5
@@ -0,0 +1,5 @@
1+  6   7   
2+  7   8  func main() { 
3+  …   …  @@ -9,5 +10,6 @@  
4+  9  10  } 
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf07.goldennew file+5
@@ -0,0 +1,5 @@
1+  7   8  func main() { 
2+  …   …  @@ -9,5 +10,6 @@  
3+  9  10  } 
4+ 10  11   
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf08.goldennew file+5
@@ -0,0 +1,5 @@
1+  …   …  @@ -9,5 +10,6 @@  
2+  9  10  } 
3+ 10  11   
4+ 11  12  func getContent() string { 
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf09.goldennew file+5
@@ -0,0 +1,5 @@
1+  9  10  } 
2+ 10  11   
3+ 11  12  func getContent() string { 
4+ 12    -  return "Hello, world!" 
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf10.goldennew file+5
@@ -0,0 +1,5 @@
1+ 10  11   
2+ 11  12  func getContent() string { 
3+ 12    -  return "Hello, world!" 
4+    13 +  content := strings.ToUpper("Hello, World!") 
5+  …   …  … 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf11.goldennew file+5
@@ -0,0 +1,5 @@
1+ 11  12  func getContent() string { 
2+ 12    -  return "Hello, world!" 
3+    13 +  content := strings.ToUpper("Hello, World!") 
4+    14 +  return content 
5+ 13  15  } 
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf12.goldennew file+5
@@ -0,0 +1,5 @@
1+ 12    -  return "Hello, world!" 
2+    13 +  content := strings.ToUpper("Hello, World!") 
3+    14 +  return content 
4+ 13  15  } 
5+        
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf13.goldennew file+5
@@ -0,0 +1,5 @@
1+    13 +  content := strings.ToUpper("Hello, World!") 
2+    14 +  return content 
3+ 13  15  } 
4+        
5+        
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf14.goldennew file+5
@@ -0,0 +1,5 @@
1+    14 +  return content 
2+ 13  15  } 
3+        
4+        
5+        
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf15.goldennew file+5
@@ -0,0 +1,5 @@
1+ 13  15  } 
2+        
3+        
4+        
5+        
internal/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf16.goldennew file+5
@@ -0,0 +1,5 @@
1+        
2+        
3+        
4+        
5+        
internal/exp/diffview/testdata/TestMultipleHunks.afternew file+15
@@ -0,0 +1,15 @@
1+package main
2+
3+import (
4+ "fmt"
5+ "strings"
6+)
7+
8+func main() {
9+ fmt.Println(getContent())
10+}
11+
12+func getContent() string {
13+ content := strings.ToUpper("Hello, World!")
14+ return content
15+}
internal/exp/diffview/testdata/TestMultipleHunks.beforenew file+13
@@ -0,0 +1,13 @@
1+package main
2+
3+import (
4+ "fmt"
5+)
6+
7+func main() {
8+ fmt.Println(getContent())
9+}
10+
11+func getContent() string {
12+ return "Hello, world!"
13+}
internal/exp/diffview/testdata/TestNarrow.afternew file+3
@@ -0,0 +1,3 @@
1+d
2+e
3+f
internal/exp/diffview/testdata/TestNarrow.beforenew file+3
@@ -0,0 +1,3 @@
1+a
2+b
3+c
internal/exp/diffview/testdata/TestTabs.afternew file+15
@@ -0,0 +1,15 @@
1+package main
2+
3+import (
4+ "fmt"
5+ "strings"
6+)
7+
8+func main() {
9+ fmt.Println(getContent())
10+}
11+
12+func getContent() string {
13+ content := strings.ToUpper("Hello, World!")
14+ return content
15+}
internal/exp/diffview/testdata/TestTabs.beforenew file+13
@@ -0,0 +1,13 @@
1+package main
2+
3+import (
4+ "fmt"
5+)
6+
7+func main() {
8+ fmt.Println(getContent())
9+}
10+
11+func getContent() string {
12+ return "Hello, world!"
13+}
internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLines/Content.goldennew file+11
@@ -0,0 +1,11 @@
1+--- main.go
2++++ main.go
3+@@ -5,5 +5,6 @@
4+ )
5+
6+ func main() {
7+- fmt.Println("Hello, World!")
8++ content := "Hello, World!"
9++ fmt.Println(content)
10+ }
11+\ No newline at end of file
internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLines/JSON.goldennew file+40
@@ -0,0 +1,40 @@
1+{
2+ "From": "main.go",
3+ "To": "main.go",
4+ "Hunks": [
5+ {
6+ "FromLine": 5,
7+ "ToLine": 5,
8+ "Lines": [
9+ {
10+ "Kind": 2,
11+ "Content": "\t)\n"
12+ },
13+ {
14+ "Kind": 2,
15+ "Content": "\n"
16+ },
17+ {
18+ "Kind": 2,
19+ "Content": "\tfunc main() {\n"
20+ },
21+ {
22+ "Kind": 0,
23+ "Content": "\t\tfmt.Println(\"Hello, World!\")\n"
24+ },
25+ {
26+ "Kind": 1,
27+ "Content": "\t\tcontent := \"Hello, World!\"\n"
28+ },
29+ {
30+ "Kind": 1,
31+ "Content": "\t\tfmt.Println(content)\n"
32+ },
33+ {
34+ "Kind": 2,
35+ "Content": "\t}"
36+ }
37+ ]
38+ }
39+ ]
40+}
internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusOne/Content.goldennew file+12
@@ -0,0 +1,12 @@
1+--- main.go
2++++ main.go
3+@@ -4,6 +4,7 @@
4+ "fmt"
5+ )
6+
7+ func main() {
8+- fmt.Println("Hello, World!")
9++ content := "Hello, World!"
10++ fmt.Println(content)
11+ }
12+\ No newline at end of file
internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusOne/JSON.goldennew file+44
@@ -0,0 +1,44 @@
1+{
2+ "From": "main.go",
3+ "To": "main.go",
4+ "Hunks": [
5+ {
6+ "FromLine": 4,
7+ "ToLine": 4,
8+ "Lines": [
9+ {
10+ "Kind": 2,
11+ "Content": "\t\t\"fmt\"\n"
12+ },
13+ {
14+ "Kind": 2,
15+ "Content": "\t)\n"
16+ },
17+ {
18+ "Kind": 2,
19+ "Content": "\n"
20+ },
21+ {
22+ "Kind": 2,
23+ "Content": "\tfunc main() {\n"
24+ },
25+ {
26+ "Kind": 0,
27+ "Content": "\t\tfmt.Println(\"Hello, World!\")\n"
28+ },
29+ {
30+ "Kind": 1,
31+ "Content": "\t\tcontent := \"Hello, World!\"\n"
32+ },
33+ {
34+ "Kind": 1,
35+ "Content": "\t\tfmt.Println(content)\n"
36+ },
37+ {
38+ "Kind": 2,
39+ "Content": "\t}"
40+ }
41+ ]
42+ }
43+ ]
44+}
internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusTwo/Content.goldennew file+13
@@ -0,0 +1,13 @@
1+--- main.go
2++++ main.go
3+@@ -3,7 +3,8 @@
4+ import (
5+ "fmt"
6+ )
7+
8+ func main() {
9+- fmt.Println("Hello, World!")
10++ content := "Hello, World!"
11++ fmt.Println(content)
12+ }
13+\ No newline at end of file
internal/exp/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusTwo/JSON.goldennew file+48
@@ -0,0 +1,48 @@
1+{
2+ "From": "main.go",
3+ "To": "main.go",
4+ "Hunks": [
5+ {
6+ "FromLine": 3,
7+ "ToLine": 3,
8+ "Lines": [
9+ {
10+ "Kind": 2,
11+ "Content": "\timport (\n"
12+ },
13+ {
14+ "Kind": 2,
15+ "Content": "\t\t\"fmt\"\n"
16+ },
17+ {
18+ "Kind": 2,
19+ "Content": "\t)\n"
20+ },
21+ {
22+ "Kind": 2,
23+ "Content": "\n"
24+ },
25+ {
26+ "Kind": 2,
27+ "Content": "\tfunc main() {\n"
28+ },
29+ {
30+ "Kind": 0,
31+ "Content": "\t\tfmt.Println(\"Hello, World!\")\n"
32+ },
33+ {
34+ "Kind": 1,
35+ "Content": "\t\tcontent := \"Hello, World!\"\n"
36+ },
37+ {
38+ "Kind": 1,
39+ "Content": "\t\tfmt.Println(content)\n"
40+ },
41+ {
42+ "Kind": 2,
43+ "Content": "\t}"
44+ }
45+ ]
46+ }
47+ ]
48+}
internal/exp/diffview/testdata/TestUdiff/Unified.goldennew file+11
@@ -0,0 +1,11 @@
1+--- main.go
2++++ main.go
3+@@ -5,5 +5,6 @@
4+ )
5+
6+ func main() {
7+- fmt.Println("Hello, World!")
8++ content := "Hello, World!"
9++ fmt.Println(content)
10+ }
11+\ No newline at end of file
internal/exp/diffview/udiff_test.gonew file+92
@@ -0,0 +1,92 @@
1+package diffview_test
2+
3+import (
4+ "bytes"
5+ "encoding/json"
6+ "testing"
7+
8+ "github.com/aymanbagabas/go-udiff"
9+ "github.com/aymanbagabas/go-udiff/myers"
10+ "github.com/charmbracelet/x/exp/golden"
11+)
12+
13+func TestUdiff(t *testing.T) {
14+ before := `package main
15+
16+ import (
17+ "fmt"
18+ )
19+
20+ func main() {
21+ fmt.Println("Hello, World!")
22+ }`
23+
24+ after := `package main
25+
26+ import (
27+ "fmt"
28+ )
29+
30+ func main() {
31+ content := "Hello, World!"
32+ fmt.Println(content)
33+ }`
34+
35+ t.Run("Unified", func(t *testing.T) {
36+ content := udiff.Unified("main.go", "main.go", before, after)
37+ golden.RequireEqual(t, []byte(content))
38+ })
39+
40+ t.Run("ToUnifiedDiff", func(t *testing.T) {
41+ toUnifiedDiff := func(t *testing.T, before, after string, contextLines int) udiff.UnifiedDiff {
42+ edits := myers.ComputeEdits(before, after) //nolint:staticcheck
43+ unifiedDiff, err := udiff.ToUnifiedDiff("main.go", "main.go", before, edits, contextLines)
44+ if err != nil {
45+ t.Fatalf("ToUnifiedDiff failed: %v", err)
46+ }
47+ return unifiedDiff
48+ }
49+ toJSON := func(t *testing.T, unifiedDiff udiff.UnifiedDiff) []byte {
50+ var buff bytes.Buffer
51+ encoder := json.NewEncoder(&buff)
52+ encoder.SetIndent("", " ")
53+ if err := encoder.Encode(unifiedDiff); err != nil {
54+ t.Fatalf("Failed to encode unified diff: %v", err)
55+ }
56+ return buff.Bytes()
57+ }
58+
59+ t.Run("DefaultContextLines", func(t *testing.T) {
60+ unifiedDiff := toUnifiedDiff(t, before, after, udiff.DefaultContextLines)
61+
62+ t.Run("Content", func(t *testing.T) {
63+ golden.RequireEqual(t, []byte(unifiedDiff.String()))
64+ })
65+ t.Run("JSON", func(t *testing.T) {
66+ golden.RequireEqual(t, toJSON(t, unifiedDiff))
67+ })
68+ })
69+
70+ t.Run("DefaultContextLinesPlusOne", func(t *testing.T) {
71+ unifiedDiff := toUnifiedDiff(t, before, after, udiff.DefaultContextLines+1)
72+
73+ t.Run("Content", func(t *testing.T) {
74+ golden.RequireEqual(t, []byte(unifiedDiff.String()))
75+ })
76+ t.Run("JSON", func(t *testing.T) {
77+ golden.RequireEqual(t, toJSON(t, unifiedDiff))
78+ })
79+ })
80+
81+ t.Run("DefaultContextLinesPlusTwo", func(t *testing.T) {
82+ unifiedDiff := toUnifiedDiff(t, before, after, udiff.DefaultContextLines+2)
83+
84+ t.Run("Content", func(t *testing.T) {
85+ golden.RequireEqual(t, []byte(unifiedDiff.String()))
86+ })
87+ t.Run("JSON", func(t *testing.T) {
88+ golden.RequireEqual(t, toJSON(t, unifiedDiff))
89+ })
90+ })
91+ })
92+}
internal/exp/diffview/util.gonew file+39
@@ -0,0 +1,39 @@
1+package diffview
2+
3+import (
4+ "fmt"
5+ "strings"
6+
7+ "github.com/charmbracelet/x/ansi"
8+)
9+
10+func pad(v any, width int) string {
11+ s := fmt.Sprintf("%v", v)
12+ w := ansi.StringWidth(s)
13+ if w >= width {
14+ return s
15+ }
16+ return strings.Repeat(" ", width-w) + s
17+}
18+
19+func isEven(n int) bool {
20+ return n%2 == 0
21+}
22+
23+func isOdd(n int) bool {
24+ return !isEven(n)
25+}
26+
27+func btoi(b bool) int {
28+ if b {
29+ return 1
30+ }
31+ return 0
32+}
33+
34+func ternary[T any](cond bool, t, f T) T {
35+ if cond {
36+ return t
37+ }
38+ return f
39+}
internal/exp/diffview/util_test.gonew file+27
@@ -0,0 +1,27 @@
1+package diffview
2+
3+import (
4+ "testing"
5+)
6+
7+func TestPad(t *testing.T) {
8+ tests := []struct {
9+ input any
10+ width int
11+ expected string
12+ }{
13+ {7, 2, " 7"},
14+ {7, 3, " 7"},
15+ {"a", 2, " a"},
16+ {"a", 3, " a"},
17+ {"…", 2, " …"},
18+ {"…", 3, " …"},
19+ }
20+
21+ for _, tt := range tests {
22+ result := pad(tt.input, tt.width)
23+ if result != tt.expected {
24+ t.Errorf("expected %q, got %q", tt.expected, result)
25+ }
26+ }
27+}
internal/fileutil/fileutil.go+24
@@ -211,3 +211,27 @@ func PrettyPath(path string) string {
211211 }
212212 return path
213213}
214+
215+func DirTrim(pwd string, lim int) string {
216+ var (
217+ out string
218+ sep = string(filepath.Separator)
219+ )
220+ dirs := strings.Split(pwd, sep)
221+ if lim > len(dirs)-1 || lim <= 0 {
222+ return pwd
223+ }
224+ for i := len(dirs) - 1; i > 0; i-- {
225+ out = sep + out
226+ if i == len(dirs)-1 {
227+ out = dirs[i]
228+ } else if i >= len(dirs)-lim {
229+ out = string(dirs[i][0]) + out
230+ } else {
231+ out = "..." + out
232+ break
233+ }
234+ }
235+ out = filepath.Join("~", out)
236+ return out
237+}
internal/llm/agent/tools.go−1
@@ -33,7 +33,6 @@ func CoderAgentTools(
3333 tools.NewLsTool(),
3434 tools.NewSourcegraphTool(),
3535 tools.NewViewTool(lspClients),
36− tools.NewPatchTool(lspClients, permissions, history),
3736 tools.NewWriteTool(lspClients, permissions, history),
3837 NewAgentTool(sessions, messages, lspClients),
3938 }, otherTools...,
internal/llm/tools/edit.go+31−23
@@ -24,14 +24,16 @@ type EditParams struct {
2424}
2525
2626type EditPermissionsParams struct {
27− FilePath string `json:"file_path"`
28− Diff string `json:"diff"`
27+ FilePath string `json:"file_path"`
28+ OldContent string `json:"old_content,omitempty"`
29+ NewContent string `json:"new_content,omitempty"`
2930}
3031
3132type EditResponseMetadata struct {
32− Diff string `json:"diff"`
33− Additions int `json:"additions"`
34− Removals int `json:"removals"`
33+ Additions int `json:"additions"`
34+ Removals int `json:"removals"`
35+ OldContent string `json:"old_content,omitempty"`
36+ NewContent string `json:"new_content,omitempty"`
3537}
3638
3739type editTool struct {
@@ -191,7 +193,7 @@ func (e *editTool) createNewFile(ctx context.Context, filePath, content string)
191193 return ToolResponse{}, fmt.Errorf("session ID and message ID are required for creating a new file")
192194 }
193195
194− diff, additions, removals := diff.GenerateDiff(
196+ _, additions, removals := diff.GenerateDiff(
195197 "",
196198 content,
197199 filePath,
@@ -209,8 +211,9 @@ func (e *editTool) createNewFile(ctx context.Context, filePath, content string)
209211 Action: "write",
210212 Description: fmt.Sprintf("Create file %s", filePath),
211213 Params: EditPermissionsParams{
212− FilePath: filePath,
213− Diff: diff,
214+ FilePath: filePath,
215+ OldContent: "",
216+ NewContent: content,
214217 },
215218 },
216219 )
@@ -243,9 +246,10 @@ func (e *editTool) createNewFile(ctx context.Context, filePath, content string)
243246 return WithResponseMetadata(
244247 NewTextResponse("File created: "+filePath),
245248 EditResponseMetadata{
246− Diff: diff,
247− Additions: additions,
248− Removals: removals,
249+ OldContent: "",
250+ NewContent: content,
251+ Additions: additions,
252+ Removals: removals,
249253 },
250254 ), nil
251255}
@@ -301,7 +305,7 @@ func (e *editTool) deleteContent(ctx context.Context, filePath, oldString string
301305 return ToolResponse{}, fmt.Errorf("session ID and message ID are required for creating a new file")
302306 }
303307
304− diff, additions, removals := diff.GenerateDiff(
308+ _, additions, removals := diff.GenerateDiff(
305309 oldContent,
306310 newContent,
307311 filePath,
@@ -320,8 +324,9 @@ func (e *editTool) deleteContent(ctx context.Context, filePath, oldString string
320324 Action: "write",
321325 Description: fmt.Sprintf("Delete content from file %s", filePath),
322326 Params: EditPermissionsParams{
323− FilePath: filePath,
324− Diff: diff,
327+ FilePath: filePath,
328+ OldContent: oldContent,
329+ NewContent: newContent,
325330 },
326331 },
327332 )
@@ -362,9 +367,10 @@ func (e *editTool) deleteContent(ctx context.Context, filePath, oldString string
362367 return WithResponseMetadata(
363368 NewTextResponse("Content deleted from file: "+filePath),
364369 EditResponseMetadata{
365− Diff: diff,
366− Additions: additions,
367− Removals: removals,
370+ OldContent: oldContent,
371+ NewContent: newContent,
372+ Additions: additions,
373+ Removals: removals,
368374 },
369375 ), nil
370376}
@@ -422,7 +428,7 @@ func (e *editTool) replaceContent(ctx context.Context, filePath, oldString, newS
422428 if sessionID == "" || messageID == "" {
423429 return ToolResponse{}, fmt.Errorf("session ID and message ID are required for creating a new file")
424430 }
425− diff, additions, removals := diff.GenerateDiff(
431+ _, additions, removals := diff.GenerateDiff(
426432 oldContent,
427433 newContent,
428434 filePath,
@@ -440,8 +446,9 @@ func (e *editTool) replaceContent(ctx context.Context, filePath, oldString, newS
440446 Action: "write",
441447 Description: fmt.Sprintf("Replace content in file %s", filePath),
442448 Params: EditPermissionsParams{
443− FilePath: filePath,
444− Diff: diff,
449+ FilePath: filePath,
450+ OldContent: oldContent,
451+ NewContent: newContent,
445452 },
446453 },
447454 )
@@ -482,8 +489,9 @@ func (e *editTool) replaceContent(ctx context.Context, filePath, oldString, newS
482489 return WithResponseMetadata(
483490 NewTextResponse("Content replaced in file: "+filePath),
484491 EditResponseMetadata{
485− Diff: diff,
486− Additions: additions,
487− Removals: removals,
492+ OldContent: oldContent,
493+ NewContent: newContent,
494+ Additions: additions,
495+ Removals: removals,
488496 }), nil
489497}
internal/llm/tools/fetch.go+12−6
@@ -69,6 +69,11 @@ func NewFetchTool(permissions permission.Service) BaseTool {
6969 return &fetchTool{
7070 client: &http.Client{
7171 Timeout: 30 * time.Second,
72+ Transport: &http.Transport{
73+ MaxIdleConns: 100,
74+ MaxIdleConnsPerHost: 10,
75+ IdleConnTimeout: 90 * time.Second,
76+ },
7277 },
7378 permissions: permissions,
7479 }
@@ -136,25 +141,26 @@ func (t *fetchTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
136141 return ToolResponse{}, permission.ErrorPermissionDenied
137142 }
138143
139− client := t.client
144+ // Handle timeout with context
145+ requestCtx := ctx
140146 if params.Timeout > 0 {
141147 maxTimeout := 120 // 2 minutes
142148 if params.Timeout > maxTimeout {
143149 params.Timeout = maxTimeout
144150 }
145− client = &http.Client{
146− Timeout: time.Duration(params.Timeout) * time.Second,
147− }
151+ var cancel context.CancelFunc
152+ requestCtx, cancel = context.WithTimeout(ctx, time.Duration(params.Timeout)*time.Second)
153+ defer cancel()
148154 }
149155
150− req, err := http.NewRequestWithContext(ctx, "GET", params.URL, nil)
156+ req, err := http.NewRequestWithContext(requestCtx, "GET", params.URL, nil)
151157 if err != nil {
152158 return ToolResponse{}, fmt.Errorf("failed to create request: %w", err)
153159 }
154160
155161 req.Header.Set("User-Agent", "crush/1.0")
156162
157− resp, err := client.Do(req)
163+ resp, err := t.client.Do(req)
158164 if err != nil {
159165 return ToolResponse{}, fmt.Errorf("failed to fetch URL: %w", err)
160166 }
internal/llm/tools/grep.go+47
@@ -5,6 +5,7 @@ import (
55 "context"
66 "encoding/json"
77 "fmt"
8+ "io"
89 "os"
910 "os/exec"
1011 "path/filepath"
@@ -377,6 +378,11 @@ func searchFilesWithRegex(pattern, rootPath, include string) ([]grepMatch, error
377378}
378379
379380func fileContainsPattern(filePath string, pattern *regexp.Regexp) (bool, int, string, error) {
381+ // Quick binary file detection
382+ if isBinaryFile(filePath) {
383+ return false, 0, "", nil
384+ }
385+
380386 file, err := os.Open(filePath)
381387 if err != nil {
382388 return false, 0, "", err
@@ -396,6 +402,47 @@ func fileContainsPattern(filePath string, pattern *regexp.Regexp) (bool, int, st
396402 return false, 0, "", scanner.Err()
397403}
398404
405+var binaryExts = map[string]struct{}{
406+ ".exe": {}, ".dll": {}, ".so": {}, ".dylib": {},
407+ ".bin": {}, ".obj": {}, ".o": {}, ".a": {},
408+ ".zip": {}, ".tar": {}, ".gz": {}, ".bz2": {},
409+ ".jpg": {}, ".jpeg": {}, ".png": {}, ".gif": {},
410+ ".pdf": {}, ".doc": {}, ".docx": {}, ".xls": {},
411+ ".mp3": {}, ".mp4": {}, ".avi": {}, ".mov": {},
412+}
413+
414+// isBinaryFile performs a quick check to determine if a file is binary
415+func isBinaryFile(filePath string) bool {
416+ // Check file extension first (fastest)
417+ ext := strings.ToLower(filepath.Ext(filePath))
418+ if _, isBinary := binaryExts[ext]; isBinary {
419+ return true
420+ }
421+
422+ // Quick content check for files without clear extensions
423+ file, err := os.Open(filePath)
424+ if err != nil {
425+ return false // If we can't open it, let the caller handle the error
426+ }
427+ defer file.Close()
428+
429+ // Read first 512 bytes to check for null bytes
430+ buffer := make([]byte, 512)
431+ n, err := file.Read(buffer)
432+ if err != nil && err != io.EOF {
433+ return false
434+ }
435+
436+ // Check for null bytes (common in binary files)
437+ for i := range n {
438+ if buffer[i] == 0 {
439+ return true
440+ }
441+ }
442+
443+ return false
444+}
445+
399446func globToRegex(glob string) string {
400447 regexPattern := strings.ReplaceAll(glob, ".", "\\.")
401448 regexPattern = strings.ReplaceAll(regexPattern, "*", ".*")
internal/llm/tools/patch.godeleted−372
@@ -1,372 +0,0 @@
1−package tools
2−
3−import (
4− "context"
5− "encoding/json"
6− "fmt"
7− "os"
8− "path/filepath"
9− "time"
10−
11− "github.com/charmbracelet/crush/internal/config"
12− "github.com/charmbracelet/crush/internal/diff"
13− "github.com/charmbracelet/crush/internal/history"
14− "github.com/charmbracelet/crush/internal/logging"
15− "github.com/charmbracelet/crush/internal/lsp"
16− "github.com/charmbracelet/crush/internal/permission"
17−)
18−
19−type PatchParams struct {
20− PatchText string `json:"patch_text"`
21−}
22−
23−type PatchResponseMetadata struct {
24− FilesChanged []string `json:"files_changed"`
25− Additions int `json:"additions"`
26− Removals int `json:"removals"`
27−}
28−
29−type patchTool struct {
30− lspClients map[string]*lsp.Client
31− permissions permission.Service
32− files history.Service
33−}
34−
35−const (
36− PatchToolName = "patch"
37− patchDescription = `Applies a patch to multiple files in one operation. This tool is useful for making coordinated changes across multiple files.
38−
39−The patch text must follow this format:
40−*** Begin Patch
41−*** Update File: /path/to/file
42−@@ Context line (unique within the file)
43− Line to keep
44−-Line to remove
45−+Line to add
46− Line to keep
47−*** Add File: /path/to/new/file
48−+Content of the new file
49−+More content
50−*** Delete File: /path/to/file/to/delete
51−*** End Patch
52−
53−Before using this tool:
54−1. Use the FileRead tool to understand the files' contents and context
55−2. Verify all file paths are correct (use the LS tool)
56−
57−CRITICAL REQUIREMENTS FOR USING THIS TOOL:
58−
59−1. UNIQUENESS: Context lines MUST uniquely identify the specific sections you want to change
60−2. PRECISION: All whitespace, indentation, and surrounding code must match exactly
61−3. VALIDATION: Ensure edits result in idiomatic, correct code
62−4. PATHS: Always use absolute file paths (starting with /)
63−
64−The tool will apply all changes in a single atomic operation.`
65−)
66−
67−func NewPatchTool(lspClients map[string]*lsp.Client, permissions permission.Service, files history.Service) BaseTool {
68− return &patchTool{
69− lspClients: lspClients,
70− permissions: permissions,
71− files: files,
72− }
73−}
74−
75−func (p *patchTool) Info() ToolInfo {
76− return ToolInfo{
77− Name: PatchToolName,
78− Description: patchDescription,
79− Parameters: map[string]any{
80− "patch_text": map[string]any{
81− "type": "string",
82− "description": "The full patch text that describes all changes to be made",
83− },
84− },
85− Required: []string{"patch_text"},
86− }
87−}
88−
89−func (p *patchTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error) {
90− var params PatchParams
91− if err := json.Unmarshal([]byte(call.Input), &params); err != nil {
92− return NewTextErrorResponse("invalid parameters"), nil
93− }
94−
95− if params.PatchText == "" {
96− return NewTextErrorResponse("patch_text is required"), nil
97− }
98−
99− // Identify all files needed for the patch and verify they've been read
100− filesToRead := diff.IdentifyFilesNeeded(params.PatchText)
101− for _, filePath := range filesToRead {
102− absPath := filePath
103− if !filepath.IsAbs(absPath) {
104− wd := config.WorkingDirectory()
105− absPath = filepath.Join(wd, absPath)
106− }
107−
108− if getLastReadTime(absPath).IsZero() {
109− return NewTextErrorResponse(fmt.Sprintf("you must read the file %s before patching it. Use the FileRead tool first", filePath)), nil
110− }
111−
112− fileInfo, err := os.Stat(absPath)
113− if err != nil {
114− if os.IsNotExist(err) {
115− return NewTextErrorResponse(fmt.Sprintf("file not found: %s", absPath)), nil
116− }
117− return ToolResponse{}, fmt.Errorf("failed to access file: %w", err)
118− }
119−
120− if fileInfo.IsDir() {
121− return NewTextErrorResponse(fmt.Sprintf("path is a directory, not a file: %s", absPath)), nil
122− }
123−
124− modTime := fileInfo.ModTime()
125− lastRead := getLastReadTime(absPath)
126− if modTime.After(lastRead) {
127− return NewTextErrorResponse(
128− fmt.Sprintf("file %s has been modified since it was last read (mod time: %s, last read: %s)",
129− absPath, modTime.Format(time.RFC3339), lastRead.Format(time.RFC3339),
130− )), nil
131− }
132− }
133−
134− // Check for new files to ensure they don't already exist
135− filesToAdd := diff.IdentifyFilesAdded(params.PatchText)
136− for _, filePath := range filesToAdd {
137− absPath := filePath
138− if !filepath.IsAbs(absPath) {
139− wd := config.WorkingDirectory()
140− absPath = filepath.Join(wd, absPath)
141− }
142−
143− _, err := os.Stat(absPath)
144− if err == nil {
145− return NewTextErrorResponse(fmt.Sprintf("file already exists and cannot be added: %s", absPath)), nil
146− } else if !os.IsNotExist(err) {
147− return ToolResponse{}, fmt.Errorf("failed to check file: %w", err)
148− }
149− }
150−
151− // Load all required files
152− currentFiles := make(map[string]string)
153− for _, filePath := range filesToRead {
154− absPath := filePath
155− if !filepath.IsAbs(absPath) {
156− wd := config.WorkingDirectory()
157− absPath = filepath.Join(wd, absPath)
158− }
159−
160− content, err := os.ReadFile(absPath)
161− if err != nil {
162− return ToolResponse{}, fmt.Errorf("failed to read file %s: %w", absPath, err)
163− }
164− currentFiles[filePath] = string(content)
165− }
166−
167− // Process the patch
168− patch, fuzz, err := diff.TextToPatch(params.PatchText, currentFiles)
169− if err != nil {
170− return NewTextErrorResponse(fmt.Sprintf("failed to parse patch: %s", err)), nil
171− }
172−
173− if fuzz > 3 {
174− return NewTextErrorResponse(fmt.Sprintf("patch contains fuzzy matches (fuzz level: %d). Please make your context lines more precise", fuzz)), nil
175− }
176−
177− // Convert patch to commit
178− commit, err := diff.PatchToCommit(patch, currentFiles)
179− if err != nil {
180− return NewTextErrorResponse(fmt.Sprintf("failed to create commit from patch: %s", err)), nil
181− }
182−
183− // Get session ID and message ID
184− sessionID, messageID := GetContextValues(ctx)
185− if sessionID == "" || messageID == "" {
186− return ToolResponse{}, fmt.Errorf("session ID and message ID are required for creating a patch")
187− }
188−
189− // Request permission for all changes
190− for path, change := range commit.Changes {
191− switch change.Type {
192− case diff.ActionAdd:
193− dir := filepath.Dir(path)
194− patchDiff, _, _ := diff.GenerateDiff("", *change.NewContent, path)
195− p := p.permissions.Request(
196− permission.CreatePermissionRequest{
197− SessionID: sessionID,
198− Path: dir,
199− ToolName: PatchToolName,
200− Action: "create",
201− Description: fmt.Sprintf("Create file %s", path),
202− Params: EditPermissionsParams{
203− FilePath: path,
204− Diff: patchDiff,
205− },
206− },
207− )
208− if !p {
209− return ToolResponse{}, permission.ErrorPermissionDenied
210− }
211− case diff.ActionUpdate:
212− currentContent := ""
213− if change.OldContent != nil {
214− currentContent = *change.OldContent
215− }
216− newContent := ""
217− if change.NewContent != nil {
218− newContent = *change.NewContent
219− }
220− patchDiff, _, _ := diff.GenerateDiff(currentContent, newContent, path)
221− dir := filepath.Dir(path)
222− p := p.permissions.Request(
223− permission.CreatePermissionRequest{
224− SessionID: sessionID,
225− Path: dir,
226− ToolName: PatchToolName,
227− Action: "update",
228− Description: fmt.Sprintf("Update file %s", path),
229− Params: EditPermissionsParams{
230− FilePath: path,
231− Diff: patchDiff,
232− },
233− },
234− )
235− if !p {
236− return ToolResponse{}, permission.ErrorPermissionDenied
237− }
238− case diff.ActionDelete:
239− dir := filepath.Dir(path)
240− patchDiff, _, _ := diff.GenerateDiff(*change.OldContent, "", path)
241− p := p.permissions.Request(
242− permission.CreatePermissionRequest{
243− SessionID: sessionID,
244− Path: dir,
245− ToolName: PatchToolName,
246− Action: "delete",
247− Description: fmt.Sprintf("Delete file %s", path),
248− Params: EditPermissionsParams{
249− FilePath: path,
250− Diff: patchDiff,
251− },
252− },
253− )
254− if !p {
255− return ToolResponse{}, permission.ErrorPermissionDenied
256− }
257− }
258− }
259−
260− // Apply the changes to the filesystem
261− err = diff.ApplyCommit(commit, func(path string, content string) error {
262− absPath := path
263− if !filepath.IsAbs(absPath) {
264− wd := config.WorkingDirectory()
265− absPath = filepath.Join(wd, absPath)
266− }
267−
268− // Create parent directories if needed
269− dir := filepath.Dir(absPath)
270− if err := os.MkdirAll(dir, 0o755); err != nil {
271− return fmt.Errorf("failed to create parent directories for %s: %w", absPath, err)
272− }
273−
274− return os.WriteFile(absPath, []byte(content), 0o644)
275− }, func(path string) error {
276− absPath := path
277− if !filepath.IsAbs(absPath) {
278− wd := config.WorkingDirectory()
279− absPath = filepath.Join(wd, absPath)
280− }
281− return os.Remove(absPath)
282− })
283− if err != nil {
284− return NewTextErrorResponse(fmt.Sprintf("failed to apply patch: %s", err)), nil
285− }
286−
287− // Update file history for all modified files
288− changedFiles := []string{}
289− totalAdditions := 0
290− totalRemovals := 0
291−
292− for path, change := range commit.Changes {
293− absPath := path
294− if !filepath.IsAbs(absPath) {
295− wd := config.WorkingDirectory()
296− absPath = filepath.Join(wd, absPath)
297− }
298− changedFiles = append(changedFiles, absPath)
299−
300− oldContent := ""
301− if change.OldContent != nil {
302− oldContent = *change.OldContent
303− }
304−
305− newContent := ""
306− if change.NewContent != nil {
307− newContent = *change.NewContent
308− }
309−
310− // Calculate diff statistics
311− _, additions, removals := diff.GenerateDiff(oldContent, newContent, path)
312− totalAdditions += additions
313− totalRemovals += removals
314−
315− // Update history
316− file, err := p.files.GetByPathAndSession(ctx, absPath, sessionID)
317− if err != nil && change.Type != diff.ActionAdd {
318− // If not adding a file, create history entry for existing file
319− _, err = p.files.Create(ctx, sessionID, absPath, oldContent)
320− if err != nil {
321− logging.Debug("Error creating file history", "error", err)
322− }
323− }
324−
325− if err == nil && change.Type != diff.ActionAdd && file.Content != oldContent {
326− // User manually changed content, store intermediate version
327− _, err = p.files.CreateVersion(ctx, sessionID, absPath, oldContent)
328− if err != nil {
329− logging.Debug("Error creating file history version", "error", err)
330− }
331− }
332−
333− // Store new version
334− if change.Type == diff.ActionDelete {
335− _, err = p.files.CreateVersion(ctx, sessionID, absPath, "")
336− } else {
337− _, err = p.files.CreateVersion(ctx, sessionID, absPath, newContent)
338− }
339− if err != nil {
340− logging.Debug("Error creating file history version", "error", err)
341− }
342−
343− // Record file operations
344− recordFileWrite(absPath)
345− recordFileRead(absPath)
346− }
347−
348− // Run LSP diagnostics on all changed files
349− for _, filePath := range changedFiles {
350− waitForLspDiagnostics(ctx, filePath, p.lspClients)
351− }
352−
353− result := fmt.Sprintf("Patch applied successfully. %d files changed, %d additions, %d removals",
354− len(changedFiles), totalAdditions, totalRemovals)
355−
356− diagnosticsText := ""
357− for _, filePath := range changedFiles {
358− diagnosticsText += getDiagnostics(filePath, p.lspClients)
359− }
360−
361− if diagnosticsText != "" {
362− result += "\n\nDiagnostics:\n" + diagnosticsText
363− }
364−
365− return WithResponseMetadata(
366− NewTextResponse(result),
367− PatchResponseMetadata{
368− FilesChanged: changedFiles,
369− Additions: totalAdditions,
370− Removals: totalRemovals,
371− }), nil
372−}
internal/llm/tools/shell/comparison_test.go−29
@@ -3,7 +3,6 @@ package shell
33import (
44 "context"
55 "os"
6− "runtime"
76 "testing"
87 "time"
98
@@ -32,34 +31,6 @@ func TestShellPerformanceComparison(t *testing.T) {
3231 t.Logf("Quick command took: %v", duration)
3332}
3433
35−func TestShellCPUUsageComparison(t *testing.T) {
36− tmpDir, err := os.MkdirTemp("", "shell-test")
37− require.NoError(t, err)
38− defer os.RemoveAll(tmpDir)
39−
40− shell := GetPersistentShell(tmpDir)
41− defer shell.Close()
42−
43− // Measure CPU and memory usage during a longer command
44− var m1, m2 runtime.MemStats
45− runtime.GC()
46− runtime.ReadMemStats(&m1)
47−
48− start := time.Now()
49− _, stderr, exitCode, _, err := shell.Exec(context.Background(), "sleep 0.1", 1000)
50− duration := time.Since(start)
51−
52− runtime.ReadMemStats(&m2)
53−
54− require.NoError(t, err)
55− assert.Equal(t, 0, exitCode)
56− assert.Empty(t, stderr)
57−
58− memGrowth := m2.Alloc - m1.Alloc
59− t.Logf("Sleep 0.1s command took: %v", duration)
60− t.Logf("Memory growth during polling: %d bytes", memGrowth)
61− t.Logf("GC cycles during test: %d", m2.NumGC-m1.NumGC)
62−}
6334
6435// Benchmark CPU usage during polling
6536func BenchmarkShellPolling(b *testing.B) {
internal/llm/tools/shell/shell_test.go−25
@@ -4,35 +4,10 @@ import (
44 "context"
55 "os"
66 "testing"
7− "time"
87
9− "github.com/stretchr/testify/assert"
108 "github.com/stretchr/testify/require"
119)
1210
13−func TestShellPerformanceImprovement(t *testing.T) {
14− // Create a temporary directory for the shell
15− tmpDir, err := os.MkdirTemp("", "shell-test")
16− require.NoError(t, err)
17− defer os.RemoveAll(tmpDir)
18−
19− shell := GetPersistentShell(tmpDir)
20− defer shell.Close()
21−
22− // Test that quick commands complete fast
23− start := time.Now()
24− stdout, stderr, exitCode, _, err := shell.Exec(context.Background(), "echo 'hello world'", 0)
25− duration := time.Since(start)
26−
27− require.NoError(t, err)
28− assert.Equal(t, 0, exitCode)
29− assert.Contains(t, stdout, "hello world")
30− assert.Empty(t, stderr)
31−
32− // Quick commands should complete very fast with our exponential backoff
33− assert.Less(t, duration, 50*time.Millisecond, "Quick command should complete fast with exponential backoff")
34−}
35−
3611// Benchmark to measure CPU efficiency
3712func BenchmarkShellQuickCommands(b *testing.B) {
3813 tmpDir, err := os.MkdirTemp("", "shell-bench")
internal/llm/tools/sourcegraph.go+13−6
@@ -129,6 +129,11 @@ func NewSourcegraphTool() BaseTool {
129129 return &sourcegraphTool{
130130 client: &http.Client{
131131 Timeout: 30 * time.Second,
132+ Transport: &http.Transport{
133+ MaxIdleConns: 100,
134+ MaxIdleConnsPerHost: 10,
135+ IdleConnTimeout: 90 * time.Second,
136+ },
132137 },
133138 }
134139}
@@ -178,15 +183,17 @@ func (t *sourcegraphTool) Run(ctx context.Context, call ToolCall) (ToolResponse,
178183 if params.ContextWindow <= 0 {
179184 params.ContextWindow = 10 // Default context window
180185 }
181− client := t.client
186+
187+ // Handle timeout with context
188+ requestCtx := ctx
182189 if params.Timeout > 0 {
183190 maxTimeout := 120 // 2 minutes
184191 if params.Timeout > maxTimeout {
185192 params.Timeout = maxTimeout
186193 }
187− client = &http.Client{
188− Timeout: time.Duration(params.Timeout) * time.Second,
189− }
194+ var cancel context.CancelFunc
195+ requestCtx, cancel = context.WithTimeout(ctx, time.Duration(params.Timeout)*time.Second)
196+ defer cancel()
190197 }
191198
192199 type graphqlRequest struct {
@@ -208,7 +215,7 @@ func (t *sourcegraphTool) Run(ctx context.Context, call ToolCall) (ToolResponse,
208215 graphqlQuery := string(graphqlQueryBytes)
209216
210217 req, err := http.NewRequestWithContext(
211− ctx,
218+ requestCtx,
212219 "POST",
213220 "https://sourcegraph.com/.api/graphql",
214221 bytes.NewBuffer([]byte(graphqlQuery)),
@@ -220,7 +227,7 @@ func (t *sourcegraphTool) Run(ctx context.Context, call ToolCall) (ToolResponse,
220227 req.Header.Set("Content-Type", "application/json")
221228 req.Header.Set("User-Agent", "crush/1.0")
222229
223− resp, err := client.Do(req)
230+ resp, err := t.client.Do(req)
224231 if err != nil {
225232 return ToolResponse{}, fmt.Errorf("failed to fetch URL: %w", err)
226233 }
internal/lsp/watcher/watcher.go+25−9
@@ -257,7 +257,10 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
257257 }
258258 }
259259
260− // For each pattern, find and open matching files
260+ // Collect all files to open first
261+ var filesToOpen []string
262+
263+ // For each pattern, find matching files
261264 for _, pattern := range patterns {
262265 // Use doublestar.Glob to find files matching the pattern (supports ** patterns)
263266 matches, err := doublestar.Glob(os.DirFS(w.workspacePath), pattern)
@@ -278,7 +281,23 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
278281 continue
279282 }
280283
281− // Open the file
284+ filesToOpen = append(filesToOpen, fullPath)
285+
286+ // Limit the number of files per pattern
287+ if len(filesToOpen) >= 5 && (serverName != "java" && serverName != "jdtls") {
288+ break
289+ }
290+ }
291+ }
292+
293+ // Open files in batches to reduce overhead
294+ batchSize := 3
295+ for i := 0; i < len(filesToOpen); i += batchSize {
296+ end := min(i+batchSize, len(filesToOpen))
297+
298+ // Open batch of files
299+ for j := i; j < end; j++ {
300+ fullPath := filesToOpen[j]
282301 if err := w.client.OpenFile(ctx, fullPath); err != nil {
283302 if cnf.DebugLSP {
284303 logging.Debug("Error opening high-priority file", "path", fullPath, "error", err)
@@ -289,14 +308,11 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
289308 logging.Debug("Opened high-priority file", "path", fullPath)
290309 }
291310 }
311+ }
292312
293− // Add a small delay to prevent overwhelming the server
294− time.Sleep(20 * time.Millisecond)
295−
296− // Limit the number of files opened per pattern
297− if filesOpened >= 5 && (serverName != "java" && serverName != "jdtls") {
298− break
299− }
313+ // Only add delay between batches, not individual files
314+ if end < len(filesToOpen) {
315+ time.Sleep(50 * time.Millisecond)
300316 }
301317 }
302318
internal/tui/components/chat/messages/renderer.go+7−39
@@ -6,11 +6,11 @@ import (
66 "strings"
77 "time"
88
9− "github.com/charmbracelet/crush/internal/diff"
109 "github.com/charmbracelet/crush/internal/fileutil"
1110 "github.com/charmbracelet/crush/internal/highlight"
1211 "github.com/charmbracelet/crush/internal/llm/agent"
1312 "github.com/charmbracelet/crush/internal/llm/tools"
13+ "github.com/charmbracelet/crush/internal/tui/components/core"
1414 "github.com/charmbracelet/crush/internal/tui/styles"
1515 "github.com/charmbracelet/lipgloss/v2"
1616 "github.com/charmbracelet/lipgloss/v2/tree"
@@ -148,7 +148,6 @@ func init() {
148148 registry.register(tools.GrepToolName, func() renderer { return grepRenderer{} })
149149 registry.register(tools.LSToolName, func() renderer { return lsRenderer{} })
150150 registry.register(tools.SourcegraphToolName, func() renderer { return sourcegraphRenderer{} })
151− registry.register(tools.PatchToolName, func() renderer { return patchRenderer{} })
152151 registry.register(tools.DiagnosticsToolName, func() renderer { return diagnosticsRenderer{} })
153152 registry.register(agent.AgentToolName, func() renderer { return agentRenderer{} })
154153}
@@ -258,9 +257,12 @@ func (er editRenderer) Render(v *toolCallCmp) string {
258257 return renderPlainContent(v, v.result.Content)
259258 }
260259
261− trunc := truncateHeight(meta.Diff, responseContextHeight)
262− diffView, _ := diff.FormatDiff(trunc, diff.WithTotalWidth(v.textWidth()-2))
263− return diffView
260+ formatter := core.DiffFormatter().
261+ Before(fileutil.PrettyPath(params.FilePath), meta.OldContent).
262+ After(fileutil.PrettyPath(params.FilePath), meta.NewContent).
263+ Split().
264+ Width(v.textWidth() - 2) // -2 for padding
265+ return formatter.String()
264266 })
265267}
266268
@@ -446,38 +448,6 @@ func (sr sourcegraphRenderer) Render(v *toolCallCmp) string {
446448 })
447449}
448450
449−// -----------------------------------------------------------------------------
450−// Patch renderer
451−// -----------------------------------------------------------------------------
452−
453−// patchRenderer handles multi-file patches with change summaries
454−type patchRenderer struct {
455− baseRenderer
456−}
457−
458−// Render displays patch summary with file count and change statistics
459−func (pr patchRenderer) Render(v *toolCallCmp) string {
460− var params tools.PatchParams
461− if err := pr.unmarshalParams(v.call.Input, &params); err != nil {
462− return pr.renderError(v, "Invalid patch parameters")
463− }
464−
465− args := newParamBuilder().addMain("multiple files").build()
466−
467− return pr.renderWithParams(v, "Patch", args, func() string {
468− var meta tools.PatchResponseMetadata
469− if err := pr.unmarshalParams(v.result.Metadata, &meta); err != nil {
470− return renderPlainContent(v, v.result.Content)
471− }
472−
473− summary := fmt.Sprintf("Changed %d files (%d+ %d-)",
474− len(meta.FilesChanged), meta.Additions, meta.Removals)
475− filesList := strings.Join(meta.FilesChanged, "\n")
476−
477− return renderPlainContent(v, summary+"\n\n"+filesList)
478− })
479−}
480−
481451// -----------------------------------------------------------------------------
482452// Diagnostics renderer
483453// -----------------------------------------------------------------------------
@@ -711,8 +681,6 @@ func prettifyToolName(name string) string {
711681 return "View"
712682 case tools.WriteToolName:
713683 return "Write"
714− case tools.PatchToolName:
715− return "Patch"
716684 default:
717685 return name
718686 }
internal/tui/components/chat/sidebar/sidebar.go+135−8
@@ -1,12 +1,16 @@
11package sidebar
22
33import (
4+ "context"
45 "fmt"
56 "os"
67 "strings"
78
89 tea "github.com/charmbracelet/bubbletea/v2"
910 "github.com/charmbracelet/crush/internal/config"
11+ "github.com/charmbracelet/crush/internal/diff"
12+ "github.com/charmbracelet/crush/internal/fileutil"
13+ "github.com/charmbracelet/crush/internal/history"
1014 "github.com/charmbracelet/crush/internal/llm/models"
1115 "github.com/charmbracelet/crush/internal/logging"
1216 "github.com/charmbracelet/crush/internal/lsp"
@@ -21,12 +25,22 @@ import (
2125 "github.com/charmbracelet/crush/internal/tui/util"
2226 "github.com/charmbracelet/crush/internal/version"
2327 "github.com/charmbracelet/lipgloss/v2"
28+ "github.com/charmbracelet/x/ansi"
2429)
2530
2631const (
2732 logoBreakpoint = 65
2833)
2934
35+type SessionFile struct {
36+ FilePath string
37+ Additions int
38+ Deletions int
39+}
40+type SessionFilesMsg struct {
41+ Files []SessionFile
42+}
43+
3044type Sidebar interface {
3145 util.Model
3246 layout.Sizeable
@@ -38,11 +52,14 @@ type sidebarCmp struct {
3852 logo string
3953 cwd string
4054 lspClients map[string]*lsp.Client
55+ history history.Service
56+ files []SessionFile
4157}
4258
43−func NewSidebarCmp(lspClients map[string]*lsp.Client) Sidebar {
59+func NewSidebarCmp(history history.Service, lspClients map[string]*lsp.Client) Sidebar {
4460 return &sidebarCmp{
4561 lspClients: lspClients,
62+ history: history,
4663 }
4764}
4865
@@ -58,6 +75,12 @@ func (m *sidebarCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
5875 if msg.ID != m.session.ID {
5976 m.session = msg
6077 }
78+ return m, m.loadSessionFiles
79+ case SessionFilesMsg:
80+ m.files = msg.Files
81+ logging.Info("Loaded session files", "count", len(m.files))
82+ return m, nil
83+
6184 case chat.SessionClearedMsg:
6285 m.session = session.Session{}
6386 case pubsub.Event[session.Session]:
@@ -85,6 +108,8 @@ func (m *sidebarCmp) View() tea.View {
85108 "",
86109 m.currentModelBlock(),
87110 "",
111+ m.filesBlock(),
112+ "",
88113 m.lspBlock(),
89114 "",
90115 m.mcpBlock(),
@@ -95,6 +120,58 @@ func (m *sidebarCmp) View() tea.View {
95120 )
96121}
97122
123+func (m *sidebarCmp) loadSessionFiles() tea.Msg {
124+ files, err := m.history.ListBySession(context.Background(), m.session.ID)
125+ if err != nil {
126+ return util.InfoMsg{
127+ Type: util.InfoTypeError,
128+ Msg: err.Error(),
129+ }
130+ }
131+
132+ type fileHistory struct {
133+ initialVersion history.File
134+ latestVersion history.File
135+ }
136+
137+ fileMap := make(map[string]fileHistory)
138+
139+ for _, file := range files {
140+ if existing, ok := fileMap[file.Path]; ok {
141+ // Update the latest version
142+ if existing.latestVersion.CreatedAt < file.CreatedAt {
143+ existing.latestVersion = file
144+ }
145+ if file.Version == history.InitialVersion {
146+ existing.initialVersion = file
147+ }
148+ fileMap[file.Path] = existing
149+ } else {
150+ // Add the initial version
151+ fileMap[file.Path] = fileHistory{
152+ initialVersion: file,
153+ latestVersion: file,
154+ }
155+ }
156+ }
157+
158+ sessionFiles := make([]SessionFile, 0, len(fileMap))
159+ for path, fh := range fileMap {
160+ if fh.initialVersion.Version == history.InitialVersion {
161+ _, additions, deletions := diff.GenerateDiff(fh.initialVersion.Content, fh.latestVersion.Content, fh.initialVersion.Path)
162+ sessionFiles = append(sessionFiles, SessionFile{
163+ FilePath: path,
164+ Additions: additions,
165+ Deletions: deletions,
166+ })
167+ }
168+ }
169+
170+ return SessionFilesMsg{
171+ Files: sessionFiles,
172+ }
173+}
174+
98175func (m *sidebarCmp) SetSize(width, height int) tea.Cmd {
99176 if width < logoBreakpoint && m.width >= logoBreakpoint {
100177 m.logo = m.logoBlock(true)
@@ -122,11 +199,64 @@ func (m *sidebarCmp) logoBlock(compact bool) string {
122199 })
123200}
124201
202+func (m *sidebarCmp) filesBlock() string {
203+ maxWidth := min(m.width, 58)
204+ t := styles.CurrentTheme()
205+
206+ section := t.S().Subtle.Render(
207+ core.Section("Modified Files", maxWidth),
208+ )
209+
210+ if len(m.files) == 0 {
211+ return lipgloss.JoinVertical(
212+ lipgloss.Left,
213+ section,
214+ "",
215+ t.S().Base.Foreground(t.Border).Render("None"),
216+ )
217+ }
218+
219+ fileList := []string{section, ""}
220+
221+ for _, file := range m.files {
222+ // Extract just the filename from the path
223+
224+ // Create status indicators for additions/deletions
225+ var statusParts []string
226+ if file.Additions > 0 {
227+ statusParts = append(statusParts, t.S().Base.Foreground(t.Success).Render(fmt.Sprintf("+%d", file.Additions)))
228+ }
229+ if file.Deletions > 0 {
230+ statusParts = append(statusParts, t.S().Base.Foreground(t.Error).Render(fmt.Sprintf("-%d", file.Deletions)))
231+ }
232+
233+ extraContent := strings.Join(statusParts, " ")
234+ filePath := fileutil.DirTrim(fileutil.PrettyPath(file.FilePath), 2)
235+ filePath = ansi.Truncate(filePath, maxWidth-lipgloss.Width(extraContent)-2, "…")
236+ fileList = append(fileList,
237+ core.Status(
238+ core.StatusOpts{
239+ IconColor: t.FgMuted,
240+ NoIcon: true,
241+ Title: filePath,
242+ ExtraContent: extraContent,
243+ },
244+ m.width,
245+ ),
246+ )
247+ }
248+
249+ return lipgloss.JoinVertical(
250+ lipgloss.Left,
251+ fileList...,
252+ )
253+}
254+
125255func (m *sidebarCmp) lspBlock() string {
126256 maxWidth := min(m.width, 58)
127257 t := styles.CurrentTheme()
128258
129− section := t.S().Muted.Render(
259+ section := t.S().Subtle.Render(
130260 core.Section("LSPs", maxWidth),
131261 )
132262
@@ -177,7 +307,6 @@ func (m *sidebarCmp) lspBlock() string {
177307 errs = append(errs, t.S().Base.Foreground(t.FgHalfMuted).Render(fmt.Sprintf("%s%d", styles.InfoIcon, lspErrs[protocol.SeverityInformation])))
178308 }
179309
180− logging.Info("LSP Errors", "errors", errs)
181310 lspList = append(lspList,
182311 core.Status(
183312 core.StatusOpts{
@@ -201,7 +330,7 @@ func (m *sidebarCmp) mcpBlock() string {
201330 maxWidth := min(m.width, 58)
202331 t := styles.CurrentTheme()
203332
204− section := t.S().Muted.Render(
333+ section := t.S().Subtle.Render(
205334 core.Section("MCPs", maxWidth),
206335 )
207336
@@ -264,8 +393,8 @@ func formatTokensAndCost(tokens, contextWindow int64, cost float64) string {
264393
265394 formattedCost := baseStyle.Foreground(t.FgMuted).Render(fmt.Sprintf("$%.2f", cost))
266395
267− formattedTokens = baseStyle.Foreground(t.FgMuted).Render(fmt.Sprintf("(%s)", formattedTokens))
268− formattedPercentage := baseStyle.Foreground(t.FgSubtle).Render(fmt.Sprintf("%d%%", int(percentage)))
396+ formattedTokens = baseStyle.Foreground(t.FgSubtle).Render(fmt.Sprintf("(%s)", formattedTokens))
397+ formattedPercentage := baseStyle.Foreground(t.FgMuted).Render(fmt.Sprintf("%d%%", int(percentage)))
269398 formattedTokens = fmt.Sprintf("%s %s", formattedPercentage, formattedTokens)
270399 if percentage > 80 {
271400 // add the warning icon
@@ -287,8 +416,6 @@ func (s *sidebarCmp) currentModelBlock() string {
287416 modelName := t.S().Text.Render(model.Name)
288417 modelInfo := fmt.Sprintf("%s %s", modelIcon, modelName)
289418 parts := []string{
290− // section,
291− // "",
292419 modelInfo,
293420 }
294421 if s.session.ID != "" {
internal/tui/components/core/helpers.go+19−5
@@ -4,6 +4,8 @@ import (
44 "image/color"
55 "strings"
66
7+ "github.com/alecthomas/chroma/v2"
8+ "github.com/charmbracelet/crush/internal/exp/diffview"
79 "github.com/charmbracelet/crush/internal/tui/styles"
810 "github.com/charmbracelet/lipgloss/v2"
911 "github.com/charmbracelet/x/ansi"
@@ -38,6 +40,7 @@ func Title(title string, width int) string {
3840type StatusOpts struct {
3941 Icon string
4042 IconColor color.Color
43+ NoIcon bool // If true, no icon will be displayed
4144 Title string
4245 TitleColor color.Color
4346 Description string
@@ -51,6 +54,8 @@ func Status(ops StatusOpts, width int) string {
5154 iconColor := t.Success
5255 if ops.Icon != "" {
5356 icon = ops.Icon
57+ } else if ops.NoIcon {
58+ icon = ""
5459 }
5560 if ops.IconColor != nil {
5661 iconColor = ops.IconColor
@@ -65,7 +70,6 @@ func Status(ops StatusOpts, width int) string {
6570 if ops.DescriptionColor != nil {
6671 descriptionColor = ops.DescriptionColor
6772 }
68− icon = t.S().Base.Foreground(iconColor).Render(icon)
6973 title = t.S().Base.Foreground(titleColor).Render(title)
7074 if description != "" {
7175 extraContent := len(ops.ExtraContent)
@@ -75,11 +79,12 @@ func Status(ops StatusOpts, width int) string {
7579 description = ansi.Truncate(description, width-lipgloss.Width(icon)-lipgloss.Width(title)-2-extraContent, "…")
7680 }
7781 description = t.S().Base.Foreground(descriptionColor).Render(description)
78− content := []string{
79− icon,
80− title,
81− description,
82+
83+ content := []string{}
84+ if icon != "" {
85+ content = append(content, t.S().Base.Foreground(iconColor).Render(icon))
8286 }
87+ content = append(content, title, description)
8388 if ops.ExtraContent != "" {
8489 content = append(content, ops.ExtraContent)
8590 }
@@ -141,3 +146,12 @@ func SelectableButtons(buttons []ButtonOpts, spacing string) string {
141146
142147 return lipgloss.JoinHorizontal(lipgloss.Left, parts...)
143148}
149+
150+func DiffFormatter() *diffview.DiffView {
151+ formatDiff := diffview.New()
152+ style := chroma.MustNewStyle("crush", styles.GetChromaTheme())
153+ diff := formatDiff.
154+ SyntaxHightlight(true).
155+ ChromaStyle(style)
156+ return diff
157+}
internal/tui/components/dialogs/commands/commands.go+2−1
@@ -239,7 +239,8 @@ func (c *commandDialogCmp) defaultCommands() []Command {
239239
240240 The file you create will be given to agentic coding agents (such as yourself) that operate in this repository. Make it about 20 lines long.
241241 If there's already a CRUSH.md, improve it.
242− If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include them.`
242+ If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include them.
243+ Add the .crush directory to the .gitignore file if it's not already there.`
243244 return util.CmdHandler(chat.SendMsg{
244245 Text: prompt,
245246 })
internal/tui/components/dialogs/init/init.go+2−1
@@ -180,7 +180,8 @@ func (m *initDialogCmp) handleInitialization(initialize bool) tea.Cmd {
180180
181181The file you create will be given to agentic coding agents (such as yourself) that operate in this repository. Make it about 20 lines long.
182182If there's already a CRUSH.md, improve it.
183−If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include them.`
183+If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include them.
184+Add the .crush directory to the .gitignore file if it's not already there.`
184185
185186 // Mark the project as initialized
186187 if err := config.MarkProjectInitialized(); err != nil {
internal/tui/components/dialogs/permissions/permissions.go+6−19
@@ -267,24 +267,13 @@ func (p *permissionDialogCmp) renderBashContent() string {
267267
268268func (p *permissionDialogCmp) renderEditContent() string {
269269 if pr, ok := p.permission.Params.(tools.EditPermissionsParams); ok {
270− diff := p.GetOrSetDiff(p.permission.ID, func() (string, error) {
271− return diff.FormatDiff(pr.Diff, diff.WithTotalWidth(p.contentViewPort.Width()))
272− })
273−
274− contentHeight := min(p.height-9, lipgloss.Height(diff))
275− p.contentViewPort.SetHeight(contentHeight)
276− p.contentViewPort.SetContent(diff)
277− return p.styleViewport()
278− }
279− return ""
280−}
281−
282−func (p *permissionDialogCmp) renderPatchContent() string {
283− if pr, ok := p.permission.Params.(tools.EditPermissionsParams); ok {
284− diff := p.GetOrSetDiff(p.permission.ID, func() (string, error) {
285− return diff.FormatDiff(pr.Diff, diff.WithTotalWidth(p.contentViewPort.Width()))
286− })
270+ formatter := core.DiffFormatter().
271+ Before(fileutil.PrettyPath(pr.FilePath), pr.OldContent).
272+ After(fileutil.PrettyPath(pr.FilePath), pr.NewContent).
273+ Width(p.contentViewPort.Width()).
274+ Split()
287275
276+ diff := formatter.String()
288277 contentHeight := min(p.height-9, lipgloss.Height(diff))
289278 p.contentViewPort.SetHeight(contentHeight)
290279 p.contentViewPort.SetContent(diff)
@@ -381,8 +370,6 @@ func (p *permissionDialogCmp) render() string {
381370 contentFinal = p.renderBashContent()
382371 case tools.EditToolName:
383372 contentFinal = p.renderEditContent()
384− case tools.PatchToolName:
385− contentFinal = p.renderPatchContent()
386373 case tools.WriteToolName:
387374 contentFinal = p.renderWriteContent()
388375 case tools.FetchToolName:
internal/tui/page/chat/chat.go+1−1
@@ -209,7 +209,7 @@ func (p *chatPage) Bindings() []key.Binding {
209209
210210func NewChatPage(app *app.App) ChatPage {
211211 sidebarContainer := layout.NewContainer(
212− sidebar.NewSidebarCmp(app.LSPClients),
212+ sidebar.NewSidebarCmp(app.History, app.LSPClients),
213213 layout.WithPadding(1, 1, 1, 1),
214214 )
215215 editorContainer := layout.NewContainer(
todos.md+1
@@ -27,6 +27,7 @@
2727- [ ] Update interactive mode to use the spinner
2828- [ ] Revisit the core list component
2929 - [ ] This component has become super complex we might need to fix this.
30+- [ ] Handle correct LSP and MCP status icon
3031- [ ] Investigate ways to make the spinner less CPU intensive
3132- [ ] General cleanup and documentation
3233- [ ] Update the readme