feat: tx: started implementing cursor stuff.

This commit is contained in:
Andrey Parhomenko 2024-07-26 23:13:04 +05:00
parent 141d2a53be
commit 1e2d60b0d5
7 changed files with 145 additions and 4 deletions

View file

@ -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

View file

@ -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"
)

View file

@ -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)
} }

View file

View file

@ -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),
) )
} }
} }

View file

@ -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
) )

View file

@ -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)
}