mirror of
https://github.com/1f349/voidterm.git
synced 2024-11-13 23:41:38 +00:00
325 lines
7.2 KiB
Go
325 lines
7.2 KiB
Go
package termutil
|
|
|
|
func (buffer *Buffer) ClearSelection() {
|
|
buffer.selectionMu.Lock()
|
|
defer buffer.selectionMu.Unlock()
|
|
buffer.selectionStart = nil
|
|
buffer.selectionEnd = nil
|
|
}
|
|
|
|
func (buffer *Buffer) GetBoundedTextAtPosition(pos Position) (start Position, end Position, text string, textIndex int, found bool) {
|
|
return buffer.FindWordAt(pos, func(r rune) bool {
|
|
return r > 0 && r < 256
|
|
})
|
|
}
|
|
|
|
// if the selection is invalid - e.g. lines are selected that no longer exist in the buffer
|
|
func (buffer *Buffer) fixSelection() bool {
|
|
buffer.selectionMu.Lock()
|
|
defer buffer.selectionMu.Unlock()
|
|
|
|
if buffer.selectionStart == nil || buffer.selectionEnd == nil {
|
|
return false
|
|
}
|
|
|
|
if buffer.selectionStart.Line >= uint64(len(buffer.lines)) {
|
|
buffer.selectionStart.Line = uint64(len(buffer.lines)) - 1
|
|
}
|
|
|
|
if buffer.selectionEnd.Line >= uint64(len(buffer.lines)) {
|
|
buffer.selectionEnd.Line = uint64(len(buffer.lines)) - 1
|
|
}
|
|
|
|
if buffer.selectionStart.Col >= uint16(len(buffer.lines[buffer.selectionStart.Line].cells)) {
|
|
buffer.selectionStart.Col = 0
|
|
if buffer.selectionStart.Line < uint64(len(buffer.lines))-1 {
|
|
buffer.selectionStart.Line++
|
|
}
|
|
}
|
|
|
|
if buffer.selectionEnd.Col >= uint16(len(buffer.lines[buffer.selectionEnd.Line].cells)) {
|
|
buffer.selectionEnd.Col = uint16(len(buffer.lines[buffer.selectionEnd.Line].cells)) - 1
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (buffer *Buffer) ExtendSelectionToEntireLines() {
|
|
if !buffer.fixSelection() {
|
|
return
|
|
}
|
|
|
|
buffer.selectionMu.Lock()
|
|
defer buffer.selectionMu.Unlock()
|
|
|
|
buffer.selectionStart.Col = 0
|
|
buffer.selectionEnd.Col = uint16(len(buffer.lines[buffer.selectionEnd.Line].cells)) - 1
|
|
}
|
|
|
|
type RuneMatcher func(r rune) bool
|
|
|
|
func (buffer *Buffer) SelectWordAt(pos Position, runeMatcher RuneMatcher) {
|
|
start, end, _, _, found := buffer.FindWordAt(pos, runeMatcher)
|
|
if !found {
|
|
return
|
|
}
|
|
buffer.setRawSelectionStart(start)
|
|
buffer.setRawSelectionEnd(end)
|
|
}
|
|
|
|
// takes raw coords
|
|
func (buffer *Buffer) Highlight(start Position, end Position, annotation *Annotation) {
|
|
buffer.highlightStart = &start
|
|
buffer.highlightEnd = &end
|
|
buffer.highlightAnnotation = annotation
|
|
}
|
|
|
|
func (buffer *Buffer) ClearHighlight() {
|
|
buffer.highlightStart = nil
|
|
buffer.highlightEnd = nil
|
|
}
|
|
|
|
// returns raw lines
|
|
func (buffer *Buffer) FindWordAt(pos Position, runeMatcher RuneMatcher) (start Position, end Position, text string, textIndex int, found bool) {
|
|
line := buffer.convertViewLineToRawLine(uint16(pos.Line))
|
|
col := pos.Col
|
|
|
|
if line >= uint64(len(buffer.lines)) {
|
|
return
|
|
}
|
|
if col >= uint16(len(buffer.lines[line].cells)) {
|
|
return
|
|
}
|
|
|
|
if !runeMatcher(buffer.lines[line].cells[col].r.Rune) {
|
|
return
|
|
}
|
|
|
|
found = true
|
|
|
|
start = Position{
|
|
Line: line,
|
|
Col: col,
|
|
}
|
|
end = Position{
|
|
Line: line,
|
|
Col: col,
|
|
}
|
|
|
|
var startCol uint16
|
|
BACK:
|
|
for y := int(line); y >= 0; y-- {
|
|
if y == int(line) {
|
|
startCol = col
|
|
} else {
|
|
if len(buffer.lines[y].cells) < int(buffer.viewWidth) {
|
|
break
|
|
}
|
|
startCol = uint16(len(buffer.lines[y].cells) - 1)
|
|
}
|
|
for x := int(startCol); x >= 0; x-- {
|
|
if runeMatcher(buffer.lines[y].cells[x].r.Rune) {
|
|
start = Position{
|
|
Line: uint64(y),
|
|
Col: uint16(x),
|
|
}
|
|
text = string(buffer.lines[y].cells[x].r.Rune) + text
|
|
} else {
|
|
break BACK
|
|
}
|
|
}
|
|
|
|
}
|
|
textIndex = len([]rune(text)) - 1
|
|
FORWARD:
|
|
for y := uint64(line); y < uint64(len(buffer.lines)); y++ {
|
|
if y == line {
|
|
startCol = col + 1
|
|
} else {
|
|
startCol = 0
|
|
}
|
|
for x := int(startCol); x < len(buffer.lines[y].cells); x++ {
|
|
if runeMatcher(buffer.lines[y].cells[x].r.Rune) {
|
|
end = Position{
|
|
Line: y,
|
|
Col: uint16(x),
|
|
}
|
|
text = text + string(buffer.lines[y].cells[x].r.Rune)
|
|
} else {
|
|
break FORWARD
|
|
}
|
|
}
|
|
if len(buffer.lines[y].cells) < int(buffer.viewWidth) {
|
|
break
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (buffer *Buffer) SetSelectionStart(pos Position) {
|
|
buffer.selectionMu.Lock()
|
|
defer buffer.selectionMu.Unlock()
|
|
buffer.selectionStart = &Position{
|
|
Col: pos.Col,
|
|
Line: buffer.convertViewLineToRawLine(uint16(pos.Line)),
|
|
}
|
|
}
|
|
|
|
func (buffer *Buffer) setRawSelectionStart(pos Position) {
|
|
buffer.selectionMu.Lock()
|
|
defer buffer.selectionMu.Unlock()
|
|
buffer.selectionStart = &pos
|
|
}
|
|
|
|
func (buffer *Buffer) SetSelectionEnd(pos Position) {
|
|
buffer.selectionMu.Lock()
|
|
defer buffer.selectionMu.Unlock()
|
|
buffer.selectionEnd = &Position{
|
|
Col: pos.Col,
|
|
Line: buffer.convertViewLineToRawLine(uint16(pos.Line)),
|
|
}
|
|
}
|
|
|
|
func (buffer *Buffer) setRawSelectionEnd(pos Position) {
|
|
buffer.selectionMu.Lock()
|
|
defer buffer.selectionMu.Unlock()
|
|
buffer.selectionEnd = &pos
|
|
}
|
|
|
|
func (buffer *Buffer) GetSelection() (string, *Selection) {
|
|
if !buffer.fixSelection() {
|
|
return "", nil
|
|
}
|
|
|
|
buffer.selectionMu.Lock()
|
|
defer buffer.selectionMu.Unlock()
|
|
|
|
start := *buffer.selectionStart
|
|
end := *buffer.selectionEnd
|
|
|
|
if end.Line < start.Line || (end.Line == start.Line && end.Col < start.Col) {
|
|
swap := end
|
|
end = start
|
|
start = swap
|
|
}
|
|
|
|
var text string
|
|
for y := start.Line; y <= end.Line; y++ {
|
|
if y >= uint64(len(buffer.lines)) {
|
|
break
|
|
}
|
|
line := buffer.lines[y]
|
|
startX := 0
|
|
endX := len(line.cells) - 1
|
|
if y == start.Line {
|
|
startX = int(start.Col)
|
|
}
|
|
if y == end.Line {
|
|
endX = int(end.Col)
|
|
}
|
|
if y > start.Line {
|
|
text += "\n"
|
|
}
|
|
for x := startX; x <= endX; x++ {
|
|
if x >= len(line.cells) {
|
|
break
|
|
}
|
|
mr := line.cells[x].Rune()
|
|
if mr.Width == 0 {
|
|
continue
|
|
}
|
|
x += mr.Width - 1
|
|
text += string(mr.Rune)
|
|
}
|
|
}
|
|
|
|
viewSelection := Selection{
|
|
Start: start,
|
|
End: end,
|
|
}
|
|
|
|
viewSelection.Start.Line = uint64(buffer.convertRawLineToViewLine(viewSelection.Start.Line))
|
|
viewSelection.End.Line = uint64(buffer.convertRawLineToViewLine(viewSelection.End.Line))
|
|
return text, &viewSelection
|
|
}
|
|
|
|
func (buffer *Buffer) InSelection(pos Position) bool {
|
|
|
|
if !buffer.fixSelection() {
|
|
return false
|
|
}
|
|
buffer.selectionMu.Lock()
|
|
defer buffer.selectionMu.Unlock()
|
|
|
|
start := *buffer.selectionStart
|
|
end := *buffer.selectionEnd
|
|
|
|
if end.Line < start.Line || (end.Line == start.Line && end.Col < start.Col) {
|
|
swap := end
|
|
end = start
|
|
start = swap
|
|
}
|
|
|
|
rY := buffer.convertViewLineToRawLine(uint16(pos.Line))
|
|
if rY < start.Line {
|
|
return false
|
|
}
|
|
if rY > end.Line {
|
|
return false
|
|
}
|
|
if rY == start.Line {
|
|
if pos.Col < start.Col {
|
|
return false
|
|
}
|
|
}
|
|
if rY == end.Line {
|
|
if pos.Col > end.Col {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (buffer *Buffer) GetHighlightAnnotation() *Annotation {
|
|
return buffer.highlightAnnotation
|
|
}
|
|
|
|
func (buffer *Buffer) GetViewHighlight() (start Position, end Position, exists bool) {
|
|
|
|
if buffer.highlightStart == nil || buffer.highlightEnd == nil {
|
|
return
|
|
}
|
|
|
|
if buffer.highlightStart.Line >= uint64(len(buffer.lines)) {
|
|
return
|
|
}
|
|
|
|
if buffer.highlightEnd.Line >= uint64(len(buffer.lines)) {
|
|
return
|
|
}
|
|
|
|
if buffer.highlightStart.Col >= uint16(len(buffer.lines[buffer.highlightStart.Line].cells)) {
|
|
return
|
|
}
|
|
|
|
if buffer.highlightEnd.Col >= uint16(len(buffer.lines[buffer.highlightEnd.Line].cells)) {
|
|
return
|
|
}
|
|
|
|
start = *buffer.highlightStart
|
|
end = *buffer.highlightEnd
|
|
|
|
if end.Line < start.Line || (end.Line == start.Line && end.Col < start.Col) {
|
|
swap := end
|
|
end = start
|
|
start = swap
|
|
}
|
|
|
|
start.Line = uint64(buffer.convertRawLineToViewLine(start.Line))
|
|
end.Line = uint64(buffer.convertRawLineToViewLine(end.Line))
|
|
|
|
return start, end, true
|
|
}
|