@@ -160,6 +160,52 @@ func (h *BufPane) Center() bool {
160160 return true
161161}
162162
163+ // CursorToViewTop moves the cursor to the top of the view,
164+ // offset by scrollmargin unless at the beginning or end of the file
165+ func (h * BufPane ) CursorToViewTop () bool {
166+ v := h .GetView ()
167+ h .Buf .ClearCursors ()
168+ scrollmargin := int (h .Buf .Settings ["scrollmargin" ].(float64 ))
169+ bStart := display.SLoc {0 , 0 }
170+ if v .StartLine == bStart {
171+ scrollmargin = 0
172+ }
173+ h .Cursor .GotoLoc (h .LocFromVLoc (display.VLoc {
174+ SLoc : h .Scroll (v .StartLine , scrollmargin ),
175+ VisualX : 0 ,
176+ }))
177+ return true
178+ }
179+
180+ // CursorToViewCenter moves the cursor to the center of the view
181+ func (h * BufPane ) CursorToViewCenter () bool {
182+ v := h .GetView ()
183+ h .Buf .ClearCursors ()
184+ h .Cursor .GotoLoc (h .LocFromVLoc (display.VLoc {
185+ SLoc : h .Scroll (v .StartLine , h .BufView ().Height / 2 ),
186+ VisualX : 0 ,
187+ }))
188+ return true
189+ }
190+
191+ // CursorToViewBottom moves the cursor to the bottom of the view,
192+ // offset by scrollmargin unless at the beginning or end of the file
193+ func (h * BufPane ) CursorToViewBottom () bool {
194+ v := h .GetView ()
195+ h .Buf .ClearCursors ()
196+ scrollmargin := int (h .Buf .Settings ["scrollmargin" ].(float64 ))
197+ bEnd := h .SLocFromLoc (h .Buf .End ())
198+ lastLine := h .Scroll (v .StartLine , h .BufView ().Height - 1 )
199+ if lastLine == bEnd {
200+ scrollmargin = 0
201+ }
202+ h .Cursor .GotoLoc (h .LocFromVLoc (display.VLoc {
203+ SLoc : h .Scroll (lastLine , - scrollmargin ),
204+ VisualX : 0 ,
205+ }))
206+ return true
207+ }
208+
163209// MoveCursorUp is not an action
164210func (h * BufPane ) MoveCursorUp (n int ) {
165211 if ! h .Buf .Settings ["softwrap" ].(bool ) {
@@ -170,10 +216,10 @@ func (h *BufPane) MoveCursorUp(n int) {
170216 if sloc == vloc .SLoc {
171217 // we are at the beginning of buffer
172218 h .Cursor .Loc = h .Buf .Start ()
173- h .Cursor .LastVisualX = 0
219+ h .Cursor .StoreVisualX ()
174220 } else {
175221 vloc .SLoc = sloc
176- vloc .VisualX = h .Cursor .LastVisualX
222+ vloc .VisualX = h .Cursor .LastWrappedVisualX
177223 h .Cursor .Loc = h .LocFromVLoc (vloc )
178224 }
179225 }
@@ -189,11 +235,10 @@ func (h *BufPane) MoveCursorDown(n int) {
189235 if sloc == vloc .SLoc {
190236 // we are at the end of buffer
191237 h .Cursor .Loc = h .Buf .End ()
192- vloc = h .VLocFromLoc (h .Cursor .Loc )
193- h .Cursor .LastVisualX = vloc .VisualX
238+ h .Cursor .StoreVisualX ()
194239 } else {
195240 vloc .SLoc = sloc
196- vloc .VisualX = h .Cursor .LastVisualX
241+ vloc .VisualX = h .Cursor .LastWrappedVisualX
197242 h .Cursor .Loc = h .LocFromVLoc (vloc )
198243 }
199244 }
@@ -657,7 +702,7 @@ func (h *BufPane) InsertNewline() bool {
657702 h .Buf .Remove (buffer.Loc {X : 0 , Y : h .Cursor .Y - 1 }, buffer.Loc {X : util .CharacterCount (line ), Y : h .Cursor .Y - 1 })
658703 }
659704 }
660- h .Cursor .LastVisualX = h . Cursor . GetVisualX ()
705+ h .Cursor .StoreVisualX ()
661706 h .Relocate ()
662707 return true
663708}
@@ -687,7 +732,7 @@ func (h *BufPane) Backspace() bool {
687732 h .Buf .Remove (loc .Move (- 1 , h .Buf ), loc )
688733 }
689734 }
690- h .Cursor .LastVisualX = h . Cursor . GetVisualX ()
735+ h .Cursor .StoreVisualX ()
691736 h .Relocate ()
692737 return true
693738}
@@ -888,7 +933,7 @@ func (h *BufPane) InsertTab() bool {
888933 b := h .Buf
889934 indent := b .IndentString (util .IntOpt (b .Settings ["tabsize" ]))
890935 tabBytes := len (indent )
891- bytesUntilIndent := tabBytes - (h .Cursor .GetVisualX () % tabBytes )
936+ bytesUntilIndent := tabBytes - (h .Cursor .GetVisualX (false ) % tabBytes )
892937 b .Insert (h .Cursor .Loc , indent [:bytesUntilIndent ])
893938 h .Relocate ()
894939 return true
@@ -1254,7 +1299,13 @@ func (h *BufPane) selectLines() int {
12541299 } else {
12551300 h .Cursor .SelectLine ()
12561301 }
1257- return h .Cursor .CurSelection [1 ].Y - h .Cursor .CurSelection [0 ].Y
1302+
1303+ nlines := h .Cursor .CurSelection [1 ].Y - h .Cursor .CurSelection [0 ].Y
1304+ if nlines == 0 && h .Cursor .HasSelection () {
1305+ // selected last line and it is not empty
1306+ nlines ++
1307+ }
1308+ return nlines
12581309}
12591310
12601311// Copy the selection to the system clipboard
@@ -1274,6 +1325,7 @@ func (h *BufPane) Copy() bool {
12741325func (h * BufPane ) CopyLine () bool {
12751326 origLoc := h .Cursor .Loc
12761327 origLastVisualX := h .Cursor .LastVisualX
1328+ origLastWrappedVisualX := h .Cursor .LastWrappedVisualX
12771329 origSelection := h .Cursor .CurSelection
12781330
12791331 nlines := h .selectLines ()
@@ -1290,6 +1342,7 @@ func (h *BufPane) CopyLine() bool {
12901342
12911343 h .Cursor .Loc = origLoc
12921344 h .Cursor .LastVisualX = origLastVisualX
1345+ h .Cursor .LastWrappedVisualX = origLastWrappedVisualX
12931346 h .Cursor .CurSelection = origSelection
12941347 h .Relocate ()
12951348 return true
@@ -1359,6 +1412,7 @@ func (h *BufPane) DuplicateLine() bool {
13591412 if h .Cursor .HasSelection () {
13601413 origLoc := h .Cursor .Loc
13611414 origLastVisualX := h .Cursor .LastVisualX
1415+ origLastWrappedVisualX := h .Cursor .LastWrappedVisualX
13621416 origSelection := h .Cursor .CurSelection
13631417
13641418 start := h .Cursor .CurSelection [0 ]
@@ -1379,6 +1433,7 @@ func (h *BufPane) DuplicateLine() bool {
13791433
13801434 h .Cursor .Loc = origLoc
13811435 h .Cursor .LastVisualX = origLastVisualX
1436+ h .Cursor .LastWrappedVisualX = origLastWrappedVisualX
13821437 h .Cursor .CurSelection = origSelection
13831438
13841439 if start .Y < end .Y {
@@ -1635,63 +1690,77 @@ func (h *BufPane) End() bool {
16351690
16361691// PageUp scrolls the view up a page
16371692func (h * BufPane ) PageUp () bool {
1638- h .ScrollUp (h .BufView ().Height )
1693+ pageOverlap := int (h .Buf .Settings ["pageoverlap" ].(float64 ))
1694+ h .ScrollUp (h .BufView ().Height - pageOverlap )
16391695 return true
16401696}
16411697
16421698// PageDown scrolls the view down a page
16431699func (h * BufPane ) PageDown () bool {
1644- h .ScrollDown (h .BufView ().Height )
1700+ pageOverlap := int (h .Buf .Settings ["pageoverlap" ].(float64 ))
1701+ h .ScrollDown (h .BufView ().Height - pageOverlap )
16451702 h .ScrollAdjust ()
16461703 return true
16471704}
16481705
16491706// SelectPageUp selects up one page
16501707func (h * BufPane ) SelectPageUp () bool {
1708+ pageOverlap := int (h .Buf .Settings ["pageoverlap" ].(float64 ))
1709+ scrollAmount := h .BufView ().Height - pageOverlap
16511710 if ! h .Cursor .HasSelection () {
16521711 h .Cursor .OrigSelection [0 ] = h .Cursor .Loc
16531712 }
1654- h .MoveCursorUp (h . BufView (). Height )
1713+ h .MoveCursorUp (scrollAmount )
16551714 h .Cursor .SelectTo (h .Cursor .Loc )
1715+ if h .Cursor .Num == 0 {
1716+ h .ScrollUp (scrollAmount )
1717+ }
16561718 h .Relocate ()
16571719 return true
16581720}
16591721
16601722// SelectPageDown selects down one page
16611723func (h * BufPane ) SelectPageDown () bool {
1724+ pageOverlap := int (h .Buf .Settings ["pageoverlap" ].(float64 ))
1725+ scrollAmount := h .BufView ().Height - pageOverlap
16621726 if ! h .Cursor .HasSelection () {
16631727 h .Cursor .OrigSelection [0 ] = h .Cursor .Loc
16641728 }
1665- h .MoveCursorDown (h . BufView (). Height )
1729+ h .MoveCursorDown (scrollAmount )
16661730 h .Cursor .SelectTo (h .Cursor .Loc )
1731+ if h .Cursor .Num == 0 {
1732+ h .ScrollDown (scrollAmount )
1733+ h .ScrollAdjust ()
1734+ }
16671735 h .Relocate ()
16681736 return true
16691737}
16701738
1671- // CursorPageUp places the cursor a page up
1739+ // CursorPageUp places the cursor a page up,
1740+ // moving the view to keep cursor at the same relative position in the view
16721741func (h * BufPane ) CursorPageUp () bool {
16731742 h .Cursor .Deselect (true )
1674-
1675- if h . Cursor . HasSelection () {
1676- h . Cursor . Loc = h . Cursor . CurSelection [ 0 ]
1677- h .Cursor .ResetSelection ()
1678- h .Cursor . StoreVisualX ( )
1743+ pageOverlap := int ( h . Buf . Settings [ "pageoverlap" ].( float64 ))
1744+ scrollAmount := h . BufView (). Height - pageOverlap
1745+ h . MoveCursorUp ( scrollAmount )
1746+ if h .Cursor .Num == 0 {
1747+ h .ScrollUp ( scrollAmount )
16791748 }
1680- h .MoveCursorUp (h .BufView ().Height )
16811749 h .Relocate ()
16821750 return true
16831751}
16841752
1685- // CursorPageDown places the cursor a page up
1753+ // CursorPageDown places the cursor a page down,
1754+ // moving the view to keep cursor at the same relative position in the view
16861755func (h * BufPane ) CursorPageDown () bool {
16871756 h .Cursor .Deselect (false )
1688-
1689- if h .Cursor .HasSelection () {
1690- h .Cursor .Loc = h .Cursor .CurSelection [1 ]
1691- h .Cursor .ResetSelection ()
1692- h .Cursor .StoreVisualX ()
1757+ pageOverlap := int (h .Buf .Settings ["pageoverlap" ].(float64 ))
1758+ scrollAmount := h .BufView ().Height - pageOverlap
1759+ h .MoveCursorDown (scrollAmount )
1760+ if h .Cursor .Num == 0 {
1761+ h .ScrollDown (scrollAmount )
1762+ h .ScrollAdjust ()
16931763 }
1694- h .MoveCursorDown (h .BufView ().Height )
16951764 h .Relocate ()
16961765 return true
16971766}
@@ -1744,7 +1813,8 @@ func (h *BufPane) ToggleHelp() bool {
17441813 if h .Buf .Type == buffer .BTHelp {
17451814 h .Quit ()
17461815 } else {
1747- h .openHelp ("help" )
1816+ hsplit := config .GlobalSettings ["helpsplit" ] == "hsplit"
1817+ h .openHelp ("help" , hsplit , false )
17481818 }
17491819 return true
17501820}
@@ -2078,35 +2148,20 @@ func (h *BufPane) SpawnCursorAtLoc(loc buffer.Loc) *buffer.Cursor {
20782148// SpawnMultiCursorUpN is not an action
20792149func (h * BufPane ) SpawnMultiCursorUpN (n int ) bool {
20802150 lastC := h .Buf .GetCursor (h .Buf .NumCursors () - 1 )
2081- var c * buffer.Cursor
2082- if ! h .Buf .Settings ["softwrap" ].(bool ) {
2083- if n > 0 && lastC .Y == 0 {
2084- return false
2085- }
2086- if n < 0 && lastC .Y + 1 == h .Buf .LinesNum () {
2087- return false
2088- }
2089-
2090- h .Buf .DeselectCursors ()
2091-
2092- c = buffer .NewCursor (h .Buf , buffer.Loc {lastC .X , lastC .Y - n })
2093- c .LastVisualX = lastC .LastVisualX
2094- c .X = c .GetCharPosInLine (h .Buf .LineBytes (c .Y ), c .LastVisualX )
2095- c .Relocate ()
2096- } else {
2097- vloc := h .VLocFromLoc (lastC .Loc )
2098- sloc := h .Scroll (vloc .SLoc , - n )
2099- if sloc == vloc .SLoc {
2100- return false
2101- }
2151+ if n > 0 && lastC .Y == 0 {
2152+ return false
2153+ }
2154+ if n < 0 && lastC .Y + 1 == h .Buf .LinesNum () {
2155+ return false
2156+ }
21022157
2103- h .Buf .DeselectCursors ()
2158+ h .Buf .DeselectCursors ()
21042159
2105- vloc . SLoc = sloc
2106- vloc . VisualX = lastC .LastVisualX
2107- c = buffer . NewCursor ( h . Buf , h . LocFromVLoc ( vloc ))
2108- c . LastVisualX = lastC . LastVisualX
2109- }
2160+ c := buffer . NewCursor ( h . Buf , buffer. Loc { lastC . X , lastC . Y - n })
2161+ c . LastVisualX = lastC .LastVisualX
2162+ c . LastWrappedVisualX = lastC . LastWrappedVisualX
2163+ c . X = c . GetCharPosInLine ( h . Buf . LineBytes ( c . Y ), c . LastVisualX )
2164+ c . Relocate ()
21102165
21112166 h .Buf .AddCursor (c )
21122167 h .Buf .SetCurCursor (h .Buf .NumCursors () - 1 )
0 commit comments