mirror of
https://github.com/peco/peco.git
synced 2026-09-10 07:16:29 -04:00
This change fixes #144 by delaying all the terminal initialization until there's something coming in from the standard input. Without this, for example, a succesive chain of commands that expect to use stdin will fail, because peco might accidentally grab the stdin under the hood. With this change, peco is forced to wait to do any terminal related stuff until some output has been spewed by the previous command (which is most likely when the command is ready to give up the control of the terminal), so things work again.
96 lines
2 KiB
Go
96 lines
2 KiB
Go
package peco
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// BufferReader reads lines from the input, either Stdin or a file.
|
|
// If the incoming data is endless, it keeps reading and adding to
|
|
// the search buffer, as long as it can.
|
|
//
|
|
// If you would like to limit the number of lines to keep in the
|
|
// buffer, you should set --buffer-size to a number > 0
|
|
type BufferReader struct {
|
|
*Ctx
|
|
input io.ReadCloser
|
|
inputReadyCh chan struct{}
|
|
}
|
|
|
|
func (b *BufferReader) InputReadyCh() <-chan struct{} {
|
|
return b.inputReadyCh
|
|
}
|
|
|
|
// Loop keeps reading from the input
|
|
func (b *BufferReader) Loop() {
|
|
defer b.ReleaseWaitGroup()
|
|
defer func() { recover() }() // ignore errors
|
|
defer func() { close(b.inputReadyCh) }() // Make sure to close notifier
|
|
|
|
ch := make(chan string, 10)
|
|
|
|
// scanner.Scan() blocks until the next read or error. But we want to
|
|
// exit immediately, so we move it out to its own goroutine
|
|
go func() {
|
|
defer func() { recover() }()
|
|
defer func() { close(ch) }()
|
|
scanner := bufio.NewScanner(b.input)
|
|
for scanner.Scan() {
|
|
ch <- scanner.Text()
|
|
}
|
|
}()
|
|
|
|
m := &sync.Mutex{}
|
|
once := &sync.Once{}
|
|
var refresh *time.Timer
|
|
|
|
loop := true
|
|
for loop {
|
|
select {
|
|
case <-b.LoopCh():
|
|
loop = false
|
|
case line, ok := <-ch:
|
|
if !ok {
|
|
loop = false
|
|
continue
|
|
}
|
|
|
|
if line != "" {
|
|
once.Do(func() { b.inputReadyCh <- struct{}{} })
|
|
m.Lock()
|
|
b.lines = append(b.lines, NewNoMatch(line, b.enableSep))
|
|
if b.IsBufferOverflowing() {
|
|
b.lines = b.lines[1:]
|
|
}
|
|
m.Unlock()
|
|
}
|
|
|
|
m.Lock()
|
|
if refresh == nil {
|
|
refresh = time.AfterFunc(100*time.Millisecond, func() {
|
|
if !b.ExecQuery() {
|
|
b.DrawMatches(b.lines)
|
|
}
|
|
m.Lock()
|
|
refresh = nil
|
|
m.Unlock()
|
|
})
|
|
}
|
|
m.Unlock()
|
|
}
|
|
}
|
|
|
|
b.input.Close()
|
|
|
|
// Out of the reader loop. If at this point we have no buffer,
|
|
// that means we have no buffer, so we should quit.
|
|
if len(b.lines) == 0 {
|
|
b.ExitWith(1)
|
|
fmt.Fprintf(os.Stderr, "No buffer to work with was available")
|
|
}
|
|
}
|