Repository: zyedidia/micro
File: internal/action/actions.go (Go)

Code before:
func (h *BufPane) ScrollUpAction() bool {
	h.ScrollUp(util.IntOpt(h.Buf.Settings["scrollspeed"]))
	return true
}

// ScrollDownAction scrolls the view up
func (h *BufPane) ScrollDownAction() bool {
	h.ScrollDown(util.IntOpt(h.Buf.Settings["scrollspeed"]))
	return true
}

// Center centers the view on the cursor
func (h *BufPane) Center() bool {
	v := h.GetView()
	v.StartLine = h.Scroll(h.SLocFromLoc(h.Cursor.Loc), -h.BufView().Height/2)
	h.SetView(v)
	h.ScrollAdjust()
	return true
}

// CursorToView moves the cursor to the current view
func (h *BufPane) CursorToView() bool {
	v := h.GetView()
	h.Cursor.Deselect(true)
	loc := h.Cursor.Loc
	if(loc.Y < v.StartLine.Line || loc.Y > v.StartLine.Line + h.BufView().Height - 1) {
		scrollmargin := int(h.Buf.Settings["scrollmargin"].(float64))
		h.Cursor.GotoLoc(h.LocFromVLoc(display.VLoc{
			SLoc: h.Scroll(v.StartLine, scrollmargin),
			VisualX: 0,
		}))
		h.RemoveAllMultiCursors()
	}
	return true
}

// MoveCursorUp is not an action
func (h *BufPane) MoveCursorUp(n int) {
	if !h.Buf.Settings["softwrap"].(bool) {
		h.Cursor.UpN(n)
	} else {
		vloc := h.VLocFromLoc(h.Cursor.Loc)
		sloc := h.Scroll(vloc.SLoc, -n)
		if sloc == vloc.SLoc {
			// we are at the beginning of buffer
			h.Cursor.Loc = h.Buf.Start()
			h.Cursor.LastVisualX = 0
		} else {
			vloc.SLoc = sloc
			vloc.VisualX = h.Cursor.LastVisualX
			h.Cursor.Loc = h.LocFromVLoc(vloc)

Review comment (suggestion):
This is, again, not the right way to check if the cursor is within the view. For the same reason: the cursor may be in the first line in the view, yet outside the view, since this line may be wrapped, so only a part of this line may be visible. That's why `v.StartLine` is a `SLoc` structure, with 2 fields: `Line` which is the number of the logical line in the file, and `Row` which is the number of the visual line within this logical line.

The right way is:

```
	sloc := h.SLocFromLoc(h.Cursor.Loc)
	if sloc.LessThan(v.StartLine) || sloc.GreaterThan(h.Scroll(v.StartLine, h.BufView().Height-1)) {
```

Code after:
func (h *BufPane) ScrollUpAction() bool {
	h.ScrollUp(util.IntOpt(h.Buf.Settings["scrollspeed"]))
	return true
}

// ScrollDownAction scrolls the view up
func (h *BufPane) ScrollDownAction() bool {
	h.ScrollDown(util.IntOpt(h.Buf.Settings["scrollspeed"]))
	return true
}

// Center centers the view on the cursor
func (h *BufPane) Center() bool {
	v := h.GetView()
	v.StartLine = h.Scroll(h.SLocFromLoc(h.Cursor.Loc), -h.BufView().Height/2)
	h.SetView(v)
	h.ScrollAdjust()
	return true
}

// CursorToViewTop moves the cursor to the top of the view,
// offset by scrollmargin unless at the beginning or end of the file
func (h *BufPane) CursorToViewTop() bool {
	v := h.GetView()
	h.Buf.ClearCursors()
	scrollmargin := int(h.Buf.Settings["scrollmargin"].(float64))
	bStart := display.SLoc{0, 0}
	if v.StartLine == bStart {
		scrollmargin = 0
	}
	h.Cursor.GotoLoc(h.LocFromVLoc(display.VLoc{
		SLoc:    h.Scroll(v.StartLine, scrollmargin),
		VisualX: 0,
	}))
	return true
}

// CursorToViewCenter moves the cursor to the center of the view
func (h *BufPane) CursorToViewCenter() bool {
	v := h.GetView()
	h.Buf.ClearCursors()
	h.Cursor.GotoLoc(h.LocFromVLoc(display.VLoc{
		SLoc:    h.Scroll(v.StartLine, h.BufView().Height/2),
		VisualX: 0,
	}))
	return true
}

// CursorToViewBottom moves the cursor to the bottom of the view,
// offset by scrollmargin unless at the beginning or end of the file
func (h *BufPane) CursorToViewBottom() bool {