Reimplement simple selection
This commit is contained in:
parent
b0ca65a613
commit
8d775804cb
@ -17,27 +17,19 @@ type position struct {
|
||||
// The start and end are inclusive. If the EndCol of a Region is one more than the
|
||||
// last column of a line, then it points to the line delimiter at the end of that
|
||||
// line. It is understood that as a Region spans multiple lines, those connecting
|
||||
// line-delimiters are included, as well.
|
||||
// line-delimiters are included in the selection, as well.
|
||||
type Region struct {
|
||||
buffer *Buffer
|
||||
start position
|
||||
end position
|
||||
Start Cursor
|
||||
End Cursor
|
||||
}
|
||||
|
||||
func NewRegion(in *Buffer) Region {
|
||||
return Region{
|
||||
buffer: in,
|
||||
NewCursor(in),
|
||||
NewCursor(in),
|
||||
}
|
||||
}
|
||||
|
||||
func (r Region) Start() (line, col int) {
|
||||
return r.start.line, r.start.col
|
||||
}
|
||||
|
||||
func (r Region) End() (line, col int) {
|
||||
return r.end.line, r.end.col
|
||||
}
|
||||
|
||||
// A Cursor's functions emulate common cursor actions. To have a Cursor be
|
||||
// automatically updated when the buffer has text prepended or appended -- one
|
||||
// should register the Cursor with the Buffer's function `RegisterCursor()`
|
||||
@ -105,3 +97,7 @@ func (c Cursor) SetLineCol(line, col int) Cursor {
|
||||
c.line, c.col = (*c.buffer).ClampLineCol(line, col)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c Cursor) Eq(other Cursor) bool {
|
||||
return c.buffer == other.buffer && c.line == other.line && c.col == other.col
|
||||
}
|
||||
|
142
ui/textedit.go
142
ui/textedit.go
@ -77,6 +77,7 @@ loop:
|
||||
|
||||
t.Buffer = buffer.NewRopeBuffer(contents)
|
||||
t.cursor = buffer.NewCursor(&t.Buffer)
|
||||
t.selection = buffer.NewRegion(&t.Buffer)
|
||||
|
||||
// TODO: replace with automatic determination of language via filetype
|
||||
lang := &buffer.Language{
|
||||
@ -151,8 +152,8 @@ func (t *TextEdit) Delete(forwards bool) {
|
||||
if t.selectMode { // If text is selected, delete the whole selection
|
||||
t.selectMode = false // Disable selection and prevent infinite loop
|
||||
|
||||
startLine, startCol := t.selection.Start()
|
||||
endLine, endCol := t.selection.End()
|
||||
startLine, startCol := t.selection.Start.GetLineCol()
|
||||
endLine, endCol := t.selection.End.GetLineCol()
|
||||
|
||||
// Delete the region
|
||||
t.Buffer.Remove(startLine, startCol, endLine, endCol)
|
||||
@ -319,8 +320,8 @@ func (t *TextEdit) getColumnWidth() int {
|
||||
func (t *TextEdit) GetSelectedBytes() []byte {
|
||||
// TODO: there's a bug with copying text
|
||||
if t.selectMode {
|
||||
startLine, startCol := t.selection.Start()
|
||||
endLine, endCol := t.selection.End()
|
||||
startLine, startCol := t.selection.Start.GetLineCol()
|
||||
endLine, endCol := t.selection.End.GetLineCol()
|
||||
return t.Buffer.Slice(startLine, startCol, endLine, endCol)
|
||||
}
|
||||
return []byte{}
|
||||
@ -421,8 +422,8 @@ func (t *TextEdit) Draw(s tcell.Screen) {
|
||||
r = ' '
|
||||
}
|
||||
|
||||
startLine, startCol := t.selection.Start()
|
||||
endLine, endCol := t.selection.End()
|
||||
startLine, startCol := t.selection.Start.GetLineCol()
|
||||
endLine, endCol := t.selection.End.GetLineCol()
|
||||
|
||||
// Determine whether we select the current rune. Also only select runes within
|
||||
// the line bytes range.
|
||||
@ -508,87 +509,98 @@ func (t *TextEdit) HandleEvent(event tcell.Event) bool {
|
||||
// Cursor movement
|
||||
case tcell.KeyUp:
|
||||
if ev.Modifiers() == tcell.ModShift {
|
||||
// if !t.selectMode {
|
||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
||||
// t.selectMode = true
|
||||
// } else {
|
||||
// prevCurX, prevCurY := t.curx, t.cury
|
||||
// t.CursorUp()
|
||||
// // Grow the selection in the correct direction
|
||||
// if prevCurY <= t.selection.StartLine && prevCurX <= t.selection.StartCol {
|
||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
||||
// } else {
|
||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
||||
// }
|
||||
// }
|
||||
if !t.selectMode {
|
||||
var endCursor buffer.Cursor
|
||||
if cursLine, _ := t.cursor.GetLineCol(); cursLine != 0 {
|
||||
endCursor = t.cursor.Left()
|
||||
} else {
|
||||
endCursor = t.cursor
|
||||
}
|
||||
t.selection.End = endCursor
|
||||
t.SetCursor(t.cursor.Up())
|
||||
t.selection.Start = t.cursor
|
||||
t.selectMode = true
|
||||
t.ScrollToCursor()
|
||||
break // Select only a single character at start
|
||||
}
|
||||
|
||||
if t.selection.Start.Eq(t.cursor) {
|
||||
t.SetCursor(t.cursor.Up())
|
||||
t.selection.Start = t.cursor
|
||||
} else {
|
||||
t.SetCursor(t.cursor.Up())
|
||||
t.selection.End = t.cursor
|
||||
}
|
||||
} else {
|
||||
t.selectMode = false
|
||||
t.SetCursor(t.cursor.Up())
|
||||
t.ScrollToCursor()
|
||||
}
|
||||
t.ScrollToCursor()
|
||||
case tcell.KeyDown:
|
||||
if ev.Modifiers() == tcell.ModShift {
|
||||
// if !t.selectMode {
|
||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
||||
// t.selectMode = true
|
||||
// } else {
|
||||
// prevCurX, prevCurY := t.curx, t.cury
|
||||
// t.CursorDown()
|
||||
// if prevCurY >= t.selection.EndLine && prevCurX >= t.selection.EndCol {
|
||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
||||
// } else {
|
||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
||||
// }
|
||||
// }
|
||||
if !t.selectMode {
|
||||
t.selection.Start = t.cursor
|
||||
t.SetCursor(t.cursor.Down())
|
||||
t.selection.End = t.cursor
|
||||
t.selectMode = true
|
||||
t.ScrollToCursor()
|
||||
break
|
||||
}
|
||||
|
||||
if t.selection.End.Eq(t.cursor) {
|
||||
t.SetCursor(t.cursor.Down())
|
||||
t.selection.End = t.cursor
|
||||
} else {
|
||||
t.SetCursor(t.cursor.Down())
|
||||
t.selection.Start = t.cursor
|
||||
}
|
||||
} else {
|
||||
t.selectMode = false
|
||||
t.SetCursor(t.cursor.Down())
|
||||
t.ScrollToCursor()
|
||||
}
|
||||
t.ScrollToCursor()
|
||||
case tcell.KeyLeft:
|
||||
if ev.Modifiers() == tcell.ModShift {
|
||||
// if !t.selectMode {
|
||||
// t.CursorLeft() // We want the character to the left to be selected only (think insert)
|
||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
||||
// t.selectMode = true
|
||||
// } else {
|
||||
// prevCurX, prevCurY := t.curx, t.cury
|
||||
// t.CursorLeft()
|
||||
// if prevCurY == t.selection.StartLine && prevCurX == t.selection.StartCol { // We are moving the start...
|
||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
||||
// } else {
|
||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
||||
// }
|
||||
// }
|
||||
if !t.selectMode {
|
||||
t.SetCursor(t.cursor.Left())
|
||||
t.selection.Start, t.selection.End = t.cursor, t.cursor
|
||||
t.selectMode = true
|
||||
t.ScrollToCursor()
|
||||
break // Select only a single character at start
|
||||
}
|
||||
|
||||
if t.selection.Start.Eq(t.cursor) {
|
||||
t.SetCursor(t.cursor.Left())
|
||||
t.selection.Start = t.cursor
|
||||
} else {
|
||||
t.SetCursor(t.cursor.Left())
|
||||
t.selection.End = t.cursor
|
||||
}
|
||||
} else {
|
||||
t.selectMode = false
|
||||
t.SetCursor(t.cursor.Left())
|
||||
t.ScrollToCursor()
|
||||
}
|
||||
t.ScrollToCursor()
|
||||
case tcell.KeyRight:
|
||||
if ev.Modifiers() == tcell.ModShift {
|
||||
// if !t.selectMode { // If we are not already selecting...
|
||||
// // Reset the selection to cursor pos
|
||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
||||
// t.selectMode = true
|
||||
// } else {
|
||||
// prevCurX, prevCurY := t.curx, t.cury
|
||||
// t.CursorRight() // Advance the cursor
|
||||
// if prevCurY == t.selection.EndLine && prevCurX == t.selection.EndCol {
|
||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
||||
// } else {
|
||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
||||
// }
|
||||
// }
|
||||
if !t.selectMode {
|
||||
t.selection.Start, t.selection.End = t.cursor, t.cursor
|
||||
t.selectMode = true
|
||||
break
|
||||
}
|
||||
|
||||
if t.selection.End.Eq(t.cursor) {
|
||||
t.SetCursor(t.cursor.Right())
|
||||
t.selection.End = t.cursor
|
||||
} else {
|
||||
t.SetCursor(t.cursor.Right())
|
||||
t.selection.Start = t.cursor
|
||||
}
|
||||
} else {
|
||||
t.selectMode = false
|
||||
t.SetCursor(t.cursor.Right())
|
||||
t.ScrollToCursor()
|
||||
}
|
||||
t.ScrollToCursor()
|
||||
case tcell.KeyHome:
|
||||
cursLine, _ := t.cursor.GetLineCol()
|
||||
// TODO: go to first (non-whitespace) character on current line, if we are not already there
|
||||
|
Loading…
x
Reference in New Issue
Block a user