diff --git a/buffer/buffer.go b/buffer/buffer.go index 23a90ec..8fa1424 100644 --- a/buffer/buffer.go +++ b/buffer/buffer.go @@ -200,6 +200,9 @@ func (buffer *Buffer) ViewHeight() uint16 { } func (buffer *Buffer) insertLine() { + + defer buffer.emitDisplayChange() + if !buffer.InScrollableRegion() { pos := buffer.RawLine() out := make([]Line, len(buffer.lines)+1) @@ -251,6 +254,8 @@ func (buffer *Buffer) Index() { // This sequence causes the active position to move downward one line without changing the column position. // If the active position is at the bottom margin, a scroll up is performed." + defer buffer.emitDisplayChange() + if buffer.InScrollableRegion() { if uint(buffer.cursorY) < buffer.bottomMargin { @@ -277,6 +282,9 @@ func (buffer *Buffer) Index() { } func (buffer *Buffer) ReverseIndex() { + + defer buffer.emitDisplayChange() + if buffer.InScrollableRegion() { if uint(buffer.cursorY) > buffer.topMargin { diff --git a/config.go b/config.go new file mode 100644 index 0000000..86a4bac --- /dev/null +++ b/config.go @@ -0,0 +1,58 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + + "github.com/liamg/aminal/config" +) + +func getConfig() *config.Config { + ignore := false + flag.BoolVar(&ignore, "ignore-config", ignore, "Ignore user config files and use defauls") + if ignore { + return &config.DefaultConfig + } + + conf := loadConfigFile() + + flag.BoolVar(&conf.DebugMode, "debug", conf.DebugMode, "Enable debug logging") + flag.BoolVar(&conf.Slomo, "slomo", conf.Slomo, "Render in slow motion (useful for debugging)") + flag.BoolVar(&conf.Rendering.AlwaysRepaint, "always-repaint", conf.Rendering.AlwaysRepaint, "Always repaint the window, even when no changes have occurred") + + flag.Parse() + return conf +} + +func loadConfigFile() *config.Config { + + home := os.Getenv("HOME") + if home == "" { + return &config.DefaultConfig + } + + places := []string{ + fmt.Sprintf("%s/.aminal.toml", home), + } + + for _, place := range places { + if b, err := ioutil.ReadFile(place); err == nil { + if c, err := config.Parse(b); err == nil { + return c + } + + fmt.Printf("Invalid config at %s: %s\n", place, err) + } + } + + if b, err := config.DefaultConfig.Encode(); err != nil { + fmt.Printf("Failed to encode config file: %s\n", err) + } else { + if err := ioutil.WriteFile(fmt.Sprintf("%s/.aminal.toml", home), b, 0644); err != nil { + fmt.Printf("Failed to encode config file: %s\n", err) + } + } + return &config.DefaultConfig +} diff --git a/logger.go b/logger.go new file mode 100644 index 0000000..aa9b6eb --- /dev/null +++ b/logger.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + + "github.com/liamg/aminal/config" + "go.uber.org/zap" +) + +func getLogger(conf *config.Config) (*zap.SugaredLogger, error) { + + var logger *zap.Logger + var err error + if conf.DebugMode { + logger, err = zap.NewDevelopment() + } else { + loggerConfig := zap.NewProductionConfig() + loggerConfig.Encoding = "console" + logger, err = loggerConfig.Build() + } + if err != nil { + return nil, fmt.Errorf("Failed to create logger: %s", err) + } + return logger.Sugar(), nil +} diff --git a/main.go b/main.go index 8531b07..15501f9 100644 --- a/main.go +++ b/main.go @@ -1,93 +1,20 @@ package main import ( - "flag" "fmt" - "io/ioutil" "os" "os/exec" "syscall" "github.com/kr/pty" - "github.com/liamg/aminal/config" "github.com/liamg/aminal/gui" "github.com/liamg/aminal/terminal" "github.com/riywo/loginshell" - "go.uber.org/zap" ) -func getConfig() *config.Config { - ignore := false - flag.BoolVar(&ignore, "ignore-config", ignore, "Ignore user config files and use defauls") - if ignore { - return &config.DefaultConfig - } - - conf := loadConfigFile() - - flag.BoolVar(&conf.DebugMode, "debug", conf.DebugMode, "Enable debug logging") - flag.BoolVar(&conf.Slomo, "slomo", conf.Slomo, "Render in slow motion (useful for debugging)") - flag.BoolVar(&conf.Rendering.AlwaysRepaint, "always-repaint", conf.Rendering.AlwaysRepaint, "Always repaint the window, even when no changes have occurred") - - flag.Parse() - return conf -} - -func loadConfigFile() *config.Config { - - home := os.Getenv("HOME") - if home == "" { - return &config.DefaultConfig - } - - places := []string{ - fmt.Sprintf("%s/.aminal.toml", home), - } - - for _, place := range places { - if b, err := ioutil.ReadFile(place); err == nil { - if c, err := config.Parse(b); err == nil { - return c - } else { - fmt.Printf("Invalid config at %s: %s\n", place, err) - } - } - } - - if b, err := config.DefaultConfig.Encode(); err != nil { - fmt.Printf("Failed to encode config file: %s\n", err) - } else { - if err := ioutil.WriteFile(fmt.Sprintf("%s/.aminal.toml", home), b, 0644); err != nil { - fmt.Printf("Failed to encode config file: %s\n", err) - } - } - return &config.DefaultConfig -} - -func getLogger(conf *config.Config) (*zap.SugaredLogger, error) { - - var logger *zap.Logger - var err error - if conf.DebugMode { - logger, err = zap.NewDevelopment() - } else { - loggerConfig := zap.NewProductionConfig() - loggerConfig.Encoding = "console" - logger, err = loggerConfig.Build() - } - if err != nil { - return nil, fmt.Errorf("Failed to create logger: %s", err) - } - return logger.Sugar(), nil -} - func main() { - // parse this conf := getConfig() - - os.Setenv("TERM", "xterm-256color") // contraversial! easier than installing terminfo everywhere, but obviously going to be slightly different to xterm functionality, so we'll see... - logger, err := getLogger(conf) if err != nil { fmt.Printf("Failed to create logger: %s\n", err) @@ -106,6 +33,9 @@ func main() { logger.Fatalf("Failed to ascertain your shell: %s", err) } + os.Setenv("TERM", "xterm-256color") // contraversial! easier than installing terminfo everywhere, but obviously going to be slightly different to xterm functionality, so we'll see... + os.Setenv("COLORTERM", "truecolor") + shell := exec.Command(shellStr) shell.Stdout = tty shell.Stdin = tty diff --git a/pty/pty.go b/pty/pty.go deleted file mode 100644 index 2fbe747..0000000 --- a/pty/pty.go +++ /dev/null @@ -1,34 +0,0 @@ -package pty - -import ( - "fmt" - "os" - "os/exec" - "syscall" - - "github.com/riywo/loginshell" -) - -func NewPtyWithShell() (*os.File, error) { - - shellStr, err := loginshell.Shell() - if err != nil { - return nil, fmt.Errorf("Failed to ascertain your shell: %s", err) - } - - pty, tty, err := open() - if err != nil { - return nil, err - } - defer tty.Close() - shell := exec.Command(shellStr) - shell.Stdout = tty - shell.Stdin = tty - shell.Stderr = tty - shell.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true} - if err := shell.Start(); err != nil { - pty.Close() - return nil, err - } - return pty, nil -} diff --git a/pty/pty_darwin.go b/pty/pty_darwin.go deleted file mode 100644 index 3a0f1f8..0000000 --- a/pty/pty_darwin.go +++ /dev/null @@ -1,79 +0,0 @@ -package pty - -import ( - "errors" - "fmt" - "os" - "syscall" - "unsafe" -) - -// todo: port these for darwin/windows: -func open() (*os.File, *os.File, error) { - - pty, err := getpt() - if err != nil { - panic(err) - } - - ptsName, err := ptsname(pty) - if err != nil { - panic(err) - } - - err = grantpt(pty) - if err != nil { - return nil, nil, err - } - - err = unlockpt(pty) - if err != nil { - return nil, nil, err - } - - tty, err := os.OpenFile(ptsName, os.O_RDWR, 0) - if err != nil { - return nil, nil, err - } - return pty, tty, nil - -} - -func getpt() (file *os.File, err error) { - f, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|syscall.O_CLOEXEC, 0) - if err != nil { - return nil, err - } - return os.NewFile(uintptr(f), "/dev/ptmx"), nil -} - -func ptsname(file *os.File) (name string, err error) { - - n := make([]byte, (syscall.TIOCPTYGNAME>>16)&((1<<13)-1)) - _, err = ioctl(file, syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0]))) - for i, c := range n { - if c == 0 { - return string(n[:i]), nil - } - } - return "", errors.New("TIOCPTYGNAME string not NUL-terminated") -} - -func ioctl(file *os.File, command uint, arg uintptr) (uintptr, error) { - _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(file.Fd()), - uintptr(command), uintptr(unsafe.Pointer(&arg))) - if err != 0 { - return 0, fmt.Errorf("Error no %d", err) - } - return arg, nil -} - -func grantpt(f *os.File) error { - _, err := ioctl(f, syscall.TIOCPTYGRANT, 0) - return err -} - -func unlockpt(f *os.File) error { - _, err := ioctl(f, syscall.TIOCPTYUNLK, 0) - return err -} diff --git a/pty/pty_linux.go b/pty/pty_linux.go deleted file mode 100644 index 0b3389a..0000000 --- a/pty/pty_linux.go +++ /dev/null @@ -1,70 +0,0 @@ -package pty - -import ( - "fmt" - "os" - "syscall" - "unsafe" -) - -// todo: port these for darwin/windows: -func open() (*os.File, *os.File, error) { - - pty, err := getpt() - if err != nil { - panic(err) - } - - ptsName, err := ptsname(pty) - if err != nil { - panic(err) - } - - // err = grantpt(pty) - // if err != nil { - // return nil, nil, err - // } - - err = unlockpt(pty) - if err != nil { - return nil, nil, err - } - - tty, err := os.OpenFile(ptsName, os.O_RDWR, 0) - if err != nil { - return nil, nil, err - } - return pty, tty, nil - -} - -func getpt() (file *os.File, err error) { - return os.OpenFile("/dev/ptmx", os.O_RDWR, 0) -} - -func ptsname(file *os.File) (name string, err error) { - n, err := ioctl(file, syscall.TIOCGPTN, 0) - return fmt.Sprintf("/dev/pts/%d", n), err -} - -func ioctl(file *os.File, command uint, arg int) (int, error) { - _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(file.Fd()), - uintptr(command), uintptr(unsafe.Pointer(&arg))) - if err != 0 { - return 0, fmt.Errorf("Error no %d", err) - } - return arg, nil -} - -/* -func grantpt(f *os.File) error { - _, err := ioctl(f, syscall.TIOCPTYGRANT, 0) - syscall.SYS - return err -} -*/ - -func unlockpt(f *os.File) error { - _, err := ioctl(f, syscall.TIOCSPTLCK, 0) - return err -}