fzf/src/core.go

165 lines
3.6 KiB
Go
Raw Normal View History

2015-01-01 19:49:30 +00:00
package fzf
import (
"fmt"
"os"
"runtime"
"time"
)
2015-01-08 13:07:04 +00:00
const COORDINATOR_DELAY_MAX time.Duration = 100 * time.Millisecond
const COORDINATOR_DELAY_STEP time.Duration = 10 * time.Millisecond
2015-01-01 19:49:30 +00:00
func initProcs() {
runtime.GOMAXPROCS(runtime.NumCPU())
}
/*
Reader -> EVT_READ_FIN
Reader -> EVT_READ_NEW -> Matcher (restart)
Terminal -> EVT_SEARCH_NEW -> Matcher (restart)
Matcher -> EVT_SEARCH_PROGRESS -> Terminal (update info)
Matcher -> EVT_SEARCH_FIN -> Terminal (update list)
*/
func Run(options *Options) {
initProcs()
opts := ParseOptions()
if opts.Version {
fmt.Println(VERSION)
os.Exit(0)
}
// Event channel
eventBox := NewEventBox()
// Chunk list
var chunkList *ChunkList
if len(opts.WithNth) == 0 {
chunkList = NewChunkList(func(data *string, index int) *Item {
2015-01-08 17:37:08 +00:00
return &Item{text: data, rank: Rank{0, 0, uint32(index)}}
2015-01-01 19:49:30 +00:00
})
} else {
chunkList = NewChunkList(func(data *string, index int) *Item {
2015-01-08 17:37:08 +00:00
tokens := Tokenize(data, opts.Delimiter)
item := Item{
text: Transform(tokens, opts.WithNth).whole,
origText: data,
rank: Rank{0, 0, uint32(index)}}
2015-01-01 19:49:30 +00:00
return &item
})
}
// Reader
reader := Reader{func(str string) { chunkList.Push(str) }, eventBox}
go reader.ReadSource()
// Matcher
patternBuilder := func(runes []rune) *Pattern {
return BuildPattern(
opts.Mode, opts.Case, opts.Nth, opts.Delimiter, runes)
}
matcher := NewMatcher(patternBuilder, opts.Sort > 0, eventBox)
// Defered-interactive / Non-interactive
// --select-1 | --exit-0 | --filter
if filtering := opts.Filter != nil; filtering || opts.Select1 || opts.Exit0 {
limit := 0
var patternString string
if filtering {
patternString = *opts.Filter
} else {
if opts.Select1 || opts.Exit0 {
limit = 1
}
patternString = opts.Query
}
pattern := patternBuilder([]rune(patternString))
looping := true
eventBox.Unwatch(EVT_READ_NEW)
2015-01-01 19:49:30 +00:00
for looping {
eventBox.Wait(func(events *Events) {
for evt, _ := range *events {
switch evt {
case EVT_READ_FIN:
looping = false
return
}
}
})
}
snapshot, _ := chunkList.Snapshot()
merger, cancelled := matcher.scan(MatchRequest{
chunks: snapshot,
2015-01-01 19:49:30 +00:00
pattern: pattern}, limit)
if !cancelled && (filtering ||
opts.Exit0 && merger.Length() == 0 ||
opts.Select1 && merger.Length() == 1) {
2015-01-01 19:49:30 +00:00
if opts.PrintQuery {
fmt.Println(patternString)
}
for i := 0; i < merger.Length(); i++ {
merger.Get(i).Print()
2015-01-01 19:49:30 +00:00
}
os.Exit(0)
}
}
// Go interactive
go matcher.Loop()
// Terminal I/O
terminal := NewTerminal(opts, eventBox)
go terminal.Loop()
// Event coordination
reading := true
ticks := 0
eventBox.Watch(EVT_READ_NEW)
2015-01-01 19:49:30 +00:00
for {
delay := true
ticks += 1
eventBox.Wait(func(events *Events) {
defer events.Clear()
for evt, value := range *events {
switch evt {
case EVT_READ_NEW, EVT_READ_FIN:
reading = reading && evt == EVT_READ_NEW
snapshot, count := chunkList.Snapshot()
terminal.UpdateCount(count, !reading)
matcher.Reset(snapshot, terminal.Input(), false)
2015-01-01 19:49:30 +00:00
case EVT_SEARCH_NEW:
snapshot, _ := chunkList.Snapshot()
matcher.Reset(snapshot, terminal.Input(), true)
2015-01-01 19:49:30 +00:00
delay = false
case EVT_SEARCH_PROGRESS:
switch val := value.(type) {
case float32:
terminal.UpdateProgress(val)
}
case EVT_SEARCH_FIN:
switch val := value.(type) {
case *Merger:
2015-01-01 19:49:30 +00:00
terminal.UpdateList(val)
}
}
}
})
2015-01-08 13:07:04 +00:00
if delay && reading {
dur := DurWithin(
time.Duration(ticks)*COORDINATOR_DELAY_STEP,
0, COORDINATOR_DELAY_MAX)
time.Sleep(dur)
2015-01-01 19:49:30 +00:00
}
}
}