Support CTRL-Z (SIGSTOP)
This commit is contained in:
parent
6b592137b9
commit
d34e4cf698
@ -59,6 +59,7 @@ type Terminal struct {
|
||||
inlineInfo bool
|
||||
prompt string
|
||||
reverse bool
|
||||
fullscreen bool
|
||||
hscroll bool
|
||||
hscrollOff int
|
||||
wordRubout string
|
||||
@ -141,6 +142,7 @@ const (
|
||||
reqList
|
||||
reqJump
|
||||
reqRefresh
|
||||
reqReinit
|
||||
reqRedraw
|
||||
reqClose
|
||||
reqPrintQuery
|
||||
@ -210,6 +212,7 @@ const (
|
||||
actExecute
|
||||
actExecuteSilent
|
||||
actExecuteMulti // Deprecated
|
||||
actSigStop
|
||||
)
|
||||
|
||||
func toActions(types ...actionType) []action {
|
||||
@ -246,6 +249,9 @@ func defaultKeymap() map[int][]action {
|
||||
keymap[tui.CtrlU] = toActions(actUnixLineDiscard)
|
||||
keymap[tui.CtrlW] = toActions(actUnixWordRubout)
|
||||
keymap[tui.CtrlY] = toActions(actYank)
|
||||
if !util.IsWindows() {
|
||||
keymap[tui.CtrlZ] = toActions(actSigStop)
|
||||
}
|
||||
|
||||
keymap[tui.AltB] = toActions(actBackwardWord)
|
||||
keymap[tui.SLeft] = toActions(actBackwardWord)
|
||||
@ -295,7 +301,8 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||
strongAttr = tui.AttrRegular
|
||||
}
|
||||
var renderer tui.Renderer
|
||||
if opts.Height.size == 0 || opts.Height.percent && opts.Height.size == 100 {
|
||||
fullscreen := opts.Height.size == 0 || opts.Height.percent && opts.Height.size == 100
|
||||
if fullscreen {
|
||||
if tui.HasFullscreenRenderer() {
|
||||
renderer = tui.NewFullscreenRenderer(opts.Theme, opts.Black, opts.Mouse)
|
||||
} else {
|
||||
@ -337,6 +344,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||
inlineInfo: opts.InlineInfo,
|
||||
prompt: opts.Prompt,
|
||||
reverse: opts.Reverse,
|
||||
fullscreen: fullscreen,
|
||||
hscroll: opts.Hscroll,
|
||||
hscrollOff: opts.HscrollOff,
|
||||
wordRubout: wordRubout,
|
||||
@ -1170,6 +1178,12 @@ func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, fo
|
||||
})
|
||||
}
|
||||
|
||||
func (t *Terminal) redraw() {
|
||||
t.tui.Clear()
|
||||
t.tui.Refresh()
|
||||
t.printAll()
|
||||
}
|
||||
|
||||
func (t *Terminal) executeCommand(template string, forcePlus bool, background bool) {
|
||||
valid, list := t.buildPlusList(template, forcePlus)
|
||||
if !valid {
|
||||
@ -1181,12 +1195,10 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
t.tui.Pause()
|
||||
t.tui.Pause(true)
|
||||
cmd.Run()
|
||||
if t.tui.Resume() {
|
||||
t.tui.Clear()
|
||||
t.printAll()
|
||||
}
|
||||
t.tui.Resume(true)
|
||||
t.redraw()
|
||||
t.refresh()
|
||||
} else {
|
||||
cmd.Run()
|
||||
@ -1244,6 +1256,15 @@ func (t *Terminal) Loop() {
|
||||
t.reqBox.Set(reqQuit, nil)
|
||||
}()
|
||||
|
||||
contChan := make(chan os.Signal, 1)
|
||||
notifyOnCont(contChan)
|
||||
go func() {
|
||||
for {
|
||||
<-contChan
|
||||
t.reqBox.Set(reqReinit, nil)
|
||||
}
|
||||
}()
|
||||
|
||||
resizeChan := make(chan os.Signal, 1)
|
||||
notifyOnResize(resizeChan) // Non-portable
|
||||
go func() {
|
||||
@ -1352,10 +1373,11 @@ func (t *Terminal) Loop() {
|
||||
t.printHeader()
|
||||
case reqRefresh:
|
||||
t.suppress = false
|
||||
case reqReinit:
|
||||
t.tui.Resume(t.fullscreen)
|
||||
t.redraw()
|
||||
case reqRedraw:
|
||||
t.tui.Clear()
|
||||
t.tui.Refresh()
|
||||
t.printAll()
|
||||
t.redraw()
|
||||
case reqClose:
|
||||
t.tui.Close()
|
||||
if t.output() {
|
||||
@ -1654,6 +1676,15 @@ func (t *Terminal) Loop() {
|
||||
t.input = []rune(t.history.next())
|
||||
t.cx = len(t.input)
|
||||
}
|
||||
case actSigStop:
|
||||
p, err := os.FindProcess(os.Getpid())
|
||||
if err == nil {
|
||||
t.tui.Clear()
|
||||
t.tui.Pause(t.fullscreen)
|
||||
notifyStop(p)
|
||||
t.mutex.Unlock()
|
||||
return false
|
||||
}
|
||||
case actMouse:
|
||||
me := event.MouseEvent
|
||||
mx, my := me.X, me.Y
|
||||
|
@ -11,3 +11,11 @@ import (
|
||||
func notifyOnResize(resizeChan chan<- os.Signal) {
|
||||
signal.Notify(resizeChan, syscall.SIGWINCH)
|
||||
}
|
||||
|
||||
func notifyStop(p *os.Process) {
|
||||
p.Signal(syscall.SIGSTOP)
|
||||
}
|
||||
|
||||
func notifyOnCont(resizeChan chan<- os.Signal) {
|
||||
signal.Notify(resizeChan, syscall.SIGCONT)
|
||||
}
|
||||
|
@ -9,3 +9,11 @@ import (
|
||||
func notifyOnResize(resizeChan chan<- os.Signal) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func notifyStop(p *os.Process) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
func notifyOnCont(resizeChan chan<- os.Signal) {
|
||||
// NOOP
|
||||
}
|
||||
|
@ -25,13 +25,13 @@ const (
|
||||
Reverse = Attr(1 << 6)
|
||||
)
|
||||
|
||||
func (r *FullscreenRenderer) Init() {}
|
||||
func (r *FullscreenRenderer) Pause() {}
|
||||
func (r *FullscreenRenderer) Clear() {}
|
||||
func (r *FullscreenRenderer) Refresh() {}
|
||||
func (r *FullscreenRenderer) Close() {}
|
||||
func (r *FullscreenRenderer) Init() {}
|
||||
func (r *FullscreenRenderer) Pause(bool) {}
|
||||
func (r *FullscreenRenderer) Resume(bool) {}
|
||||
func (r *FullscreenRenderer) Clear() {}
|
||||
func (r *FullscreenRenderer) Refresh() {}
|
||||
func (r *FullscreenRenderer) Close() {}
|
||||
|
||||
func (r *FullscreenRenderer) Resume() bool { return false }
|
||||
func (r *FullscreenRenderer) DoesAutoWrap() bool { return false }
|
||||
func (r *FullscreenRenderer) IsOptimized() bool { return false }
|
||||
func (r *FullscreenRenderer) GetChar() Event { return Event{} }
|
||||
|
@ -522,27 +522,35 @@ func (r *LightRenderer) rmcup() {
|
||||
r.csi("?1049l")
|
||||
}
|
||||
|
||||
func (r *LightRenderer) Pause() {
|
||||
func (r *LightRenderer) Pause(clear bool) {
|
||||
terminal.Restore(r.fd(), r.origState)
|
||||
if r.fullscreen {
|
||||
r.rmcup()
|
||||
} else {
|
||||
r.smcup()
|
||||
r.csi("H")
|
||||
if clear {
|
||||
if r.fullscreen {
|
||||
r.rmcup()
|
||||
} else {
|
||||
r.smcup()
|
||||
r.csi("H")
|
||||
}
|
||||
r.flush()
|
||||
}
|
||||
r.flush()
|
||||
}
|
||||
|
||||
func (r *LightRenderer) Resume() bool {
|
||||
func (r *LightRenderer) Resume(clear bool) {
|
||||
terminal.MakeRaw(r.fd())
|
||||
if r.fullscreen {
|
||||
r.smcup()
|
||||
} else {
|
||||
r.rmcup()
|
||||
if clear {
|
||||
if r.fullscreen {
|
||||
r.smcup()
|
||||
} else {
|
||||
r.rmcup()
|
||||
}
|
||||
r.flush()
|
||||
} else if !r.fullscreen && r.mouse {
|
||||
// NOTE: Resume(false) is only called on SIGCONT after SIGSTOP.
|
||||
// And It's highly likely that the offset we obtained at the beginning will
|
||||
// no longer be correct, so we simply disable mouse input.
|
||||
r.csi("?1000l")
|
||||
r.mouse = false
|
||||
}
|
||||
r.flush()
|
||||
// Should redraw
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *LightRenderer) Clear() {
|
||||
|
@ -176,12 +176,11 @@ func initPairs(theme *ColorTheme) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *FullscreenRenderer) Pause() {
|
||||
func (r *FullscreenRenderer) Pause(bool) {
|
||||
C.endwin()
|
||||
}
|
||||
|
||||
func (r *FullscreenRenderer) Resume() bool {
|
||||
return false
|
||||
func (r *FullscreenRenderer) Resume(bool) {
|
||||
}
|
||||
|
||||
func (r *FullscreenRenderer) Close() {
|
||||
|
@ -282,7 +282,7 @@ func (r *FullscreenRenderer) GetChar() Event {
|
||||
return Event{keyfn('z'), 0, nil}
|
||||
case tcell.KeyCtrlSpace:
|
||||
return Event{CtrlSpace, 0, nil}
|
||||
case tcell.KeyBackspace, tcell.KeyBackspace2:
|
||||
case tcell.KeyBackspace2:
|
||||
if alt {
|
||||
return Event{AltBS, 0, nil}
|
||||
}
|
||||
@ -308,8 +308,6 @@ func (r *FullscreenRenderer) GetChar() Event {
|
||||
case tcell.KeyPgDn:
|
||||
return Event{PgDn, 0, nil}
|
||||
|
||||
case tcell.KeyTab:
|
||||
return Event{Tab, 0, nil}
|
||||
case tcell.KeyBacktab:
|
||||
return Event{BTab, 0, nil}
|
||||
|
||||
@ -366,13 +364,12 @@ func (r *FullscreenRenderer) GetChar() Event {
|
||||
return Event{Invalid, 0, nil}
|
||||
}
|
||||
|
||||
func (r *FullscreenRenderer) Pause() {
|
||||
func (r *FullscreenRenderer) Pause(bool) {
|
||||
_screen.Fini()
|
||||
}
|
||||
|
||||
func (r *FullscreenRenderer) Resume() bool {
|
||||
func (r *FullscreenRenderer) Resume(bool) {
|
||||
r.initScreen()
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *FullscreenRenderer) Close() {
|
||||
|
@ -206,8 +206,8 @@ const (
|
||||
|
||||
type Renderer interface {
|
||||
Init()
|
||||
Pause()
|
||||
Resume() bool
|
||||
Pause(clear bool)
|
||||
Resume(clear bool)
|
||||
Clear()
|
||||
RefreshWindows(windows []Window)
|
||||
Refresh()
|
||||
|
Loading…
x
Reference in New Issue
Block a user