diff --git a/cursor.go b/cursor.go index 61bf74f9..da782963 100644 --- a/cursor.go +++ b/cursor.go @@ -1,6 +1,7 @@ package main import ( + // "github.com/gdamore/tcell" "strings" ) @@ -22,13 +23,21 @@ func (c *Cursor) resetSelection() { } func (c *Cursor) hasSelection() bool { - return (c.selectionEnd - c.selectionStart) > 0 + return (c.selectionEnd - c.selectionStart) != 0 } func (c *Cursor) deleteSelected() { // TODO: Implement this } +func (c *Cursor) runeUnder() rune { + line := c.v.buf.lines[c.y] + if c.x >= count(line) { + return ' ' + } + return []rune(line)[c.x] +} + func (c *Cursor) up() { if c.y > 0 { c.loc -= count(c.v.buf.lines[c.y][:c.x]) @@ -86,7 +95,7 @@ func (c *Cursor) start() { c.x = 0 } -func (c *Cursor) getCharPos(lineNum, visualPos int) int { +func (c *Cursor) getCharPosInLine(lineNum, visualPos int) int { visualLine := strings.Replace(c.v.buf.lines[lineNum], "\t", "\t"+emptyString(tabSize-1), -1) if visualPos > count(visualLine) { visualPos = count(visualLine) @@ -135,7 +144,7 @@ func (c *Cursor) distance(x, y int) int { distance-- i++ } - if x > 0 { + if x >= 0 { distance -= count(c.v.buf.lines[y][x:]) } return distance @@ -147,5 +156,7 @@ func (c *Cursor) display() { } else { voffset := numOccurences(c.v.buf.lines[c.y][:c.x], '\t') * (tabSize - 1) c.v.s.ShowCursor(c.x+voffset, c.y-c.v.topline) + // cursorStyle := tcell.StyleDefault.Reverse(true) + // c.v.s.SetContent(c.x+voffset, c.y-c.v.topline, c.runeUnder(), nil, cursorStyle) } } diff --git a/view.go b/view.go index 652485f5..9dea952c 100644 --- a/view.go +++ b/view.go @@ -2,7 +2,6 @@ package main import ( "github.com/gdamore/tcell" - "strings" ) type View struct { @@ -47,6 +46,24 @@ func newViewWidthHeight(buf *Buffer, s tcell.Screen, w, h int) *View { return v } +func (v *View) scrollUp(n int) { + // Try to scroll by n but if it would overflow, scroll by 1 + if v.topline-n >= 0 { + v.topline -= n + } else if v.topline > 0 { + v.topline-- + } +} + +func (v *View) scrollDown(n int) { + // Try to scroll by n but if it would overflow, scroll by 1 + if v.topline+n <= len(v.buf.lines)-v.height { + v.topline += n + } else if v.topline < len(v.buf.lines)-v.height { + v.topline++ + } +} + // Returns an int describing how the screen needs to be redrawn // 0: Screen does not need to be redrawn // 1: Only the cursor/statusline needs to be redrawn @@ -110,16 +127,17 @@ func (v *View) handleEvent(event tcell.Event) int { switch button { case tcell.Button1: if y-v.topline > v.height-1 { + v.scrollDown(1) y = v.height + v.topline - 1 } if y > len(v.buf.lines) { - y = len(v.buf.lines) - 1 + y = len(v.buf.lines) - 2 } + + x = v.cursor.getCharPosInLine(y, x) if x > count(v.buf.lines[y]) { x = count(v.buf.lines[y]) } - - x = v.cursor.getCharPos(y, x) d := v.cursor.distance(x, y) v.cursor.loc += d v.cursor.x = x @@ -130,23 +148,16 @@ func (v *View) handleEvent(event tcell.Event) int { } v.cursor.selectionEnd = v.cursor.loc v.mouseReleased = false - ret = 2 + return 2 case tcell.ButtonNone: v.mouseReleased = true + return 0 case tcell.WheelUp: - if v.topline > 0 { - v.topline-- - return 2 - } else { - return 0 - } + v.scrollUp(2) + return 2 case tcell.WheelDown: - if v.topline < len(v.buf.lines)-v.height { - v.topline++ - return 2 - } else { - return 0 - } + v.scrollDown(2) + return 2 } } @@ -169,14 +180,23 @@ func (v *View) display() { if lineN+v.topline >= len(v.buf.lines) { break } - line := strings.Replace(v.buf.lines[lineN+v.topline], "\t", emptyString(tabSize), -1) + // line := strings.Replace(v.buf.lines[lineN+v.topline], "\t", emptyString(tabSize), -1) + line := v.buf.lines[lineN+v.topline] + var tabchars int for colN, ch := range line { st := tcell.StyleDefault if v.cursor.hasSelection() && charNum >= v.cursor.selectionStart && charNum <= v.cursor.selectionEnd { st = st.Reverse(true) } - v.s.SetContent(colN, lineN, ch, nil, st) + if ch == '\t' { + for i := 0; i < tabSize-1; i++ { + v.s.SetContent(colN+tabchars, lineN, ' ', nil, st) + tabchars++ + } + } else { + v.s.SetContent(colN+tabchars, lineN, ch, nil, st) + } charNum++ } charNum++