mirror of https://github.com/liamg/aminal.git
commit
44f3f4d031
|
@ -200,6 +200,9 @@ func (buffer *Buffer) ViewHeight() uint16 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (buffer *Buffer) insertLine() {
|
func (buffer *Buffer) insertLine() {
|
||||||
|
|
||||||
|
defer buffer.emitDisplayChange()
|
||||||
|
|
||||||
if !buffer.InScrollableRegion() {
|
if !buffer.InScrollableRegion() {
|
||||||
pos := buffer.RawLine()
|
pos := buffer.RawLine()
|
||||||
out := make([]Line, len(buffer.lines)+1)
|
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.
|
// 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."
|
// If the active position is at the bottom margin, a scroll up is performed."
|
||||||
|
|
||||||
|
defer buffer.emitDisplayChange()
|
||||||
|
|
||||||
if buffer.InScrollableRegion() {
|
if buffer.InScrollableRegion() {
|
||||||
|
|
||||||
if uint(buffer.cursorY) < buffer.bottomMargin {
|
if uint(buffer.cursorY) < buffer.bottomMargin {
|
||||||
|
@ -277,6 +282,9 @@ func (buffer *Buffer) Index() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (buffer *Buffer) ReverseIndex() {
|
func (buffer *Buffer) ReverseIndex() {
|
||||||
|
|
||||||
|
defer buffer.emitDisplayChange()
|
||||||
|
|
||||||
if buffer.InScrollableRegion() {
|
if buffer.InScrollableRegion() {
|
||||||
|
|
||||||
if uint(buffer.cursorY) > buffer.topMargin {
|
if uint(buffer.cursorY) > buffer.topMargin {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
76
main.go
76
main.go
|
@ -1,93 +1,20 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/kr/pty"
|
"github.com/kr/pty"
|
||||||
"github.com/liamg/aminal/config"
|
|
||||||
"github.com/liamg/aminal/gui"
|
"github.com/liamg/aminal/gui"
|
||||||
"github.com/liamg/aminal/terminal"
|
"github.com/liamg/aminal/terminal"
|
||||||
"github.com/riywo/loginshell"
|
"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() {
|
func main() {
|
||||||
|
|
||||||
// parse this
|
|
||||||
conf := getConfig()
|
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)
|
logger, err := getLogger(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to create logger: %s\n", err)
|
fmt.Printf("Failed to create logger: %s\n", err)
|
||||||
|
@ -106,6 +33,9 @@ func main() {
|
||||||
logger.Fatalf("Failed to ascertain your shell: %s", err)
|
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 := exec.Command(shellStr)
|
||||||
shell.Stdout = tty
|
shell.Stdout = tty
|
||||||
shell.Stdin = tty
|
shell.Stdin = tty
|
||||||
|
|
34
pty/pty.go
34
pty/pty.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
Loading…
Reference in New Issue