Support CTRL-Z (SIGSTOP)

pull/909/head
Junegunn Choi 7 years ago
parent 6b592137b9
commit d34e4cf698
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627

@ -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…
Cancel
Save