feat: tx: started implementing cursor stuff.
This commit is contained in:
parent
141d2a53be
commit
1e2d60b0d5
7 changed files with 145 additions and 4 deletions
|
@ -14,6 +14,7 @@ func (effects Effects) Format() string {
|
||||||
return strings.Join(intStrs, ";")
|
return strings.Join(intStrs, ";")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Effect codes.
|
||||||
const (
|
const (
|
||||||
EffectReset Effect = iota
|
EffectReset Effect = iota
|
||||||
EffectBold
|
EffectBold
|
||||||
|
@ -23,6 +24,7 @@ const (
|
||||||
EffectBlinking
|
EffectBlinking
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Keep effect codes.
|
||||||
const (
|
const (
|
||||||
EffectInverse Effect = 7 + iota
|
EffectInverse Effect = 7 + iota
|
||||||
EffectHidden
|
EffectHidden
|
||||||
|
@ -30,6 +32,7 @@ const (
|
||||||
EffectStirke
|
EffectStirke
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Foreground effect codes.
|
||||||
const (
|
const (
|
||||||
EffectBlackFG = 30 + iota
|
EffectBlackFG = 30 + iota
|
||||||
EffectRedFG
|
EffectRedFG
|
||||||
|
@ -42,6 +45,7 @@ const (
|
||||||
EffectDefaultFG
|
EffectDefaultFG
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Background effect codes.
|
||||||
const (
|
const (
|
||||||
EffectBlackBG Effect = 40 + iota
|
EffectBlackBG Effect = 40 + iota
|
||||||
EffectRedBG
|
EffectRedBG
|
||||||
|
|
60
aes/es.go
60
aes/es.go
|
@ -1,5 +1,9 @@
|
||||||
package aes
|
package aes
|
||||||
|
|
||||||
|
const (
|
||||||
|
KeyESC = '\x1B'
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Start.
|
// Start.
|
||||||
ESC = "\x1B"
|
ESC = "\x1B"
|
||||||
|
@ -14,6 +18,7 @@ const (
|
||||||
OSC = ESC+"]"
|
OSC = ESC+"]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Special control sequences.
|
||||||
const (
|
const (
|
||||||
BEL = "\a"
|
BEL = "\a"
|
||||||
BS = "\b"
|
BS = "\b"
|
||||||
|
@ -25,3 +30,58 @@ const (
|
||||||
DEL = "\x7F"
|
DEL = "\x7F"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Erasing control sequences.
|
||||||
|
// Names are self describing.
|
||||||
|
const (
|
||||||
|
EraseInDisplay = CSI+"J"
|
||||||
|
EraseFromCursorToEndOfScreen = CSI+"0J"
|
||||||
|
EraseFromCursorToBeginOfScreen = CSI+"1J"
|
||||||
|
EraseEntireScreen = CSI+"2J"
|
||||||
|
EraseSavedLines = CSI+"3J"
|
||||||
|
EraseInLine = CSI+"K"
|
||||||
|
EraseFromCursorToEndOfLine = CSI+"0K"
|
||||||
|
EraseFromStartOfLineToCursor = CSI+"1K"
|
||||||
|
EraseEntireLine = CSI+"2K"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cursor control sequences.
|
||||||
|
// Any that ends with the "Format" means that
|
||||||
|
// the format is meant to be used via fmt.Sprintf
|
||||||
|
// or any fitting function to provide arguments
|
||||||
|
// into the escape code.
|
||||||
|
const (
|
||||||
|
MoveCursorHome = CSI+"H"
|
||||||
|
|
||||||
|
// Line, column (both int).
|
||||||
|
MoveCursorToFormat = CSI+"%d;%dH"
|
||||||
|
SecondaryMoveCursorToFormat = CSI+"%d;%df"
|
||||||
|
MoveCursorUpFormat = CSI+"%dA"
|
||||||
|
MoveCursorDownFormat = CSI+"%dB"
|
||||||
|
MoveCursorRightFormat = CSI+"%dC"
|
||||||
|
MoveCursorLeftFormat = CSI+"%dD"
|
||||||
|
MoveCursorToBeginOfNextLineDownFormat = CSI+"%dE"
|
||||||
|
MoveCursorToBeginOfPrevLineUpFormat = CSI+"%dF"
|
||||||
|
MoveCursorToColumnFormat = CSI+"%dG"
|
||||||
|
|
||||||
|
RequestCursorPositionReportFormat =CSI+"%d;%dR"
|
||||||
|
RequestCursorPosition = CSI+"6n"
|
||||||
|
|
||||||
|
SaveCursorPositionDEC = ESC+" 7"
|
||||||
|
UnodCursorPositionDEC = ESC+" 8"
|
||||||
|
|
||||||
|
SaveCursorPositionSCO = CSI+"s"
|
||||||
|
UndoCursorPositionSCO = CSI+"u"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Common private modes.
|
||||||
|
const (
|
||||||
|
MakeCursorInvisible = CSI+"?25l"
|
||||||
|
MakeCursorVisible = CSI+"?25h"
|
||||||
|
|
||||||
|
UndoScreen = CSI+"?47l"
|
||||||
|
SaveScreen = CSI+"?47h"
|
||||||
|
|
||||||
|
EnableAltBuffer = CSI+"?1049h"
|
||||||
|
DisableAltBuffer = CSI+"?1049l"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package aes
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
|
// The type implements more or less
|
||||||
type EffectText struct {
|
type EffectText struct {
|
||||||
Effects Effects
|
Effects Effects
|
||||||
Text string
|
Text string
|
||||||
|
@ -13,17 +14,24 @@ func (et EffectText) String() string {
|
||||||
et.Effects.Format(), et.Text,
|
et.Effects.Format(), et.Text,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create new EffectText with formatted
|
||||||
|
// by the fmt.Sprintf string as text data.
|
||||||
func ETF(format string, v ...any) EffectText {
|
func ETF(format string, v ...any) EffectText {
|
||||||
ret := EffectText{}
|
ret := EffectText{}
|
||||||
ret.Text = fmt.Sprintf(format, v...)
|
ret.Text = fmt.Sprintf(format, v...)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the new EffectText with specified
|
||||||
|
// effects appended.
|
||||||
func (et EffectText) With(effects ...Effect) EffectText {
|
func (et EffectText) With(effects ...Effect) EffectText {
|
||||||
et.Effects = append(et.Effects, effects...)
|
et.Effects = append(et.Effects, effects...)
|
||||||
return et
|
return et
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the bold effect and return
|
||||||
|
// the resulting EffectText.
|
||||||
func (et EffectText) Bold() EffectText {
|
func (et EffectText) Bold() EffectText {
|
||||||
return et.With(EffectBold)
|
return et.With(EffectBold)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,14 @@ import "surdeus.su/core/cli/aes"
|
||||||
//import "fmt"
|
//import "fmt"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
normalMode := true
|
||||||
term, err := tx.NewTerminal(os.Stdin)
|
term, err := tx.NewTerminal(os.Stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Some not terminal handling.
|
// Some not terminal handling.
|
||||||
log.Fatal("tx.NewTerminal(...): %s\n", err)
|
log.Fatal("tx.NewTerminal(...): %s\n", err)
|
||||||
}
|
}
|
||||||
term.MakeRaw()
|
term.MakeRaw()
|
||||||
|
term.EnableAltBuffer()
|
||||||
defer term.Restore()
|
defer term.Restore()
|
||||||
|
|
||||||
w, h, err := term.GetSize()
|
w, h, err := term.GetSize()
|
||||||
|
@ -24,17 +26,45 @@ func main() {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
key, _, err := term.ReadKey()
|
key, _, err := term.ReadKey()
|
||||||
|
|
||||||
|
if key == tx.KeyControlC {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !normalMode && key == tx.KeyESC {
|
||||||
|
normalMode = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if normalMode { switch key {
|
||||||
|
case 'j':
|
||||||
|
term.MoveCursorDown(1)
|
||||||
|
case 'k':
|
||||||
|
term.MoveCursorUp(1)
|
||||||
|
case 'h':
|
||||||
|
term.MoveCursorLeft(1)
|
||||||
|
case 'l' :
|
||||||
|
term.MoveCursorRight(1)
|
||||||
|
case tx.KeyESC :
|
||||||
|
case 'i' :
|
||||||
|
normalMode = false
|
||||||
|
}
|
||||||
|
continue }
|
||||||
|
|
||||||
|
if key == tx.KeyEnter {
|
||||||
|
term.NextLine(1)
|
||||||
|
//term.Print("enter")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
log.Fatalf("term.ReadLine(...): %s\n", err)
|
log.Fatalf("term.ReadLine(...): %s\n", err)
|
||||||
}
|
}
|
||||||
if key == tx.KeyControlC {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
term.Print(
|
term.Print(
|
||||||
"shit:", aes.ETF("%q", key).Bold().With(aes.EffectRedFG), "\r\n",
|
aes.ETF("%s", string(key)).
|
||||||
|
Bold().
|
||||||
|
With(aes.EffectRedFG),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
package tx
|
package tx
|
||||||
|
|
||||||
|
import "surdeus.su/core/cli/aes"
|
||||||
|
|
||||||
type Key rune
|
type Key rune
|
||||||
|
|
||||||
const (
|
const (
|
||||||
KeyControlC Key = '\x03'
|
KeyControlC Key = '\x03'
|
||||||
|
KeyESC = aes.KeyESC
|
||||||
|
KeyReturn = '\r'
|
||||||
|
KeyEnter = KeyReturn
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
34
tx/term.go
34
tx/term.go
|
@ -1,6 +1,7 @@
|
||||||
package tx
|
package tx
|
||||||
|
|
||||||
import "golang.org/x/term"
|
import "golang.org/x/term"
|
||||||
|
import "surdeus.su/core/cli/aes"
|
||||||
import "bufio"
|
import "bufio"
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "os"
|
import "os"
|
||||||
|
@ -43,6 +44,7 @@ func (t *Terminal) MakeRaw() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) Restore() error {
|
func (t *Terminal) Restore() error {
|
||||||
|
t.DisableAltBuffer()
|
||||||
if t == nil || t.prevState == nil {
|
if t == nil || t.prevState == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -83,3 +85,35 @@ func (t *Terminal) Print(v ...any) (int, error) {
|
||||||
str := fmt.Sprint(v...)
|
str := fmt.Sprint(v...)
|
||||||
return t.Write([]byte(str))
|
return t.Write([]byte(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) MoveCursorRight(n int) {
|
||||||
|
t.Printf(aes.MoveCursorRightFormat, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) MoveCursorLeft(n int) {
|
||||||
|
t.Printf(aes.MoveCursorLeftFormat, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) MoveCursorUp(n int) {
|
||||||
|
t.Printf(aes.MoveCursorUpFormat, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) MoveCursorDown(n int) {
|
||||||
|
t.Printf(aes.MoveCursorDownFormat, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) NextLine(n int) {
|
||||||
|
t.Printf(
|
||||||
|
aes.MoveCursorToBeginOfNextLineDownFormat,
|
||||||
|
n,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) EnableAltBuffer() {
|
||||||
|
t.Printf("%s", aes.EnableAltBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) DisableAltBuffer() {
|
||||||
|
t.Printf("%s", aes.DisableAltBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue