@@ -1728,11 +1728,12 @@ func TestModel_PgDownMovesCursorByPageHeight(t *testing.T) {
17281728 model = result .(Model )
17291729 assert .Equal (t , pageHeight , model .diffCursor , "PgDown should move cursor by viewport height" )
17301730
1731- // ctrl+d should also move by page height from current position
1731+ // ctrl+d should move by half page height from current position
17321732 prevCursor := model .diffCursor
17331733 result , _ = model .Update (tea.KeyMsg {Type : tea .KeyCtrlD })
17341734 model = result .(Model )
1735- assert .Equal (t , prevCursor + pageHeight , model .diffCursor , "ctrl+d should move cursor by viewport height" )
1735+ halfPage := pageHeight / 2
1736+ assert .Equal (t , prevCursor + halfPage , model .diffCursor , "ctrl+d should move cursor by half viewport height" )
17361737}
17371738
17381739func TestModel_PgUpMovesCursorByPageHeight (t * testing.T ) {
@@ -1763,11 +1764,135 @@ func TestModel_PgUpMovesCursorByPageHeight(t *testing.T) {
17631764 model = result .(Model )
17641765 assert .Equal (t , 80 - pageHeight , model .diffCursor , "PgUp should move cursor up by viewport height" )
17651766
1766- // ctrl+u should also move up by page height
1767+ // ctrl+u should move up by half page height
17671768 model .diffCursor = 80
17681769 result , _ = model .Update (tea.KeyMsg {Type : tea .KeyCtrlU })
17691770 model = result .(Model )
1770- assert .Equal (t , 80 - pageHeight , model .diffCursor , "ctrl+u should move cursor up by viewport height" )
1771+ halfPage := pageHeight / 2
1772+ assert .Equal (t , 80 - halfPage , model .diffCursor , "ctrl+u should move cursor up by half viewport height" )
1773+ }
1774+
1775+ func TestModel_CtrlDMovesHalfPageDown (t * testing.T ) {
1776+ lines := make ([]diff.DiffLine , 100 )
1777+ for i := range lines {
1778+ lines [i ] = diff.DiffLine {NewNum : i + 1 , Content : "line" , ChangeType : diff .ChangeContext }
1779+ }
1780+
1781+ m := testModel ([]string {"a.go" }, map [string ][]diff.DiffLine {"a.go" : lines })
1782+
1783+ result , _ := m .Update (tea.WindowSizeMsg {Width : 120 , Height : 40 })
1784+ model := result .(Model )
1785+
1786+ result , _ = model .Update (fileLoadedMsg {file : "a.go" , lines : lines })
1787+ model = result .(Model )
1788+ model .focus = paneDiff
1789+ assert .Equal (t , 0 , model .diffCursor )
1790+
1791+ pageHeight := model .viewport .Height
1792+ halfPage := pageHeight / 2
1793+ require .Positive (t , halfPage , "half page must be positive" )
1794+
1795+ // ctrl+d moves cursor and viewport by half page
1796+ result , _ = model .Update (tea.KeyMsg {Type : tea .KeyCtrlD })
1797+ model = result .(Model )
1798+ assert .Equal (t , halfPage , model .diffCursor , "ctrl+d should move cursor by half viewport height" )
1799+ assert .Equal (t , halfPage , model .viewport .YOffset , "ctrl+d should scroll viewport by half page" )
1800+
1801+ // PgDn moves full page from start for comparison
1802+ model .diffCursor = 0
1803+ model .viewport .SetYOffset (0 )
1804+ model .viewport .SetContent (model .renderDiff ())
1805+ result , _ = model .Update (tea.KeyMsg {Type : tea .KeyPgDown })
1806+ model = result .(Model )
1807+ assert .Equal (t , pageHeight , model .diffCursor , "PgDown should move cursor by full viewport height" )
1808+ }
1809+
1810+ func TestModel_CtrlUMovesHalfPageUp (t * testing.T ) {
1811+ lines := make ([]diff.DiffLine , 100 )
1812+ for i := range lines {
1813+ lines [i ] = diff.DiffLine {NewNum : i + 1 , Content : "line" , ChangeType : diff .ChangeContext }
1814+ }
1815+
1816+ m := testModel ([]string {"a.go" }, map [string ][]diff.DiffLine {"a.go" : lines })
1817+
1818+ result , _ := m .Update (tea.WindowSizeMsg {Width : 120 , Height : 40 })
1819+ model := result .(Model )
1820+
1821+ result , _ = model .Update (fileLoadedMsg {file : "a.go" , lines : lines })
1822+ model = result .(Model )
1823+ model .focus = paneDiff
1824+
1825+ pageHeight := model .viewport .Height
1826+ halfPage := pageHeight / 2
1827+ require .Positive (t , halfPage , "half page must be positive" )
1828+
1829+ // start at line 80 with viewport scrolled to match
1830+ model .diffCursor = 80
1831+ model .viewport .SetYOffset (80 )
1832+ model .viewport .SetContent (model .renderDiff ())
1833+ prevOffset := model .viewport .YOffset
1834+
1835+ // ctrl+u moves cursor and viewport by half page up
1836+ result , _ = model .Update (tea.KeyMsg {Type : tea .KeyCtrlU })
1837+ model = result .(Model )
1838+ assert .Equal (t , 80 - halfPage , model .diffCursor , "ctrl+u should move cursor up by half viewport height" )
1839+ assert .Equal (t , prevOffset - halfPage , model .viewport .YOffset , "ctrl+u should scroll viewport up by half page" )
1840+
1841+ // PgUp moves full page up from 80 for comparison
1842+ model .diffCursor = 80
1843+ model .viewport .SetYOffset (80 )
1844+ model .viewport .SetContent (model .renderDiff ())
1845+ result , _ = model .Update (tea.KeyMsg {Type : tea .KeyPgUp })
1846+ model = result .(Model )
1847+ assert .Equal (t , 80 - pageHeight , model .diffCursor , "PgUp should move cursor up by full viewport height" )
1848+ }
1849+
1850+ func TestModel_TreeCtrlDUMovesHalfPage (t * testing.T ) {
1851+ files := make ([]string , 50 )
1852+ for i := range files {
1853+ files [i ] = fmt .Sprintf ("pkg/file%02d.go" , i )
1854+ }
1855+ m := testModel (files , nil )
1856+ m .tree = newFileTree (files )
1857+ m .focus = paneTree
1858+ m .height = 20
1859+
1860+ pageSize := m .treePageSize ()
1861+ halfPage := max (1 , pageSize / 2 )
1862+
1863+ // ctrl+d from start
1864+ result , _ := m .Update (tea.KeyMsg {Type : tea .KeyCtrlD })
1865+ model := result .(Model )
1866+ assert .Equal (t , fmt .Sprintf ("pkg/file%02d.go" , halfPage ), model .tree .selectedFile (),
1867+ "ctrl+d should move by half page" )
1868+
1869+ // ctrl+u from end area
1870+ m3 := testModel (files , nil )
1871+ m3 .tree = newFileTree (files )
1872+ m3 .focus = paneTree
1873+ m3 .height = 20
1874+ // move to file 39
1875+ m3 .tree .moveToLast ()
1876+ for range 10 {
1877+ m3 .tree .moveUp ()
1878+ }
1879+ assert .Equal (t , "pkg/file39.go" , m3 .tree .selectedFile ())
1880+
1881+ result , _ = m3 .Update (tea.KeyMsg {Type : tea .KeyCtrlU })
1882+ model3 := result .(Model )
1883+ assert .Equal (t , fmt .Sprintf ("pkg/file%02d.go" , 39 - halfPage ), model3 .tree .selectedFile (),
1884+ "ctrl+u should move by half page" )
1885+
1886+ // PgDn from start should move full page
1887+ m2 := testModel (files , nil )
1888+ m2 .tree = newFileTree (files )
1889+ m2 .focus = paneTree
1890+ m2 .height = 20
1891+
1892+ result , _ = m2 .Update (tea.KeyMsg {Type : tea .KeyPgDown })
1893+ model2 := result .(Model )
1894+ assert .Equal (t , fmt .Sprintf ("pkg/file%02d.go" , pageSize ), model2 .tree .selectedFile (),
1895+ "PgDn should move by full page" )
17711896}
17721897
17731898func TestModel_HomeEndMoveCursorToBoundaries (t * testing.T ) {
@@ -2058,7 +2183,7 @@ func TestModel_TreePgUpMovesCursorByPage(t *testing.T) {
20582183 assert .Equal (t , expected , model .tree .selectedFile (), "PgUp in tree should move cursor by page size" )
20592184}
20602185
2061- func TestModel_TreeCtrlDMovesCursorByPage (t * testing.T ) {
2186+ func TestModel_TreeCtrlDMovesCursorByHalfPage (t * testing.T ) {
20622187 files := make ([]string , 50 )
20632188 for i := range files {
20642189 files [i ] = fmt .Sprintf ("pkg/file%02d.go" , i )
@@ -2072,14 +2197,15 @@ func TestModel_TreeCtrlDMovesCursorByPage(t *testing.T) {
20722197
20732198 pageSize := m .treePageSize ()
20742199 require .Positive (t , pageSize )
2200+ halfPage := max (1 , pageSize / 2 )
20752201
20762202 result , _ := m .Update (tea.KeyMsg {Type : tea .KeyCtrlD })
20772203 model := result .(Model )
2078- assert .Equal (t , fmt .Sprintf ("pkg/file%02d.go" , pageSize ), model .tree .selectedFile (),
2079- "ctrl+d in tree should move cursor by page size" )
2204+ assert .Equal (t , fmt .Sprintf ("pkg/file%02d.go" , halfPage ), model .tree .selectedFile (),
2205+ "ctrl+d in tree should move cursor by half page size" )
20802206}
20812207
2082- func TestModel_TreeCtrlUMovesCursorByPage (t * testing.T ) {
2208+ func TestModel_TreeCtrlUMovesCursorByHalfPage (t * testing.T ) {
20832209 files := make ([]string , 50 )
20842210 for i := range files {
20852211 files [i ] = fmt .Sprintf ("pkg/file%02d.go" , i )
@@ -2091,6 +2217,7 @@ func TestModel_TreeCtrlUMovesCursorByPage(t *testing.T) {
20912217
20922218 pageSize := m .treePageSize ()
20932219 require .Positive (t , pageSize )
2220+ halfPage := max (1 , pageSize / 2 )
20942221
20952222 m .tree .moveToLast ()
20962223 for range 10 {
@@ -2100,8 +2227,8 @@ func TestModel_TreeCtrlUMovesCursorByPage(t *testing.T) {
21002227
21012228 result , _ := m .Update (tea.KeyMsg {Type : tea .KeyCtrlU })
21022229 model := result .(Model )
2103- expected := fmt .Sprintf ("pkg/file%02d.go" , 39 - pageSize )
2104- assert .Equal (t , expected , model .tree .selectedFile (), "ctrl+u in tree should move cursor by page size" )
2230+ expected := fmt .Sprintf ("pkg/file%02d.go" , 39 - halfPage )
2231+ assert .Equal (t , expected , model .tree .selectedFile (), "ctrl+u in tree should move cursor by half page size" )
21052232}
21062233
21072234func TestModel_TreeHomeEndMoveToBoundaries (t * testing.T ) {
0 commit comments