summaryrefslogtreecommitdiff
path: root/src/core.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/core.go')
-rw-r--r--src/core.go68
1 files changed, 46 insertions, 22 deletions
diff --git a/src/core.go b/src/core.go
index 14aa781f..dbae6a69 100644
--- a/src/core.go
+++ b/src/core.go
@@ -2,7 +2,6 @@
package fzf
import (
- "fmt"
"sync"
"time"
"unsafe"
@@ -27,22 +26,29 @@ func sbytes(data string) []byte {
return unsafe.Slice(unsafe.StringData(data), len(data))
}
+type quitSignal struct {
+ code int
+ err error
+}
+
// Run starts fzf
-func Run(opts *Options, version string, revision string) {
- defer util.RunAtExitFuncs()
+func Run(opts *Options) (int, error) {
+ if err := postProcessOptions(opts); err != nil {
+ return ExitError, err
+ }
- sort := opts.Sort > 0
- sortCriteria = opts.Criteria
+ defer util.RunAtExitFuncs()
- if opts.Version {
- if len(revision) > 0 {
- fmt.Printf("%s (%s)\n", version, revision)
- } else {
- fmt.Println(version)
+ // Output channel given
+ if opts.Output != nil {
+ opts.Printer = func(str string) {
+ opts.Output <- str
}
- util.Exit(exitOk)
}
+ sort := opts.Sort > 0
+ sortCriteria = opts.Criteria
+
// Event channel
eventBox := util.NewEventBox()
@@ -131,7 +137,7 @@ func Run(opts *Options, version string, revision string) {
reader = NewReader(func(data []byte) bool {
return chunkList.Push(data)
}, eventBox, executor, opts.ReadZero, opts.Filter == nil)
- go reader.ReadSource(opts.WalkerRoot, opts.WalkerOpts, opts.WalkerSkip)
+ go reader.ReadSource(opts.Input, opts.WalkerRoot, opts.WalkerOpts, opts.WalkerSkip)
}
// Matcher
@@ -147,14 +153,16 @@ func Run(opts *Options, version string, revision string) {
forward = true
}
}
+ cache := NewChunkCache()
+ patternCache := make(map[string]*Pattern)
patternBuilder := func(runes []rune) *Pattern {
- return BuildPattern(
+ return BuildPattern(cache, patternCache,
opts.Fuzzy, opts.FuzzyAlgo, opts.Extended, opts.Case, opts.Normalize, forward, withPos,
opts.Filter == nil, opts.Nth, opts.Delimiter, runes)
}
inputRevision := 0
snapshotRevision := 0
- matcher := NewMatcher(patternBuilder, sort, opts.Tac, eventBox, inputRevision)
+ matcher := NewMatcher(cache, patternBuilder, sort, opts.Tac, eventBox, inputRevision)
// Filtering mode
if opts.Filter != nil {
@@ -182,7 +190,7 @@ func Run(opts *Options, version string, revision string) {
}
return false
}, eventBox, executor, opts.ReadZero, false)
- reader.ReadSource(opts.WalkerRoot, opts.WalkerOpts, opts.WalkerSkip)
+ reader.ReadSource(opts.Input, opts.WalkerRoot, opts.WalkerOpts, opts.WalkerSkip)
} else {
eventBox.Unwatch(EvtReadNew)
eventBox.WaitFor(EvtReadFin)
@@ -197,9 +205,9 @@ func Run(opts *Options, version string, revision string) {
}
}
if found {
- util.Exit(exitOk)
+ return ExitOk, nil
}
- util.Exit(exitNoMatch)
+ return ExitNoMatch, nil
}
// Synchronous search
@@ -210,9 +218,13 @@ func Run(opts *Options, version string, revision string) {
// Go interactive
go matcher.Loop()
+ defer matcher.Stop()
// Terminal I/O
- terminal := NewTerminal(opts, eventBox, executor)
+ terminal, err := NewTerminal(opts, eventBox, executor)
+ if err != nil {
+ return ExitError, err
+ }
maxFit := 0 // Maximum number of items that can fit on screen
padHeight := 0
heightUnknown := opts.Height.auto
@@ -258,6 +270,9 @@ func Run(opts *Options, version string, revision string) {
header = make([]string, 0, opts.HeaderLines)
go reader.restart(command, environ)
}
+
+ exitCode := ExitOk
+ stop := false
for {
delay := true
ticks++
@@ -278,7 +293,11 @@ func Run(opts *Options, version string, revision string) {
if reading {
reader.terminate()
}
- util.Exit(value.(int))
+ quitSignal := value.(quitSignal)
+ exitCode = quitSignal.code
+ err = quitSignal.err
+ stop = true
+ return
case EvtReadNew, EvtReadFin:
if evt == EvtReadFin && nextCommand != nil {
restart(*nextCommand, nextEnviron)
@@ -378,10 +397,11 @@ func Run(opts *Options, version string, revision string) {
for i := 0; i < count; i++ {
opts.Printer(val.Get(i).item.AsString(opts.Ansi))
}
- if count > 0 {
- util.Exit(exitOk)
+ if count == 0 {
+ exitCode = ExitNoMatch
}
- util.Exit(exitNoMatch)
+ stop = true
+ return
}
determine(val.final)
}
@@ -392,6 +412,9 @@ func Run(opts *Options, version string, revision string) {
}
events.Clear()
})
+ if stop {
+ break
+ }
if delay && reading {
dur := util.DurWithin(
time.Duration(ticks)*coordinatorDelayStep,
@@ -399,4 +422,5 @@ func Run(opts *Options, version string, revision string) {
time.Sleep(dur)
}
}
+ return exitCode, err
}