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