added Tab Stops support (#175)

This commit is contained in:
rrrooommmaaa 2019-01-27 14:56:23 +03:00 committed by Liam Galvin
parent 4e7b8b40e7
commit d2214b7915
5 changed files with 78 additions and 17 deletions

View File

@ -717,22 +717,11 @@ func (buffer *Buffer) CarriageReturn() {
}
func (buffer *Buffer) Tab() {
tabSize := 4
max := tabSize
// @todo rightMargin
if buffer.terminalState.cursorX < buffer.terminalState.viewWidth {
max = int(buffer.terminalState.viewWidth - buffer.terminalState.cursorX - 1)
}
shift := tabSize - (int(buffer.terminalState.cursorX+1) % tabSize)
if shift > max {
shift = max
}
for i := 0; i < shift; i++ {
for buffer.terminalState.cursorX < buffer.terminalState.viewWidth-1 { // @todo rightMargin
buffer.Write(' ')
if buffer.terminalState.IsTabSetAtCursor() {
break
}
}
}

View File

@ -26,8 +26,8 @@ func TestTabbing(t *testing.T) {
b.CarriageReturn()
b.NewLine()
expected := `
hello x goodbye
hell xxx good
hello x goodbye
hell xxx good
`
lines := b.GetVisibleLines()

View File

@ -15,6 +15,7 @@ type TerminalState struct {
LineFeedMode bool
AutoWrap bool
maxLines uint64
tabStops map[uint16]struct{}
}
// NewTerminalMode creates a new terminal state
@ -31,6 +32,7 @@ func NewTerminalState(viewCols uint16, viewLines uint16, attr CellAttributes, ma
topMargin: 0,
bottomMargin: uint(viewLines - 1),
}
b.TabReset()
return b
}
@ -47,3 +49,48 @@ func (terminalState *TerminalState) ResetVerticalMargins() {
func (terminalState *TerminalState) IsNewLineMode() bool {
return terminalState.LineFeedMode == false
}
func (terminalState *TerminalState) TabZonk() {
terminalState.tabStops = make(map[uint16]struct{})
}
func (terminalState *TerminalState) TabSet(index uint16) {
terminalState.tabStops[index] = struct{}{}
}
func (terminalState *TerminalState) TabClear(index uint16) {
delete(terminalState.tabStops, index)
}
func (terminalState *TerminalState) getTabIndexFromCursor() uint16 {
index := terminalState.cursorX
if index == terminalState.viewWidth {
index = 0
}
return index
}
func (terminalState *TerminalState) IsTabSetAtCursor() bool {
index := terminalState.getTabIndexFromCursor()
_, ok := terminalState.tabStops[index]
return ok
}
func (terminalState *TerminalState) TabClearAtCursor() {
terminalState.TabClear(terminalState.getTabIndexFromCursor())
}
func (terminalState *TerminalState) TabSetAtCursor() {
terminalState.TabSet(terminalState.getTabIndexFromCursor())
}
func (terminalState *TerminalState) TabReset() {
terminalState.TabZonk()
const MaxTabs uint16 = 1024
const TabStep = 4
var i uint16
for i < MaxTabs {
terminalState.TabSet(i)
i += TabStep
}
}

View File

@ -12,6 +12,7 @@ var ansiSequenceMap = map[rune]escapeSequenceHandler{
'8': restoreCursorHandler,
'D': indexHandler,
'E': nextLineHandler, // NEL
'H': tabSetHandler, // HTS
'M': reverseIndexHandler,
'P': sixelHandler,
'c': risHandler, //RIS
@ -75,3 +76,8 @@ func nextLineHandler(pty chan rune, terminal *Terminal) error {
terminal.ActiveBuffer().NewLineEx(true)
return nil
}
func tabSetHandler(pty chan rune, terminal *Terminal) error {
terminal.terminalState.TabSetAtCursor()
return nil
}

View File

@ -24,6 +24,7 @@ var csiSequences = []csiMapping{
{id: 'c', handler: csiSendDeviceAttributesHandler, description: " Send Device Attributes (Primary/Secondary/Tertiary DA)"},
{id: 'd', handler: csiLinePositionAbsolute, expectedParams: &expectedParams{min: 0, max: 1}, description: "Line Position Absolute [row] (default = [1,column]) (VPA)"},
{id: 'f', handler: csiCursorPositionHandler, description: "Horizontal and Vertical Position [row;column] (default = [1,1]) (HVP)"},
{id: 'g', handler: csiTabClearHandler, description: "Tab Clear (TBC)"},
{id: 'h', handler: csiSetModeHandler, expectedParams: &expectedParams{min: 1, max: 1}, description: "Set Mode (SM)"},
{id: 'l', handler: csiResetModeHandler, expectedParams: &expectedParams{min: 1, max: 1}, description: "Reset Mode (RM)"},
{id: 'm', handler: sgrSequenceHandler, description: "Character Attributes (SGR)"},
@ -463,6 +464,24 @@ func csiDeleteHandler(params []string, terminal *Terminal) error {
return nil
}
func csiTabClearHandler(params []string, terminal *Terminal) error {
n := "0"
if len(params) > 0 {
n = params[0]
}
switch n {
case "0", "":
terminal.terminalState.TabClearAtCursor()
case "3":
terminal.terminalState.TabZonk()
default:
return fmt.Errorf("Ignored TBC: CSI %s g", n)
}
return nil
}
// CSI Ps J
func csiEraseInDisplayHandler(params []string, terminal *Terminal) error {
n := "0"