Skip to content

Commit

Permalink
added Tab Stops support (#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
rrrooommmaaa authored and liamg committed Jan 27, 2019
1 parent 4e7b8b4 commit d2214b7
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 17 deletions.
19 changes: 4 additions & 15 deletions buffer/buffer.go
Expand Up @@ -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
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions buffer/buffer_test.go
Expand Up @@ -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()
Expand Down
47 changes: 47 additions & 0 deletions buffer/terminal_state.go
Expand Up @@ -15,6 +15,7 @@ type TerminalState struct {
LineFeedMode bool
AutoWrap bool
maxLines uint64
tabStops map[uint16]struct{}
}

// NewTerminalMode creates a new terminal state
Expand All @@ -31,6 +32,7 @@ func NewTerminalState(viewCols uint16, viewLines uint16, attr CellAttributes, ma
topMargin: 0,
bottomMargin: uint(viewLines - 1),
}
b.TabReset()
return b
}

Expand All @@ -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
}
}
6 changes: 6 additions & 0 deletions terminal/ansi.go
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
19 changes: 19 additions & 0 deletions terminal/csi.go
Expand Up @@ -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)"},
Expand Down Expand Up @@ -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"
Expand Down

0 comments on commit d2214b7

Please sign in to comment.