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

Code before:
		if sloc == vloc.SLoc {
			// we are at the end of buffer
			h.Cursor.Loc = h.Buf.End()
			h.Cursor.StoreVisualX()
		} else {
			vloc.SLoc = sloc
			vloc.VisualX = h.Cursor.LastWrappedVisualX
			h.Cursor.Loc = h.LocFromVLoc(vloc)
		}
	}
}

// CursorUp moves the cursor up
func (h *BufPane) CursorUp() bool {
	h.Cursor.Deselect(true)
	h.MoveCursorUp(1)
	h.Relocate()
	return true
}

// CursorDown moves the cursor down
func (h *BufPane) CursorDown() bool {
	downN := 1
	if h.Cursor.HasSelection() {
		if h.Cursor.CurSelection[1].X == 0 {
			h.Cursor.Deselect(true)
			downN += 1
		} else {
			h.Cursor.Deselect(false)
		}
	}
	h.MoveCursorDown(downN)
	h.Relocate()
	return true
}

// CursorLeft moves the cursor left
func (h *BufPane) CursorLeft() bool {
	if h.Cursor.HasSelection() {
		h.Cursor.Deselect(true)
	} else {
		tabstospaces := h.Buf.Settings["tabstospaces"].(bool)
		tabmovement := h.Buf.Settings["tabmovement"].(bool)
		if tabstospaces && tabmovement {
			tabsize := int(h.Buf.Settings["tabsize"].(float64))
			line := h.Buf.LineBytes(h.Cursor.Y)
			if h.Cursor.X-tabsize >= 0 && util.IsSpaces(line[h.Cursor.X-tabsize:h.Cursor.X]) && util.IsBytesWhitespace(line[0:h.Cursor.X-tabsize]) {
				for i := 0; i < tabsize; i++ {
					h.Cursor.Left()
				}
			} else {

Review comment (bug):
This looks completely wrong. Try selecting any number of lines other than 2 and pressing Down and see what happens.

How about something straightforward like:
```go
--- a/internal/action/actions.go
+++ b/internal/action/actions.go
@@ -254,8 +254,12 @@ func (h *BufPane) CursorUp() bool {
 
 // CursorDown moves the cursor down
 func (h *BufPane) CursorDown() bool {
+	selectionEndNewline := h.Cursor.HasSelection() && h.Cursor.CurSelection[1].X == 0
 	h.Cursor.Deselect(false)
 	h.MoveCursorDown(1)
+	if selectionEndNewline {
+		h.Cursor.Start()
+	}
 	h.Relocate()
 	return true
 }
```

Code after:
		if sloc == vloc.SLoc {
			// we are at the end of buffer
			h.Cursor.Loc = h.Buf.End()
			h.Cursor.StoreVisualX()
		} else {
			vloc.SLoc = sloc
			vloc.VisualX = h.Cursor.LastWrappedVisualX
			h.Cursor.Loc = h.LocFromVLoc(vloc)
		}
	}
}

// CursorUp moves the cursor up
func (h *BufPane) CursorUp() bool {
	h.Cursor.Deselect(true)
	h.MoveCursorUp(1)
	h.Relocate()
	return true
}

// CursorDown moves the cursor down
func (h *BufPane) CursorDown() bool {
	selectionEndNewline := h.Cursor.HasSelection() && h.Cursor.CurSelection[1].X == 0
	h.Cursor.Deselect(false)
	if selectionEndNewline {
		h.Cursor.Start()
	} else {
		h.MoveCursorDown(1)
	}
	h.Relocate()
	return true
}

// CursorLeft moves the cursor left
func (h *BufPane) CursorLeft() bool {
	if h.Cursor.HasSelection() {
		h.Cursor.Deselect(true)
	} else {
		tabstospaces := h.Buf.Settings["tabstospaces"].(bool)
		tabmovement := h.Buf.Settings["tabmovement"].(bool)
		if tabstospaces && tabmovement {
			tabsize := int(h.Buf.Settings["tabsize"].(float64))
			line := h.Buf.LineBytes(h.Cursor.Y)
			if h.Cursor.X-tabsize >= 0 && util.IsSpaces(line[h.Cursor.X-tabsize:h.Cursor.X]) && util.IsBytesWhitespace(line[0:h.Cursor.X-tabsize]) {
				for i := 0; i < tabsize; i++ {
					h.Cursor.Left()
				}
			} else {
				h.Cursor.Left()
			}
		} else {