Reorganize source code
This commit is contained in:
parent
7a2bc2cada
commit
cd847affb7
@ -33,7 +33,7 @@ build: fzf/$(BINARY32) fzf/$(BINARY64)
|
||||
|
||||
test:
|
||||
go get
|
||||
go test -v
|
||||
go test -v ./...
|
||||
|
||||
install: $(BINDIR)/fzf
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package fzf
|
||||
package algo
|
||||
|
||||
import "strings"
|
||||
|
@ -1,4 +1,4 @@
|
||||
package fzf
|
||||
package algo
|
||||
|
||||
import (
|
||||
"strings"
|
@ -8,20 +8,20 @@ const ChunkSize int = 100
|
||||
// Chunk is a list of Item pointers whose size has the upper limit of ChunkSize
|
||||
type Chunk []*Item // >>> []Item
|
||||
|
||||
// Transformer is a closure type that builds Item object from a pointer to a
|
||||
// ItemBuilder is a closure type that builds Item object from a pointer to a
|
||||
// string and an integer
|
||||
type Transformer func(*string, int) *Item
|
||||
type ItemBuilder func(*string, int) *Item
|
||||
|
||||
// ChunkList is a list of Chunks
|
||||
type ChunkList struct {
|
||||
chunks []*Chunk
|
||||
count int
|
||||
mutex sync.Mutex
|
||||
trans Transformer
|
||||
trans ItemBuilder
|
||||
}
|
||||
|
||||
// NewChunkList returns a new ChunkList
|
||||
func NewChunkList(trans Transformer) *ChunkList {
|
||||
func NewChunkList(trans ItemBuilder) *ChunkList {
|
||||
return &ChunkList{
|
||||
chunks: []*Chunk{},
|
||||
count: 0,
|
||||
@ -29,7 +29,7 @@ func NewChunkList(trans Transformer) *ChunkList {
|
||||
trans: trans}
|
||||
}
|
||||
|
||||
func (c *Chunk) push(trans Transformer, data *string, index int) {
|
||||
func (c *Chunk) push(trans ItemBuilder, data *string, index int) {
|
||||
*c = append(*c, trans(data, index))
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,15 @@
|
||||
package fzf
|
||||
|
||||
import (
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
// Current version
|
||||
const Version = "0.9.0"
|
||||
|
||||
// EventType is the type for fzf events
|
||||
type EventType int
|
||||
|
||||
// fzf events
|
||||
const (
|
||||
EvtReadNew EventType = iota
|
||||
EvtReadNew util.EventType = iota
|
||||
EvtReadFin
|
||||
EvtSearchNew
|
||||
EvtSearchProgress
|
||||
|
10
src/core.go
10
src/core.go
@ -30,6 +30,8 @@ import (
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
const coordinatorDelayMax time.Duration = 100 * time.Millisecond
|
||||
@ -59,7 +61,7 @@ func Run(options *Options) {
|
||||
}
|
||||
|
||||
// Event channel
|
||||
eventBox := NewEventBox()
|
||||
eventBox := util.NewEventBox()
|
||||
|
||||
// Chunk list
|
||||
var chunkList *ChunkList
|
||||
@ -111,7 +113,7 @@ func Run(options *Options) {
|
||||
looping := true
|
||||
eventBox.Unwatch(EvtReadNew)
|
||||
for looping {
|
||||
eventBox.Wait(func(events *Events) {
|
||||
eventBox.Wait(func(events *util.Events) {
|
||||
for evt := range *events {
|
||||
switch evt {
|
||||
case EvtReadFin:
|
||||
@ -154,7 +156,7 @@ func Run(options *Options) {
|
||||
for {
|
||||
delay := true
|
||||
ticks++
|
||||
eventBox.Wait(func(events *Events) {
|
||||
eventBox.Wait(func(events *util.Events) {
|
||||
defer events.Clear()
|
||||
for evt, value := range *events {
|
||||
switch evt {
|
||||
@ -185,7 +187,7 @@ func Run(options *Options) {
|
||||
}
|
||||
})
|
||||
if delay && reading {
|
||||
dur := DurWithin(
|
||||
dur := util.DurWithin(
|
||||
time.Duration(ticks)*coordinatorDelayStep,
|
||||
0, coordinatorDelayMax)
|
||||
time.Sleep(dur)
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
// MatchRequest represents a search request
|
||||
@ -18,14 +20,14 @@ type MatchRequest struct {
|
||||
type Matcher struct {
|
||||
patternBuilder func([]rune) *Pattern
|
||||
sort bool
|
||||
eventBox *EventBox
|
||||
reqBox *EventBox
|
||||
eventBox *util.EventBox
|
||||
reqBox *util.EventBox
|
||||
partitions int
|
||||
mergerCache map[string]*Merger
|
||||
}
|
||||
|
||||
const (
|
||||
reqRetry EventType = iota
|
||||
reqRetry util.EventType = iota
|
||||
reqReset
|
||||
)
|
||||
|
||||
@ -35,12 +37,12 @@ const (
|
||||
|
||||
// NewMatcher returns a new Matcher
|
||||
func NewMatcher(patternBuilder func([]rune) *Pattern,
|
||||
sort bool, eventBox *EventBox) *Matcher {
|
||||
sort bool, eventBox *util.EventBox) *Matcher {
|
||||
return &Matcher{
|
||||
patternBuilder: patternBuilder,
|
||||
sort: sort,
|
||||
eventBox: eventBox,
|
||||
reqBox: NewEventBox(),
|
||||
reqBox: util.NewEventBox(),
|
||||
partitions: runtime.NumCPU(),
|
||||
mergerCache: make(map[string]*Merger)}
|
||||
}
|
||||
@ -52,7 +54,7 @@ func (m *Matcher) Loop() {
|
||||
for {
|
||||
var request MatchRequest
|
||||
|
||||
m.reqBox.Wait(func(events *Events) {
|
||||
m.reqBox.Wait(func(events *util.Events) {
|
||||
for _, val := range *events {
|
||||
switch val := val.(type) {
|
||||
case MatchRequest:
|
||||
@ -128,7 +130,7 @@ func (m *Matcher) scan(request MatchRequest, limit int) (*Merger, bool) {
|
||||
}
|
||||
pattern := request.pattern
|
||||
empty := pattern.IsEmpty()
|
||||
cancelled := NewAtomicBool(false)
|
||||
cancelled := util.NewAtomicBool(false)
|
||||
|
||||
slices := m.sliceChunks(request.chunks)
|
||||
numSlices := len(slices)
|
||||
@ -202,7 +204,7 @@ func (m *Matcher) scan(request MatchRequest, limit int) (*Merger, bool) {
|
||||
func (m *Matcher) Reset(chunks []*Chunk, patternRunes []rune, cancel bool) {
|
||||
pattern := m.patternBuilder(patternRunes)
|
||||
|
||||
var event EventType
|
||||
var event util.EventType
|
||||
if cancel {
|
||||
event = reqReset
|
||||
} else {
|
||||
|
@ -2,10 +2,11 @@ package fzf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/junegunn/go-shellwords"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/junegunn/go-shellwords"
|
||||
)
|
||||
|
||||
const usage = `usage: fzf [options]
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/junegunn/fzf/src/algo"
|
||||
)
|
||||
|
||||
const uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
@ -112,10 +114,10 @@ func BuildPattern(mode Mode, caseMode Case,
|
||||
delimiter: delimiter,
|
||||
procFun: make(map[termType]func(bool, *string, []rune) (int, int))}
|
||||
|
||||
ptr.procFun[termFuzzy] = FuzzyMatch
|
||||
ptr.procFun[termExact] = ExactMatchNaive
|
||||
ptr.procFun[termPrefix] = PrefixMatch
|
||||
ptr.procFun[termSuffix] = SuffixMatch
|
||||
ptr.procFun[termFuzzy] = algo.FuzzyMatch
|
||||
ptr.procFun[termExact] = algo.ExactMatchNaive
|
||||
ptr.procFun[termPrefix] = algo.PrefixMatch
|
||||
ptr.procFun[termSuffix] = algo.SuffixMatch
|
||||
|
||||
_patternCache[asString] = ptr
|
||||
return ptr
|
||||
@ -245,7 +247,7 @@ func (p *Pattern) fuzzyMatch(chunk *Chunk) []*Item {
|
||||
matches := []*Item{}
|
||||
for _, item := range *chunk {
|
||||
input := p.prepareInput(item)
|
||||
if sidx, eidx := p.iter(FuzzyMatch, input, p.text); sidx >= 0 {
|
||||
if sidx, eidx := p.iter(algo.FuzzyMatch, input, p.text); sidx >= 0 {
|
||||
matches = append(matches,
|
||||
dupItem(item, []Offset{Offset{int32(sidx), int32(eidx)}}))
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
package fzf
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/junegunn/fzf/src/algo"
|
||||
)
|
||||
|
||||
func TestParseTermsExtended(t *testing.T) {
|
||||
terms := parseTerms(ModeExtended,
|
||||
@ -55,7 +59,7 @@ func TestExact(t *testing.T) {
|
||||
pattern := BuildPattern(ModeExtended, CaseSmart,
|
||||
[]Range{}, nil, []rune("'abc"))
|
||||
str := "aabbcc abc"
|
||||
sidx, eidx := ExactMatchNaive(pattern.caseSensitive, &str, pattern.terms[0].text)
|
||||
sidx, eidx := algo.ExactMatchNaive(pattern.caseSensitive, &str, pattern.terms[0].text)
|
||||
if sidx != 7 || eidx != 10 {
|
||||
t.Errorf("%s / %d / %d", pattern.terms, sidx, eidx)
|
||||
}
|
||||
|
@ -1,13 +1,12 @@
|
||||
package fzf
|
||||
|
||||
// #include <unistd.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
const defaultCommand = `find * -path '*/\.*' -prune -o -type f -print -o -type l -print 2> /dev/null`
|
||||
@ -15,12 +14,12 @@ const defaultCommand = `find * -path '*/\.*' -prune -o -type f -print -o -type l
|
||||
// Reader reads from command or standard input
|
||||
type Reader struct {
|
||||
pusher func(string)
|
||||
eventBox *EventBox
|
||||
eventBox *util.EventBox
|
||||
}
|
||||
|
||||
// ReadSource reads data from the default command or from standard input
|
||||
func (r *Reader) ReadSource() {
|
||||
if int(C.isatty(C.int(os.Stdin.Fd()))) != 0 {
|
||||
if util.IsTty() {
|
||||
cmd := os.Getenv("FZF_DEFAULT_COMMAND")
|
||||
if len(cmd) == 0 {
|
||||
cmd = defaultCommand
|
||||
|
@ -1,10 +1,14 @@
|
||||
package fzf
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
func TestReadFromCommand(t *testing.T) {
|
||||
strs := []string{}
|
||||
eb := NewEventBox()
|
||||
eb := util.NewEventBox()
|
||||
reader := Reader{
|
||||
pusher: func(s string) { strs = append(strs, s) },
|
||||
eventBox: eb}
|
||||
@ -26,7 +30,7 @@ func TestReadFromCommand(t *testing.T) {
|
||||
}
|
||||
|
||||
// Wait should return immediately
|
||||
eb.Wait(func(events *Events) {
|
||||
eb.Wait(func(events *util.Events) {
|
||||
if _, found := (*events)[EvtReadNew]; !found {
|
||||
t.Errorf("%s", events)
|
||||
}
|
||||
|
@ -2,13 +2,16 @@ package fzf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
C "github.com/junegunn/fzf/src/curses"
|
||||
"github.com/junegunn/go-runewidth"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
C "github.com/junegunn/fzf/src/curses"
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
|
||||
"github.com/junegunn/go-runewidth"
|
||||
)
|
||||
|
||||
// Terminal represents terminal input/output
|
||||
@ -28,8 +31,8 @@ type Terminal struct {
|
||||
reading bool
|
||||
merger *Merger
|
||||
selected map[*string]*string
|
||||
reqBox *EventBox
|
||||
eventBox *EventBox
|
||||
reqBox *util.EventBox
|
||||
eventBox *util.EventBox
|
||||
mutex sync.Mutex
|
||||
initFunc func()
|
||||
suppress bool
|
||||
@ -38,7 +41,7 @@ type Terminal struct {
|
||||
var _spinner = []string{`-`, `\`, `|`, `/`, `-`, `\`, `|`, `/`}
|
||||
|
||||
const (
|
||||
reqPrompt EventType = iota
|
||||
reqPrompt util.EventType = iota
|
||||
reqInfo
|
||||
reqList
|
||||
reqRefresh
|
||||
@ -53,7 +56,7 @@ const (
|
||||
)
|
||||
|
||||
// NewTerminal returns new Terminal object
|
||||
func NewTerminal(opts *Options, eventBox *EventBox) *Terminal {
|
||||
func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||
input := []rune(opts.Query)
|
||||
return &Terminal{
|
||||
prompt: opts.Prompt,
|
||||
@ -68,7 +71,7 @@ func NewTerminal(opts *Options, eventBox *EventBox) *Terminal {
|
||||
printQuery: opts.PrintQuery,
|
||||
merger: EmptyMerger,
|
||||
selected: make(map[*string]*string),
|
||||
reqBox: NewEventBox(),
|
||||
reqBox: util.NewEventBox(),
|
||||
eventBox: eventBox,
|
||||
mutex: sync.Mutex{},
|
||||
suppress: true,
|
||||
@ -288,7 +291,7 @@ func (*Terminal) printHighlighted(item *Item, bold bool, col1 int, col2 int) {
|
||||
b, e := offset[0], offset[1]
|
||||
b += 2 - diff
|
||||
e += 2 - diff
|
||||
b = Max32(b, 2)
|
||||
b = util.Max32(b, 2)
|
||||
if b < e {
|
||||
offsets[idx] = Offset{b, e}
|
||||
}
|
||||
@ -300,8 +303,8 @@ func (*Terminal) printHighlighted(item *Item, bold bool, col1 int, col2 int) {
|
||||
sort.Sort(ByOrder(offsets))
|
||||
var index int32
|
||||
for _, offset := range offsets {
|
||||
b := Max32(index, offset[0])
|
||||
e := Max32(index, offset[1])
|
||||
b := util.Max32(index, offset[0])
|
||||
e := util.Max32(index, offset[1])
|
||||
C.CPrint(col1, bold, string(text[index:b]))
|
||||
C.CPrint(col2, bold, string(text[b:e]))
|
||||
index = e
|
||||
@ -388,7 +391,7 @@ func (t *Terminal) Loop() {
|
||||
|
||||
go func() {
|
||||
for {
|
||||
t.reqBox.Wait(func(events *Events) {
|
||||
t.reqBox.Wait(func(events *util.Events) {
|
||||
defer events.Clear()
|
||||
t.mutex.Lock()
|
||||
for req := range *events {
|
||||
@ -426,8 +429,8 @@ func (t *Terminal) Loop() {
|
||||
|
||||
t.mutex.Lock()
|
||||
previousInput := t.input
|
||||
events := []EventType{reqPrompt}
|
||||
req := func(evts ...EventType) {
|
||||
events := []util.EventType{reqPrompt}
|
||||
req := func(evts ...util.EventType) {
|
||||
for _, event := range evts {
|
||||
events = append(events, event)
|
||||
if event == reqClose || event == reqQuit {
|
||||
@ -538,7 +541,7 @@ func (t *Terminal) Loop() {
|
||||
t.cx++
|
||||
case C.Mouse:
|
||||
me := event.MouseEvent
|
||||
mx, my := Min(len(t.input), Max(0, me.X-len(t.prompt))), me.Y
|
||||
mx, my := util.Constrain(me.X-len(t.prompt), 0, len(t.input)), me.Y
|
||||
if !t.reverse {
|
||||
my = C.MaxY() - my - 1
|
||||
}
|
||||
@ -588,7 +591,7 @@ func (t *Terminal) constrain() {
|
||||
height := C.MaxY() - 2
|
||||
diffpos := t.cy - t.offset
|
||||
|
||||
t.cy = Max(0, Min(t.cy, count-1))
|
||||
t.cy = util.Constrain(t.cy, 0, count-1)
|
||||
|
||||
if t.cy > t.offset+(height-1) {
|
||||
// Ceil
|
||||
@ -600,8 +603,8 @@ func (t *Terminal) constrain() {
|
||||
|
||||
// Adjustment
|
||||
if count-t.offset < height {
|
||||
t.offset = Max(0, count-height)
|
||||
t.cy = Max(0, Min(t.offset+diffpos, count-1))
|
||||
t.offset = util.Max(0, count-height)
|
||||
t.cy = util.Constrain(t.offset+diffpos, 0, count-1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -614,7 +617,7 @@ func (t *Terminal) vmove(o int) {
|
||||
}
|
||||
|
||||
func (t *Terminal) vset(o int) bool {
|
||||
t.cy = Max(0, Min(o, t.merger.Length()-1))
|
||||
t.cy = util.Constrain(o, 0, t.merger.Length()-1)
|
||||
return t.cy == o
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
const rangeEllipsis = 0
|
||||
@ -180,7 +182,7 @@ func Transform(tokens []Token, withNth []Range) *Transformed {
|
||||
end += numTokens + 1
|
||||
}
|
||||
}
|
||||
minIdx = Max(0, begin-1)
|
||||
minIdx = util.Max(0, begin-1)
|
||||
for idx := begin; idx <= end; idx++ {
|
||||
if idx >= 1 && idx <= numTokens {
|
||||
part += *tokens[idx-1].text
|
||||
|
@ -1,4 +1,4 @@
|
||||
package fzf
|
||||
package util
|
||||
|
||||
import "sync"
|
||||
|
@ -1,4 +1,4 @@
|
||||
package fzf
|
||||
package util
|
||||
|
||||
import "testing"
|
||||
|
@ -1,7 +1,10 @@
|
||||
package fzf
|
||||
package util
|
||||
|
||||
import "sync"
|
||||
|
||||
// EventType is the type for fzf events
|
||||
type EventType int
|
||||
|
||||
// Events is a type that associates EventType to any data
|
||||
type Events map[EventType]interface{}
|
||||
|
@ -1,7 +1,17 @@
|
||||
package fzf
|
||||
package util
|
||||
|
||||
import "testing"
|
||||
|
||||
// fzf events
|
||||
const (
|
||||
EvtReadNew EventType = iota
|
||||
EvtReadFin
|
||||
EvtSearchNew
|
||||
EvtSearchProgress
|
||||
EvtSearchFin
|
||||
EvtClose
|
||||
)
|
||||
|
||||
func TestEventBox(t *testing.T) {
|
||||
eb := NewEventBox()
|
||||
|
@ -1,6 +1,12 @@
|
||||
package fzf
|
||||
package util
|
||||
|
||||
import "time"
|
||||
// #include <unistd.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Max returns the largest integer
|
||||
func Max(first int, items ...int) int {
|
||||
@ -21,15 +27,15 @@ func Max32(first int32, second int32) int32 {
|
||||
return second
|
||||
}
|
||||
|
||||
// Min returns the smallest integer
|
||||
func Min(first int, items ...int) int {
|
||||
min := first
|
||||
for _, item := range items {
|
||||
if item < min {
|
||||
min = item
|
||||
}
|
||||
// Constrain limits the given integer with the upper and lower bounds
|
||||
func Constrain(val int, min int, max int) int {
|
||||
if val < min {
|
||||
return min
|
||||
}
|
||||
return min
|
||||
if val > max {
|
||||
return max
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// DurWithin limits the given time.Duration with the upper and lower bounds
|
||||
@ -43,3 +49,8 @@ func DurWithin(
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// IsTty returns true is stdin is a terminal
|
||||
func IsTty() bool {
|
||||
return int(C.isatty(C.int(os.Stdin.Fd()))) != 0
|
||||
}
|
22
src/util/util_test.go
Normal file
22
src/util/util_test.go
Normal file
@ -0,0 +1,22 @@
|
||||
package util
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
if Max(-2, 5, 1, 4, 3) != 5 {
|
||||
t.Error("Invalid result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContrain(t *testing.T) {
|
||||
if Constrain(-3, -1, 3) != -1 {
|
||||
t.Error("Expected", -1)
|
||||
}
|
||||
if Constrain(2, -1, 3) != 2 {
|
||||
t.Error("Expected", 2)
|
||||
}
|
||||
|
||||
if Constrain(5, -1, 3) != 3 {
|
||||
t.Error("Expected", 3)
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package fzf
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
if Max(-2, 5, 1, 4, 3) != 5 {
|
||||
t.Error("Invalid result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMin(t *testing.T) {
|
||||
if Min(2, -3) != -3 {
|
||||
t.Error("Invalid result")
|
||||
}
|
||||
if Min(-2, 5, 1, 4, 3) != -2 {
|
||||
t.Error("Invalid result")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user