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
|
// 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
|
// 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. 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 {
|
type Region struct {
|
||||||
buffer *Buffer
|
Start Cursor
|
||||||
start position
|
End Cursor
|
||||||
end position
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRegion(in *Buffer) Region {
|
func NewRegion(in *Buffer) Region {
|
||||||
return 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
|
// A Cursor's functions emulate common cursor actions. To have a Cursor be
|
||||||
// automatically updated when the buffer has text prepended or appended -- one
|
// automatically updated when the buffer has text prepended or appended -- one
|
||||||
// should register the Cursor with the Buffer's function `RegisterCursor()`
|
// 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)
|
c.line, c.col = (*c.buffer).ClampLineCol(line, col)
|
||||||
return c
|
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.Buffer = buffer.NewRopeBuffer(contents)
|
||||||
t.cursor = buffer.NewCursor(&t.Buffer)
|
t.cursor = buffer.NewCursor(&t.Buffer)
|
||||||
|
t.selection = buffer.NewRegion(&t.Buffer)
|
||||||
|
|
||||||
// TODO: replace with automatic determination of language via filetype
|
// TODO: replace with automatic determination of language via filetype
|
||||||
lang := &buffer.Language{
|
lang := &buffer.Language{
|
||||||
@ -151,8 +152,8 @@ func (t *TextEdit) Delete(forwards bool) {
|
|||||||
if t.selectMode { // If text is selected, delete the whole selection
|
if t.selectMode { // If text is selected, delete the whole selection
|
||||||
t.selectMode = false // Disable selection and prevent infinite loop
|
t.selectMode = false // Disable selection and prevent infinite loop
|
||||||
|
|
||||||
startLine, startCol := t.selection.Start()
|
startLine, startCol := t.selection.Start.GetLineCol()
|
||||||
endLine, endCol := t.selection.End()
|
endLine, endCol := t.selection.End.GetLineCol()
|
||||||
|
|
||||||
// Delete the region
|
// Delete the region
|
||||||
t.Buffer.Remove(startLine, startCol, endLine, endCol)
|
t.Buffer.Remove(startLine, startCol, endLine, endCol)
|
||||||
@ -319,8 +320,8 @@ func (t *TextEdit) getColumnWidth() int {
|
|||||||
func (t *TextEdit) GetSelectedBytes() []byte {
|
func (t *TextEdit) GetSelectedBytes() []byte {
|
||||||
// TODO: there's a bug with copying text
|
// TODO: there's a bug with copying text
|
||||||
if t.selectMode {
|
if t.selectMode {
|
||||||
startLine, startCol := t.selection.Start()
|
startLine, startCol := t.selection.Start.GetLineCol()
|
||||||
endLine, endCol := t.selection.End()
|
endLine, endCol := t.selection.End.GetLineCol()
|
||||||
return t.Buffer.Slice(startLine, startCol, endLine, endCol)
|
return t.Buffer.Slice(startLine, startCol, endLine, endCol)
|
||||||
}
|
}
|
||||||
return []byte{}
|
return []byte{}
|
||||||
@ -421,8 +422,8 @@ func (t *TextEdit) Draw(s tcell.Screen) {
|
|||||||
r = ' '
|
r = ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
startLine, startCol := t.selection.Start()
|
startLine, startCol := t.selection.Start.GetLineCol()
|
||||||
endLine, endCol := t.selection.End()
|
endLine, endCol := t.selection.End.GetLineCol()
|
||||||
|
|
||||||
// Determine whether we select the current rune. Also only select runes within
|
// Determine whether we select the current rune. Also only select runes within
|
||||||
// the line bytes range.
|
// the line bytes range.
|
||||||
@ -508,87 +509,98 @@ func (t *TextEdit) HandleEvent(event tcell.Event) bool {
|
|||||||
// Cursor movement
|
// Cursor movement
|
||||||
case tcell.KeyUp:
|
case tcell.KeyUp:
|
||||||
if ev.Modifiers() == tcell.ModShift {
|
if ev.Modifiers() == tcell.ModShift {
|
||||||
// if !t.selectMode {
|
if !t.selectMode {
|
||||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
var endCursor buffer.Cursor
|
||||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
if cursLine, _ := t.cursor.GetLineCol(); cursLine != 0 {
|
||||||
// t.selectMode = true
|
endCursor = t.cursor.Left()
|
||||||
// } else {
|
} else {
|
||||||
// prevCurX, prevCurY := t.curx, t.cury
|
endCursor = t.cursor
|
||||||
// t.CursorUp()
|
}
|
||||||
// // Grow the selection in the correct direction
|
t.selection.End = endCursor
|
||||||
// if prevCurY <= t.selection.StartLine && prevCurX <= t.selection.StartCol {
|
t.SetCursor(t.cursor.Up())
|
||||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
t.selection.Start = t.cursor
|
||||||
// } else {
|
t.selectMode = true
|
||||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
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 {
|
} else {
|
||||||
t.selectMode = false
|
t.selectMode = false
|
||||||
t.SetCursor(t.cursor.Up())
|
t.SetCursor(t.cursor.Up())
|
||||||
t.ScrollToCursor()
|
|
||||||
}
|
}
|
||||||
|
t.ScrollToCursor()
|
||||||
case tcell.KeyDown:
|
case tcell.KeyDown:
|
||||||
if ev.Modifiers() == tcell.ModShift {
|
if ev.Modifiers() == tcell.ModShift {
|
||||||
// if !t.selectMode {
|
if !t.selectMode {
|
||||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
t.selection.Start = t.cursor
|
||||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
t.SetCursor(t.cursor.Down())
|
||||||
// t.selectMode = true
|
t.selection.End = t.cursor
|
||||||
// } else {
|
t.selectMode = true
|
||||||
// prevCurX, prevCurY := t.curx, t.cury
|
t.ScrollToCursor()
|
||||||
// t.CursorDown()
|
break
|
||||||
// if prevCurY >= t.selection.EndLine && prevCurX >= t.selection.EndCol {
|
}
|
||||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
|
||||||
// } else {
|
if t.selection.End.Eq(t.cursor) {
|
||||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
t.SetCursor(t.cursor.Down())
|
||||||
// }
|
t.selection.End = t.cursor
|
||||||
// }
|
} else {
|
||||||
|
t.SetCursor(t.cursor.Down())
|
||||||
|
t.selection.Start = t.cursor
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
t.selectMode = false
|
t.selectMode = false
|
||||||
t.SetCursor(t.cursor.Down())
|
t.SetCursor(t.cursor.Down())
|
||||||
t.ScrollToCursor()
|
|
||||||
}
|
}
|
||||||
|
t.ScrollToCursor()
|
||||||
case tcell.KeyLeft:
|
case tcell.KeyLeft:
|
||||||
if ev.Modifiers() == tcell.ModShift {
|
if ev.Modifiers() == tcell.ModShift {
|
||||||
// if !t.selectMode {
|
if !t.selectMode {
|
||||||
// t.CursorLeft() // We want the character to the left to be selected only (think insert)
|
t.SetCursor(t.cursor.Left())
|
||||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
t.selection.Start, t.selection.End = t.cursor, t.cursor
|
||||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
t.selectMode = true
|
||||||
// t.selectMode = true
|
t.ScrollToCursor()
|
||||||
// } else {
|
break // Select only a single character at start
|
||||||
// prevCurX, prevCurY := t.curx, t.cury
|
}
|
||||||
// t.CursorLeft()
|
|
||||||
// if prevCurY == t.selection.StartLine && prevCurX == t.selection.StartCol { // We are moving the start...
|
if t.selection.Start.Eq(t.cursor) {
|
||||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
t.SetCursor(t.cursor.Left())
|
||||||
// } else {
|
t.selection.Start = t.cursor
|
||||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
} else {
|
||||||
// }
|
t.SetCursor(t.cursor.Left())
|
||||||
// }
|
t.selection.End = t.cursor
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
t.selectMode = false
|
t.selectMode = false
|
||||||
t.SetCursor(t.cursor.Left())
|
t.SetCursor(t.cursor.Left())
|
||||||
t.ScrollToCursor()
|
|
||||||
}
|
}
|
||||||
|
t.ScrollToCursor()
|
||||||
case tcell.KeyRight:
|
case tcell.KeyRight:
|
||||||
if ev.Modifiers() == tcell.ModShift {
|
if ev.Modifiers() == tcell.ModShift {
|
||||||
// if !t.selectMode { // If we are not already selecting...
|
if !t.selectMode {
|
||||||
// // Reset the selection to cursor pos
|
t.selection.Start, t.selection.End = t.cursor, t.cursor
|
||||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
t.selectMode = true
|
||||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
break
|
||||||
// t.selectMode = true
|
}
|
||||||
// } else {
|
|
||||||
// prevCurX, prevCurY := t.curx, t.cury
|
if t.selection.End.Eq(t.cursor) {
|
||||||
// t.CursorRight() // Advance the cursor
|
t.SetCursor(t.cursor.Right())
|
||||||
// if prevCurY == t.selection.EndLine && prevCurX == t.selection.EndCol {
|
t.selection.End = t.cursor
|
||||||
// t.selection.EndLine, t.selection.EndCol = t.cury, t.curx
|
} else {
|
||||||
// } else {
|
t.SetCursor(t.cursor.Right())
|
||||||
// t.selection.StartLine, t.selection.StartCol = t.cury, t.curx
|
t.selection.Start = t.cursor
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
t.selectMode = false
|
t.selectMode = false
|
||||||
t.SetCursor(t.cursor.Right())
|
t.SetCursor(t.cursor.Right())
|
||||||
t.ScrollToCursor()
|
|
||||||
}
|
}
|
||||||
|
t.ScrollToCursor()
|
||||||
case tcell.KeyHome:
|
case tcell.KeyHome:
|
||||||
cursLine, _ := t.cursor.GetLineCol()
|
cursLine, _ := t.cursor.GetLineCol()
|
||||||
// TODO: go to first (non-whitespace) character on current line, if we are not already there
|
// 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