summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authordelthas <delthas@dille.cc>2022-06-04 12:05:11 +0200
committerdelthas <delthas@dille.cc>2022-06-04 12:05:11 +0200
commit6f0d19ecf5809d1604d6de9b1d8bcf279d678f4a (patch)
treea3a2c4d46346468f72741abddb4b407ae6616c16 /ui
parentFix crashing on removing last char of backsearch pattern (diff)
Reset history when flushing lines
Previously, when modifying a line in the history (and then possibly sending it), the history was modified, meaning that when looking up history lines again, instead of seeing a new line, the actual original line had been modified. With this patch, history is always kepy, and modifying a previous line and sending it will add this line to the history, and restore the previous history, after flushing the message.
Diffstat (limited to 'ui')
-rw-r--r--ui/editor.go59
1 files changed, 39 insertions, 20 deletions
diff --git a/ui/editor.go b/ui/editor.go
index 4892382..a63438d 100644
--- a/ui/editor.go
+++ b/ui/editor.go
@@ -16,6 +16,11 @@ type Editor struct {
// text contains the written runes. An empty slice means no text is written.
text [][]rune
+ // history contains the original content of each previously sent message.
+ // It gets out of sync with text when history is modified à la readline,
+ // then overwrites text when a new message is added.
+ history [][]rune
+
lineIdx int
// textWidth[i] contains the width of string(text[:i]). Therefore
@@ -40,7 +45,10 @@ type Editor struct {
backsearch bool
backsearchPattern []rune // pre-lowercased
- backsearchIdx int
+
+ // oldest (lowest) index in text of lines that were changed.
+ // used as an optimization to reduce copying when flushing lines.
+ oldestTextChange int
}
// NewEditor returns a new Editor.
@@ -48,6 +56,7 @@ type Editor struct {
func NewEditor(autoComplete func(cursorIdx int, text []rune) []Completion) Editor {
return Editor{
text: [][]rune{{}},
+ history: [][]rune{},
textWidth: []int{0},
autoComplete: autoComplete,
}
@@ -89,11 +98,7 @@ func (e *Editor) PutRune(r rune) {
wasEmpty := len(e.backsearchPattern) == 0
e.backsearchPattern = append(e.backsearchPattern, lowerRune)
if wasEmpty {
- clearLine := e.lineIdx == len(e.text)-1
e.backsearchUpdate(e.lineIdx - 1)
- if clearLine && e.lineIdx < len(e.text)-1 {
- e.text = e.text[:len(e.text)-1]
- }
} else {
e.backsearchUpdate(e.lineIdx)
}
@@ -104,6 +109,7 @@ func (e *Editor) putRune(r rune) {
e.text[e.lineIdx] = append(e.text[e.lineIdx], ' ')
copy(e.text[e.lineIdx][e.cursorIdx+1:], e.text[e.lineIdx][e.cursorIdx:])
e.text[e.lineIdx][e.cursorIdx] = r
+ e.bumpOldestChange()
rw := runeWidth(r)
tw := e.textWidth[len(e.textWidth)-1]
@@ -154,6 +160,8 @@ func (e *Editor) remRuneAt(idx int) {
copy(e.text[e.lineIdx][idx:], e.text[e.lineIdx][idx+1:])
e.text[e.lineIdx] = e.text[e.lineIdx][:len(e.text[e.lineIdx])-1]
+
+ e.bumpOldestChange()
}
func (e *Editor) RemWord() (ok bool) {
@@ -186,20 +194,29 @@ func (e *Editor) RemWord() (ok bool) {
return
}
-func (e *Editor) Flush() (content string) {
- content = string(e.text[e.lineIdx])
- if len(e.text[len(e.text)-1]) == 0 {
- e.lineIdx = len(e.text) - 1
- } else {
- e.lineIdx = len(e.text)
+func (e *Editor) Flush() string {
+ content := string(e.text[e.lineIdx])
+ if len(content) > 0 {
+ // intended []rune -> string -> []rune conversion to make copies
+ e.history = append(e.history, []rune(content))
+ }
+ for i, line := range e.history[e.oldestTextChange:] {
+ i := i + e.oldestTextChange
+ e.text[i] = append(e.text[i][:0], line...)
+ }
+ if len(content) > 0 {
e.text = append(e.text, []rune{})
+ } else {
+ e.text[len(e.text)-1] = []rune{}
}
+ e.lineIdx = len(e.text) - 1
e.textWidth = e.textWidth[:1]
e.cursorIdx = 0
e.offsetIdx = 0
e.autoCache = nil
e.backsearchEnd()
- return
+ e.oldestTextChange = len(e.text) - 1
+ return content
}
func (e *Editor) Clear() bool {
@@ -207,6 +224,7 @@ func (e *Editor) Clear() bool {
return false
}
e.text[e.lineIdx] = []rune{}
+ e.bumpOldestChange()
e.textWidth = e.textWidth[:1]
e.cursorIdx = 0
e.offsetIdx = 0
@@ -217,6 +235,7 @@ func (e *Editor) Clear() bool {
func (e *Editor) Set(text string) {
r := []rune(text)
e.text[e.lineIdx] = r
+ e.bumpOldestChange()
e.cursorIdx = len(r)
e.computeTextWidth()
e.offsetIdx = 0
@@ -335,9 +354,6 @@ func (e *Editor) Up() {
func (e *Editor) Down() {
if e.lineIdx == len(e.text)-1 {
- if len(e.text[e.lineIdx]) == 0 {
- return
- }
e.Flush()
return
}
@@ -363,6 +379,7 @@ func (e *Editor) AutoComplete(offset int) (ok bool) {
}
e.text[e.lineIdx] = e.autoCache[e.autoCacheIdx].Text
+ e.bumpOldestChange()
e.cursorIdx = e.autoCache[e.autoCacheIdx].CursorIdx
e.computeTextWidth()
if len(e.textWidth) <= e.offsetIdx {
@@ -377,16 +394,11 @@ func (e *Editor) AutoComplete(offset int) (ok bool) {
}
func (e *Editor) BackSearch() {
- clearLine := false
if !e.backsearch {
e.backsearch = true
e.backsearchPattern = []rune(strings.ToLower(string(e.text[e.lineIdx])))
- clearLine = e.lineIdx == len(e.text)-1
}
e.backsearchUpdate(e.lineIdx - 1)
- if clearLine && e.lineIdx < len(e.text)-1 {
- e.text = e.text[:len(e.text)-1]
- }
}
func (e *Editor) backsearchUpdate(start int) {
@@ -422,6 +434,13 @@ func (e *Editor) computeTextWidth() {
}
}
+// call this everytime e.text is modified
+func (e *Editor) bumpOldestChange() {
+ if e.oldestTextChange > e.lineIdx {
+ e.oldestTextChange = e.lineIdx
+ }
+}
+
func (e *Editor) Draw(screen tcell.Screen, x0, y int) {
st := tcell.StyleDefault