From d7028cee00b06e81086732aaa47dfdd7cf4c3a45 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Fri, 12 May 2017 07:54:42 +0100 Subject: [PATCH] Make TTYs implement io.ByteWriter and add support for TAB/BS chars --- kernel/driver/tty/tty.go | 1 + kernel/driver/tty/vt.go | 50 ++++++++++++++++++++++++++---------- kernel/driver/tty/vt_test.go | 22 ++++++++++++++-- 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/kernel/driver/tty/tty.go b/kernel/driver/tty/tty.go index 2f74a7c..f46ce2f 100644 --- a/kernel/driver/tty/tty.go +++ b/kernel/driver/tty/tty.go @@ -5,6 +5,7 @@ import "io" // Tty is implemented by objects that can register themselves as ttys. type Tty interface { io.Writer + io.ByteWriter // Position returns the current cursor position (x, y). Position() (uint16, uint16) diff --git a/kernel/driver/tty/vt.go b/kernel/driver/tty/vt.go index 8ecd2a5..d831bc1 100644 --- a/kernel/driver/tty/vt.go +++ b/kernel/driver/tty/vt.go @@ -5,6 +5,7 @@ import "github.com/achilleasa/gopher-os/kernel/driver/video/console" const ( defaultFg = console.LightGrey defaultBg = console.Black + tabWidth = 4 ) // Vt implements a simple terminal that can process LF and CR characters. The @@ -59,26 +60,47 @@ func (t *Vt) SetPosition(x, y uint16) { // Write implements io.Writer. func (t *Vt) Write(data []byte) (int, error) { - attr := t.curAttr for _, b := range data { - switch b { - case '\r': - t.cr() - case '\n': - t.cr() - t.lf() - default: - t.cons.Write(b, attr, t.curX, t.curY) - t.curX++ - if t.curX == t.width { - t.lf() - } - } + t.WriteByte(b) } return len(data), nil } +// Write implements io.ByteWriter. +func (t *Vt) WriteByte(b byte) error { + switch b { + case '\r': + t.cr() + case '\n': + t.cr() + t.lf() + case '\b': + if t.curX > 0 { + t.cons.Write(' ', t.curAttr, t.curX, t.curY) + t.curX-- + } + case '\t': + for i := 0; i < tabWidth; i++ { + t.cons.Write(' ', t.curAttr, t.curX, t.curY) + t.curX++ + if t.curX == t.width { + t.cr() + t.lf() + } + } + default: + t.cons.Write(b, t.curAttr, t.curX, t.curY) + t.curX++ + if t.curX == t.width { + t.cr() + t.lf() + } + } + + return nil +} + // cls clears the terminal. func (t *Vt) clear() { t.cons.Clear(0, 0, t.width, t.height) diff --git a/kernel/driver/tty/vt_test.go b/kernel/driver/tty/vt_test.go index 19233b0..844a81f 100644 --- a/kernel/driver/tty/vt_test.go +++ b/kernel/driver/tty/vt_test.go @@ -44,7 +44,12 @@ func TestWrite(t *testing.T) { vt.Clear() vt.SetPosition(0, 1) - vt.Write([]byte("12\n3\n4\r56")) + vt.Write([]byte("12\n\t3\n4\r567\b8")) + + // Tab spanning rows + vt.SetPosition(78, 4) + vt.WriteByte('\t') + vt.WriteByte('9') // Trigger scroll vt.SetPosition(79, 24) @@ -56,9 +61,22 @@ func TestWrite(t *testing.T) { }{ {0, 0, '1'}, {1, 0, '2'}, - {0, 1, '3'}, + // tabs + {0, 1, ' '}, + {1, 1, ' '}, + {2, 1, ' '}, + {3, 1, ' '}, + {4, 1, '3'}, + // tab spanning 2 rows + {78, 3, ' '}, + {79, 3, ' '}, + {0, 4, ' '}, + {1, 4, ' '}, + {2, 4, '9'}, + // {0, 2, '5'}, {1, 2, '6'}, + {2, 2, '8'}, // overwritten by BS {79, 23, '!'}, }