mirror of https://github.com/liamg/aminal.git
Vttest 2 (#190)
* added Tab Stops support * added support for Screen Mode (DECSCNM) -- reverse colors * bug fix: cursor rendition in Origin Mode * bug fix: SGR parameters handling * Save/Restore Cursor updates. Partial charset implementation.
This commit is contained in:
parent
aad680440d
commit
0c7499bf7e
|
@ -14,11 +14,14 @@ type Buffer struct {
|
||||||
displayChangeHandlers []chan bool
|
displayChangeHandlers []chan bool
|
||||||
savedX uint16
|
savedX uint16
|
||||||
savedY uint16
|
savedY uint16
|
||||||
|
savedCursorAttr *CellAttributes
|
||||||
dirty bool
|
dirty bool
|
||||||
selectionStart *Position
|
selectionStart *Position
|
||||||
selectionEnd *Position
|
selectionEnd *Position
|
||||||
selectionComplete bool // whether the selected text can update or whether it is final
|
selectionComplete bool // whether the selected text can update or whether it is final
|
||||||
terminalState *TerminalState
|
terminalState *TerminalState
|
||||||
|
savedCharsets []*map[rune]rune
|
||||||
|
savedCurrentCharset int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Position struct {
|
type Position struct {
|
||||||
|
@ -355,13 +358,27 @@ func (buffer *Buffer) ScrollToEnd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (buffer *Buffer) SaveCursor() {
|
func (buffer *Buffer) SaveCursor() {
|
||||||
|
copiedAttr := buffer.terminalState.CursorAttr
|
||||||
|
buffer.savedCursorAttr = &copiedAttr
|
||||||
buffer.savedX = buffer.terminalState.cursorX
|
buffer.savedX = buffer.terminalState.cursorX
|
||||||
buffer.savedY = buffer.terminalState.cursorY
|
buffer.savedY = buffer.terminalState.cursorY
|
||||||
|
buffer.savedCharsets = make([]*map[rune]rune, len(buffer.terminalState.Charsets))
|
||||||
|
copy(buffer.savedCharsets, buffer.terminalState.Charsets)
|
||||||
|
buffer.savedCurrentCharset = buffer.terminalState.CurrentCharset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (buffer *Buffer) RestoreCursor() {
|
func (buffer *Buffer) RestoreCursor() {
|
||||||
|
if buffer.savedCursorAttr != nil {
|
||||||
|
copiedAttr := *buffer.savedCursorAttr
|
||||||
|
buffer.terminalState.CursorAttr = copiedAttr // @todo ignore colors?
|
||||||
|
}
|
||||||
buffer.terminalState.cursorX = buffer.savedX
|
buffer.terminalState.cursorX = buffer.savedX
|
||||||
buffer.terminalState.cursorY = buffer.savedY
|
buffer.terminalState.cursorY = buffer.savedY
|
||||||
|
if buffer.savedCharsets != nil {
|
||||||
|
buffer.terminalState.Charsets = make([]*map[rune]rune, len(buffer.savedCharsets))
|
||||||
|
copy(buffer.terminalState.Charsets, buffer.savedCharsets)
|
||||||
|
buffer.terminalState.CurrentCharset = buffer.savedCurrentCharset
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (buffer *Buffer) CursorAttr() *CellAttributes {
|
func (buffer *Buffer) CursorAttr() *CellAttributes {
|
||||||
|
|
|
@ -16,6 +16,8 @@ type TerminalState struct {
|
||||||
AutoWrap bool
|
AutoWrap bool
|
||||||
maxLines uint64
|
maxLines uint64
|
||||||
tabStops map[uint16]struct{}
|
tabStops map[uint16]struct{}
|
||||||
|
Charsets []*map[rune]rune // array of 2 charsets, nil means ASCII (no conversion)
|
||||||
|
CurrentCharset int // active charset index in Charsets array, valid values are 0 or 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTerminalMode creates a new terminal state
|
// NewTerminalMode creates a new terminal state
|
||||||
|
@ -30,6 +32,7 @@ func NewTerminalState(viewCols uint16, viewLines uint16, attr CellAttributes, ma
|
||||||
viewHeight: viewLines,
|
viewHeight: viewLines,
|
||||||
topMargin: 0,
|
topMargin: 0,
|
||||||
bottomMargin: uint(viewLines - 1),
|
bottomMargin: uint(viewLines - 1),
|
||||||
|
Charsets: []*map[rune]rune{nil, nil},
|
||||||
LineFeedMode: true,
|
LineFeedMode: true,
|
||||||
}
|
}
|
||||||
b.TabReset()
|
b.TabReset()
|
||||||
|
|
|
@ -17,8 +17,8 @@ var ansiSequenceMap = map[rune]escapeSequenceHandler{
|
||||||
'P': sixelHandler,
|
'P': sixelHandler,
|
||||||
'c': risHandler, //RIS
|
'c': risHandler, //RIS
|
||||||
'#': screenStateHandler,
|
'#': screenStateHandler,
|
||||||
'(': swallowHandler(1), // character set bullshit
|
'(': scs0Handler, // select character set into G0
|
||||||
')': swallowHandler(1), // character set bullshit
|
')': scs1Handler, // select character set into G1
|
||||||
'*': swallowHandler(1), // character set bullshit
|
'*': swallowHandler(1), // character set bullshit
|
||||||
'+': swallowHandler(1), // character set bullshit
|
'+': swallowHandler(1), // character set bullshit
|
||||||
'>': swallowHandler(0), // numeric char selection //@todo
|
'>': swallowHandler(0), // numeric char selection //@todo
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
package terminal
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
var charSets = map[rune]*map[rune]rune{
|
||||||
|
'0': &decSpecGraphics,
|
||||||
|
'B': nil, // ASCII
|
||||||
|
// @todo 1,2,A
|
||||||
|
}
|
||||||
|
|
||||||
|
var decSpecGraphics = map[rune]rune{
|
||||||
|
0x5f: 0x00A0, // NO-BREAK SPACE
|
||||||
|
0x60: 0x25C6, // BLACK DIAMOND
|
||||||
|
0x61: 0x2592, // MEDIUM SHADE
|
||||||
|
0x62: 0x2409, // SYMBOL FOR HORIZONTAL TABULATION
|
||||||
|
0x63: 0x240C, // SYMBOL FOR FORM FEED
|
||||||
|
0x64: 0x240D, // SYMBOL FOR CARRIAGE RETURN
|
||||||
|
0x65: 0x240A, // SYMBOL FOR LINE FEED
|
||||||
|
0x66: 0x00B0, // DEGREE SIGN
|
||||||
|
0x67: 0x00B1, // PLUS-MINUS SIGN
|
||||||
|
0x68: 0x2424, // SYMBOL FOR NEWLINE
|
||||||
|
0x69: 0x240B, // SYMBOL FOR VERTICAL TABULATION
|
||||||
|
0x6a: 0x2518, // BOX DRAWINGS LIGHT UP AND LEFT
|
||||||
|
0x6b: 0x2510, // BOX DRAWINGS LIGHT DOWN AND LEFT
|
||||||
|
0x6c: 0x250C, // BOX DRAWINGS LIGHT DOWN AND RIGHT
|
||||||
|
0x6d: 0x2514, // BOX DRAWINGS LIGHT UP AND RIGHT
|
||||||
|
0x6e: 0x253C, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
|
||||||
|
0x6f: 0x23BA, // HORIZONTAL SCAN LINE-1
|
||||||
|
0x70: 0x23BB, // HORIZONTAL SCAN LINE-3
|
||||||
|
0x71: 0x2500, // BOX DRAWINGS LIGHT HORIZONTAL
|
||||||
|
0x72: 0x23BC, // HORIZONTAL SCAN LINE-7
|
||||||
|
0x73: 0x23BD, // HORIZONTAL SCAN LINE-9
|
||||||
|
0x74: 0x251C, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
|
||||||
|
0x75: 0x2524, // BOX DRAWINGS LIGHT VERTICAL AND LEFT
|
||||||
|
0x76: 0x2534, // BOX DRAWINGS LIGHT UP AND HORIZONTAL
|
||||||
|
0x77: 0x252C, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
|
||||||
|
0x78: 0x2502, // BOX DRAWINGS LIGHT VERTICAL
|
||||||
|
0x79: 0x2264, // LESS-THAN OR EQUAL TO
|
||||||
|
0x7a: 0x2265, // GREATER-THAN OR EQUAL TO
|
||||||
|
0x7b: 0x03C0, // GREEK SMALL LETTER PI
|
||||||
|
0x7c: 0x2260, // NOT EQUAL TO
|
||||||
|
0x7d: 0x00A3, // POUND SIGN
|
||||||
|
0x7e: 0x00B7, // MIDDLE DOT
|
||||||
|
}
|
||||||
|
|
||||||
|
func scs0Handler(pty chan rune, terminal *Terminal) error {
|
||||||
|
return scsHandler(pty, terminal, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func scs1Handler(pty chan rune, terminal *Terminal) error {
|
||||||
|
return scsHandler(pty, terminal, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func scsHandler(pty chan rune, terminal *Terminal, which int) error {
|
||||||
|
b := <-pty
|
||||||
|
|
||||||
|
cs, ok := charSets[b]
|
||||||
|
if ok {
|
||||||
|
terminal.logger.Debugf("Selected charset %v into G%v", string(b), which)
|
||||||
|
terminal.terminalState.Charsets[which] = cs
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
terminal.terminalState.Charsets[which] = nil
|
||||||
|
return fmt.Errorf("Unknown SCS charset code: 0x%02X [%v]", b, string(b))
|
||||||
|
}
|
|
@ -61,12 +61,14 @@ func enqHandler(terminal *Terminal) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func shiftOutHandler(terminal *Terminal) error {
|
func shiftOutHandler(terminal *Terminal) error {
|
||||||
terminal.logger.Errorf("Received shift out")
|
terminal.logger.Debugf("Received shift out")
|
||||||
|
terminal.terminalState.CurrentCharset = 1
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func shiftInHandler(terminal *Terminal) error {
|
func shiftInHandler(terminal *Terminal) error {
|
||||||
terminal.logger.Errorf("Received shift in")
|
terminal.logger.Debugf("Received shift in")
|
||||||
|
terminal.terminalState.CurrentCharset = 0
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,10 +81,22 @@ func (terminal *Terminal) processRune(b rune) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//terminal.logger.Debugf("Received character 0x%X: %q", b, string(b))
|
//terminal.logger.Debugf("Received character 0x%X: %q", b, string(b))
|
||||||
terminal.ActiveBuffer().Write(b)
|
terminal.ActiveBuffer().Write(terminal.translateRune(b))
|
||||||
terminal.isDirty = true
|
terminal.isDirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (terminal *Terminal) translateRune(b rune) rune {
|
||||||
|
table := terminal.terminalState.Charsets[terminal.terminalState.CurrentCharset]
|
||||||
|
if table == nil {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
chr, ok := (*table)[b]
|
||||||
|
if ok {
|
||||||
|
return chr
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
func (terminal *Terminal) processInput(pty chan rune) {
|
func (terminal *Terminal) processInput(pty chan rune) {
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/ANSI_escape_code
|
// https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||||
|
|
|
@ -20,7 +20,7 @@ func sgrSequenceHandler(params []string, terminal *Terminal) error {
|
||||||
p := strings.Replace(strings.Replace(params[i], "[", "", -1), "]", "", -1)
|
p := strings.Replace(strings.Replace(params[i], "[", "", -1), "]", "", -1)
|
||||||
|
|
||||||
switch p {
|
switch p {
|
||||||
case "00", "0":
|
case "00", "0", "":
|
||||||
attr := terminal.ActiveBuffer().CursorAttr()
|
attr := terminal.ActiveBuffer().CursorAttr()
|
||||||
*attr = buffer.CellAttributes{
|
*attr = buffer.CellAttributes{
|
||||||
FgColour: terminal.config.ColourScheme.Foreground,
|
FgColour: terminal.config.ColourScheme.Foreground,
|
||||||
|
|
Loading…
Reference in New Issue