Added Alt-Backspace to text area. Also added a text area demo.

pull/759/head
Oliver 2 years ago
parent cecb44578c
commit 1ae26e1ab6

@ -0,0 +1 @@
![Screenshot](screenshot.png)

@ -0,0 +1,133 @@
// Demo code for the TextArea primitive.
package main
import (
"fmt"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
func main() {
app := tview.NewApplication()
textArea := tview.NewTextArea().
SetPlaceholder("Enter text here...")
textArea.SetTitle("Text Area").SetBorder(true)
helpInfo := tview.NewTextView().
SetText(" Press F1 for help, press Ctrl-C to exit")
position := tview.NewTextView().
SetDynamicColors(true).
SetTextAlign(tview.AlignRight)
pages := tview.NewPages()
updateInfos := func() {
fromRow, fromColumn, toRow, toColumn := textArea.GetCursor()
if fromRow == toRow && fromColumn == toColumn {
position.SetText(fmt.Sprintf("Row: [yellow]%d[white], Column: [yellow]%d ", fromRow, fromColumn))
} else {
position.SetText(fmt.Sprintf("[red]From[white] Row: [yellow]%d[white], Column: [yellow]%d[white] - [red]To[white] Row: [yellow]%d[white], To Column: [yellow]%d ", fromRow, fromColumn, toRow, toColumn))
}
}
textArea.SetMovedFunc(updateInfos)
updateInfos()
mainView := tview.NewGrid().
SetRows(0, 1).
AddItem(textArea, 0, 0, 1, 2, 0, 0, true).
AddItem(helpInfo, 1, 0, 1, 1, 0, 0, false).
AddItem(position, 1, 1, 1, 1, 0, 0, false)
help1 := tview.NewTextView().
SetDynamicColors(true).
SetText(`[green]Navigation
[yellow]Left arrow[white]: Move left.
[yellow]Right arrow[white]: Move right.
[yellow]Down arrow[white]: Move down.
[yellow]Up arrow[white]: Move up.
[yellow]Ctrl-A, Home[white]: Move to the beginning of the current line.
[yellow]Ctrl-E, End[white]: Move to the end of the current line.
[yellow]Ctrl-F, page down[white]: Move down by one page.
[yellow]Ctrl-B, page up[white]: Move up by one page.
[yellow]Alt-Up arrow[white]: Scroll the page up.
[yellow]Alt-Down arrow[white]: Scroll the page down.
[yellow]Alt-Left arrow[white]: Scroll the page to the left.
[yellow]Alt-Right arrow[white]: Scroll the page to the right.
[yellow]Alt-B, Ctrl-Left arrow[white]: Move back by one word.
[yellow]Alt-F, Ctrl-Right arrow[white]: Move forward by one word.
[blue]Press Enter for more help, press Escape to return.`)
help2 := tview.NewTextView().
SetDynamicColors(true).
SetText(`[green]Editing[white]
Type to enter text.
[yellow]Ctrl-H, Backspace[white]: Delete the left character.
[yellow]Ctrl-D, Delete[white]: Delete the right character.
[yellow]Ctrl-K[white]: Delete until the end of the line.
[yellow]Ctrl-W[white]: Delete the rest of the word.
[yellow]Ctrl-U[white]: Delete the current line.
[blue]Press Enter for more help, press Escape to return.`)
help3 := tview.NewTextView().
SetDynamicColors(true).
SetText(`[green]Selecting Text[white]
Move while holding Shift or drag the mouse.
Double-click to select a word.
[green]Clipboard
[yellow]Ctrl-Q[white]: Copy.
[yellow]Ctrl-X[white]: Cut.
[yellow]Ctrl-V[white]: Paste.
[green]Undo
[yellow]Ctrl-Z[white]: Undo.
[yellow]Ctrl-Y[white]: Redo.
[blue]Press Enter for more help, press Escape to return.`)
help := tview.NewFrame(help1).
SetBorders(1, 1, 0, 0, 2, 2)
help.SetBorder(true).
SetTitle("Help").
SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyEscape {
pages.SwitchToPage("main")
return nil
} else if event.Key() == tcell.KeyEnter {
switch {
case help.GetPrimitive() == help1:
help.SetPrimitive(help2)
case help.GetPrimitive() == help2:
help.SetPrimitive(help3)
case help.GetPrimitive() == help3:
help.SetPrimitive(help1)
}
return nil
}
return event
})
pages.AddAndSwitchToPage("main", mainView, true).
AddPage("help", tview.NewGrid().
SetColumns(0, 64, 0).
SetRows(0, 22, 0).
AddItem(help, 1, 1, 1, 1, 0, 0, true), true, false)
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyF1 {
pages.ShowPage("help") //TODO: Check when clicking outside help window with the mouse. Then clicking help again.
return nil
}
return event
})
if err := app.SetRoot(pages,
true).EnableMouse(true).Run(); err != nil {
panic(err)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

@ -27,6 +27,9 @@ type Frame struct {
// Border spacing.
top, bottom, header, footer, left, right int
// Keep a reference in case we need it when we change the primitive.
setFocus func(p Primitive)
}
// NewFrame returns a new frame around the given primitive. The primitive's
@ -52,7 +55,14 @@ func NewFrame(primitive Primitive) *Frame {
// SetPrimitive replaces the contained primitive with the given one. To remove
// a primitive, set it to nil.
func (f *Frame) SetPrimitive(p Primitive) *Frame {
var hasFocus bool
if f.primitive != nil {
hasFocus = f.primitive.HasFocus()
}
f.primitive = p
if hasFocus && f.setFocus != nil {
f.setFocus(p) // Restore focus.
}
return f
}
@ -157,6 +167,7 @@ func (f *Frame) Draw(screen tcell.Screen) {
// Focus is called when this primitive receives focus.
func (f *Frame) Focus(delegate func(p Primitive)) {
f.setFocus = delegate
if f.primitive != nil {
delegate(f.primitive)
} else {

@ -135,6 +135,7 @@ type textAreaUndoItem struct {
// - Ctrl-H, Backspace: Delete one character to the left of the cursor.
// - Ctrl-D, Delete: Delete the character under the cursor (or the first
// character on the next line if the cursor is at the end of a line).
// - Alt-Backspace: Delete the word to the left of the cursor.
// - Ctrl-K: Delete everything under and to the right of the cursor until the
// next newline character.
// - Ctrl-W: Delete from the start of the current word to the left of the
@ -1098,6 +1099,7 @@ func (t *TextArea) reset() {
t.truncateLines(0)
if t.wrap {
t.cursor.row = -1
t.selectionStart.row = -1
}
t.widestLine = 0
}
@ -1887,26 +1889,31 @@ func (t *TextArea) InputHandler() func(event *tcell.EventKey, setFocus func(p Pr
break
}
// Move the cursor back by one grapheme cluster.
endPos := t.cursor.pos
if t.cursor.actualColumn == 0 {
// Move to the end of the previous row.
if t.cursor.row > 0 {
t.moveCursor(t.cursor.row-1, -1)
beforeCursor := t.cursor
if event.Modifiers()&tcell.ModAlt == 0 {
// Move the cursor back by one grapheme cluster.
if t.cursor.actualColumn == 0 {
// Move to the end of the previous row.
if t.cursor.row > 0 {
t.moveCursor(t.cursor.row-1, -1)
}
} else {
// Move one grapheme cluster to the left.
t.moveCursor(t.cursor.row, t.cursor.actualColumn-1)
}
newLastAction = taActionBackspace
} else {
// Move one grapheme cluster to the left.
t.moveCursor(t.cursor.row, t.cursor.actualColumn-1)
// Move the cursor back by one word.
t.moveWordLeft(false)
}
// Remove that last grapheme cluster.
if t.cursor.pos != endPos {
t.cursor.pos = t.replace(t.cursor.pos, endPos, "", t.lastAction == taActionBackspace) // Delete the character.
t.cursor.pos[2] = endPos[2]
if t.cursor.pos != beforeCursor.pos {
t.cursor, beforeCursor = beforeCursor, t.cursor // So we put the right position on the stack.
t.cursor.pos = t.replace(beforeCursor.pos, t.cursor.pos, "", t.lastAction == taActionBackspace) // Delete the character.
t.cursor.row = -1
t.truncateLines(t.cursor.row - 1)
t.findCursor(true, t.cursor.row-1)
newLastAction = taActionBackspace
t.truncateLines(beforeCursor.row - 1)
t.findCursor(true, beforeCursor.row-1)
}
t.selectionStart = t.cursor
case tcell.KeyDelete, tcell.KeyCtrlD: // Delete forward.
@ -2002,7 +2009,7 @@ func (t *TextArea) InputHandler() func(event *tcell.EventKey, setFocus func(p Pr
t.spans[undo.originalBefore], t.spans[undo.before] = t.spans[undo.before], t.spans[undo.originalBefore]
t.spans[undo.originalAfter], t.spans[undo.after] = t.spans[undo.after], t.spans[undo.originalAfter]
t.cursor.pos, t.undoStack[t.nextUndo].pos = undo.pos, t.cursor.pos
t.length = undo.length
t.length, t.undoStack[t.nextUndo].length = undo.length, t.length
if !undo.continuation {
break
}
@ -2023,7 +2030,7 @@ func (t *TextArea) InputHandler() func(event *tcell.EventKey, setFocus func(p Pr
t.spans[undo.originalBefore], t.spans[undo.before] = t.spans[undo.before], t.spans[undo.originalBefore]
t.spans[undo.originalAfter], t.spans[undo.after] = t.spans[undo.after], t.spans[undo.originalAfter]
t.cursor.pos, t.undoStack[t.nextUndo].pos = undo.pos, t.cursor.pos
t.length = undo.length
t.length, t.undoStack[t.nextUndo].length = undo.length, t.length
t.nextUndo++
if t.nextUndo < len(t.undoStack) && !t.undoStack[t.nextUndo].continuation {
break
@ -2040,7 +2047,7 @@ func (t *TextArea) InputHandler() func(event *tcell.EventKey, setFocus func(p Pr
})
}
// THIS FUNCTION WILL BE REMOVED ONCE WE DEEM THE TEXT AREA STABLE!
// THIS FUNCTION WILL BE REMOVED ONCE WE DEEM THE TEXT AREA STABLE! DO NOT USE!
func (t *TextArea) Dump() string {
var buf strings.Builder

Loading…
Cancel
Save