Add named keys, input-line reporting and append guard to terminal_type
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -22,8 +23,12 @@ const (
|
||||
clientBuf = 256
|
||||
MaxSize = 1 << 15
|
||||
promptMark = "\x1b]133;D;"
|
||||
lineMark = "\x1b]7701;"
|
||||
carryMax = 64 << 10
|
||||
)
|
||||
|
||||
var lineMarks = [][]byte{[]byte(promptMark), []byte(lineMark)}
|
||||
|
||||
const zshenv = `if [[ -n $BYRE_ZDOTDIR ]]; then
|
||||
ZDOTDIR=$BYRE_ZDOTDIR
|
||||
else
|
||||
@@ -35,6 +40,13 @@ if [[ -o interactive ]]; then
|
||||
unsetopt PROMPT_SP
|
||||
_byre_precmd() { print -n "\e]133;D;$?\a" }
|
||||
precmd_functions+=(_byre_precmd)
|
||||
_byre_line() { local line=$PREBUFFER$BUFFER; print -rn -- $'\e]7701;L'"${line//[[:cntrl:]]/ }"$'\a' }
|
||||
_byre_line_end() { print -rn -- $'\e]7701;E\a' }
|
||||
zmodload zsh/zle
|
||||
autoload -Uz add-zle-hook-widget
|
||||
add-zle-hook-widget line-init _byre_line
|
||||
add-zle-hook-widget line-pre-redraw _byre_line
|
||||
add-zle-hook-widget line-finish _byre_line_end
|
||||
fi
|
||||
`
|
||||
|
||||
@@ -58,6 +70,9 @@ type Terminal struct {
|
||||
started time.Time
|
||||
lastOutput time.Time
|
||||
wake *wake
|
||||
carry []byte
|
||||
line string
|
||||
atPrompt bool
|
||||
}
|
||||
|
||||
type wake struct {
|
||||
@@ -188,6 +203,9 @@ func (term *Terminal) output(b []byte) {
|
||||
if term.wake != nil {
|
||||
term.checkWake(b)
|
||||
}
|
||||
if term.Prompts {
|
||||
term.trackLine(b)
|
||||
}
|
||||
term.backlog = append(term.backlog, b...)
|
||||
if len(term.backlog) > 2*backlogSize {
|
||||
term.backlog = bytes.Clone(term.backlog[len(term.backlog)-backlogSize:])
|
||||
@@ -222,10 +240,67 @@ func (term *Terminal) checkWake(b []byte) {
|
||||
go w.fn(string(w.out[start+len(promptMark):start+end]), w.out[:start])
|
||||
}
|
||||
|
||||
func (term *Terminal) WakeOnPrompt(fn func(exit string, out []byte)) {
|
||||
func (term *Terminal) trackLine(b []byte) {
|
||||
s := append(term.carry, b...)
|
||||
term.carry = nil
|
||||
for {
|
||||
i := bytes.Index(s, []byte("\x1b]"))
|
||||
if i < 0 {
|
||||
if len(s) > 0 && s[len(s)-1] == 0x1b {
|
||||
term.carry = []byte{0x1b}
|
||||
}
|
||||
return
|
||||
}
|
||||
rest := s[i:]
|
||||
var prefix []byte
|
||||
for _, m := range lineMarks {
|
||||
if bytes.HasPrefix(rest, m) {
|
||||
prefix = m
|
||||
break
|
||||
}
|
||||
if len(rest) < len(m) && bytes.HasPrefix(m, rest) {
|
||||
term.carry = bytes.Clone(rest)
|
||||
return
|
||||
}
|
||||
}
|
||||
if prefix == nil {
|
||||
s = rest[2:]
|
||||
continue
|
||||
}
|
||||
end := bytes.IndexByte(rest, '\a')
|
||||
if end < 0 {
|
||||
if len(rest) < carryMax {
|
||||
term.carry = bytes.Clone(rest)
|
||||
}
|
||||
return
|
||||
}
|
||||
body := string(rest[len(prefix):end])
|
||||
switch {
|
||||
case string(prefix) == promptMark:
|
||||
term.atPrompt, term.line = true, ""
|
||||
case body == "E":
|
||||
term.atPrompt, term.line = false, ""
|
||||
case strings.HasPrefix(body, "L"):
|
||||
term.atPrompt, term.line = true, body[1:]
|
||||
}
|
||||
s = rest[end+1:]
|
||||
}
|
||||
}
|
||||
|
||||
func (term *Terminal) InputLine() (string, bool) {
|
||||
term.mu.Lock()
|
||||
defer term.mu.Unlock()
|
||||
return term.line, term.atPrompt
|
||||
}
|
||||
|
||||
func (term *Terminal) WakeOnPrompt(fn func(exit string, out []byte), mayRun bool) bool {
|
||||
term.mu.Lock()
|
||||
defer term.mu.Unlock()
|
||||
if term.atPrompt && term.line == "" || !term.atPrompt && !mayRun {
|
||||
return false
|
||||
}
|
||||
term.wake = &wake{fn: fn}
|
||||
return true
|
||||
}
|
||||
|
||||
func (term *Terminal) CancelWake() {
|
||||
|
||||
Reference in New Issue
Block a user