m/fzf
1
0
mirror of https://github.com/junegunn/fzf.git synced 2025-11-17 07:43:39 -05:00

Add --header-lines option

This commit is contained in:
Junegunn Choi
2015-07-22 03:21:20 +09:00
parent 18469b6954
commit f469c25730
8 changed files with 143 additions and 77 deletions

View File

@@ -26,8 +26,13 @@ func NewChunkList(trans ItemBuilder) *ChunkList {
trans: trans}
}
func (c *Chunk) push(trans ItemBuilder, data *string, index int) {
*c = append(*c, trans(data, index))
func (c *Chunk) push(trans ItemBuilder, data *string, index int) bool {
item := trans(data, index)
if item != nil {
*c = append(*c, item)
return true
}
return false
}
// IsFull returns true if the Chunk is full
@@ -48,7 +53,7 @@ func CountItems(cs []*Chunk) int {
}
// Push adds the item to the list
func (cl *ChunkList) Push(data string) {
func (cl *ChunkList) Push(data string) bool {
cl.mutex.Lock()
defer cl.mutex.Unlock()
@@ -57,8 +62,11 @@ func (cl *ChunkList) Push(data string) {
cl.chunks = append(cl.chunks, &newChunk)
}
cl.lastChunk().push(cl.trans, &data, cl.count)
cl.count++
if cl.lastChunk().push(cl.trans, &data, cl.count) {
cl.count++
return true
}
return false
}
// Snapshot returns immutable snapshot of the ChunkList

View File

@@ -44,5 +44,6 @@ const (
EvtSearchNew
EvtSearchProgress
EvtSearchFin
EvtHeader
EvtClose
)

View File

@@ -44,6 +44,7 @@ Reader -> EvtReadNew -> Matcher (restart)
Terminal -> EvtSearchNew:bool -> Matcher (restart)
Matcher -> EvtSearchProgress -> Terminal (update info)
Matcher -> EvtSearchFin -> Terminal (update list)
Matcher -> EvtHeader -> Terminal (update header)
*/
// Run starts fzf
@@ -83,8 +84,14 @@ func Run(opts *Options) {
// Chunk list
var chunkList *ChunkList
header := make([]string, 0, opts.HeaderLines)
if len(opts.WithNth) == 0 {
chunkList = NewChunkList(func(data *string, index int) *Item {
if len(header) < opts.HeaderLines {
header = append(header, *data)
eventBox.Set(EvtHeader, header)
return nil
}
data, colors := ansiProcessor(data)
return &Item{
text: data,
@@ -94,6 +101,11 @@ func Run(opts *Options) {
})
} else {
chunkList = NewChunkList(func(data *string, index int) *Item {
if len(header) < opts.HeaderLines {
header = append(header, *data)
eventBox.Set(EvtHeader, header)
return nil
}
tokens := Tokenize(data, opts.Delimiter)
trans := Transform(tokens, opts.WithNth)
item := Item{
@@ -113,7 +125,9 @@ func Run(opts *Options) {
// Reader
streamingFilter := opts.Filter != nil && !sort && !opts.Tac && !opts.Sync
if !streamingFilter {
reader := Reader{func(str string) { chunkList.Push(str) }, eventBox, opts.ReadZero}
reader := Reader{func(str string) bool {
return chunkList.Push(str)
}, eventBox, opts.ReadZero}
go reader.ReadSource()
}
@@ -134,11 +148,12 @@ func Run(opts *Options) {
if streamingFilter {
reader := Reader{
func(str string) {
func(str string) bool {
item := chunkList.trans(&str, 0)
if pattern.MatchItem(item) {
if item != nil && pattern.MatchItem(item) {
fmt.Println(*item.text)
}
return false
}, eventBox, opts.ReadZero}
reader.ReadSource()
} else {
@@ -206,6 +221,9 @@ func Run(opts *Options) {
terminal.UpdateProgress(val)
}
case EvtHeader:
terminal.UpdateHeader(value.([]string), opts.HeaderLines)
case EvtSearchFin:
switch val := value.(type) {
case *Merger:

View File

@@ -46,6 +46,7 @@ const usage = `usage: fzf [options]
--history=FILE History file
--history-size=N Maximum number of history entries (default: 1000)
--header-file=FILE The file whose content to be printed as header
--header-lines=N The first N lines of the input are treated as header
Scripting
-q, --query=STR Start the finder with the given query
@@ -94,38 +95,39 @@ const (
// Options stores the values of command-line options
type Options struct {
Mode Mode
Case Case
Nth []Range
WithNth []Range
Delimiter *regexp.Regexp
Sort int
Tac bool
Tiebreak tiebreak
Multi bool
Ansi bool
Mouse bool
Theme *curses.ColorTheme
Black bool
Reverse bool
Cycle bool
Hscroll bool
InlineInfo bool
Prompt string
Query string
Select1 bool
Exit0 bool
Filter *string
ToggleSort bool
Expect map[int]string
Keymap map[int]actionType
Execmap map[int]string
PrintQuery bool
ReadZero bool
Sync bool
History *History
Header []string
Version bool
Mode Mode
Case Case
Nth []Range
WithNth []Range
Delimiter *regexp.Regexp
Sort int
Tac bool
Tiebreak tiebreak
Multi bool
Ansi bool
Mouse bool
Theme *curses.ColorTheme
Black bool
Reverse bool
Cycle bool
Hscroll bool
InlineInfo bool
Prompt string
Query string
Select1 bool
Exit0 bool
Filter *string
ToggleSort bool
Expect map[int]string
Keymap map[int]actionType
Execmap map[int]string
PrintQuery bool
ReadZero bool
Sync bool
History *History
Header []string
HeaderLines int
Version bool
}
func defaultTheme() *curses.ColorTheme {
@@ -137,38 +139,39 @@ func defaultTheme() *curses.ColorTheme {
func defaultOptions() *Options {
return &Options{
Mode: ModeFuzzy,
Case: CaseSmart,
Nth: make([]Range, 0),
WithNth: make([]Range, 0),
Delimiter: nil,
Sort: 1000,
Tac: false,
Tiebreak: byLength,
Multi: false,
Ansi: false,
Mouse: true,
Theme: defaultTheme(),
Black: false,
Reverse: false,
Cycle: false,
Hscroll: true,
InlineInfo: false,
Prompt: "> ",
Query: "",
Select1: false,
Exit0: false,
Filter: nil,
ToggleSort: false,
Expect: make(map[int]string),
Keymap: defaultKeymap(),
Execmap: make(map[int]string),
PrintQuery: false,
ReadZero: false,
Sync: false,
History: nil,
Header: make([]string, 0),
Version: false}
Mode: ModeFuzzy,
Case: CaseSmart,
Nth: make([]Range, 0),
WithNth: make([]Range, 0),
Delimiter: nil,
Sort: 1000,
Tac: false,
Tiebreak: byLength,
Multi: false,
Ansi: false,
Mouse: true,
Theme: defaultTheme(),
Black: false,
Reverse: false,
Cycle: false,
Hscroll: true,
InlineInfo: false,
Prompt: "> ",
Query: "",
Select1: false,
Exit0: false,
Filter: nil,
ToggleSort: false,
Expect: make(map[int]string),
Keymap: defaultKeymap(),
Execmap: make(map[int]string),
PrintQuery: false,
ReadZero: false,
Sync: false,
History: nil,
Header: make([]string, 0),
HeaderLines: 0,
Version: false}
}
func help(ok int) {
@@ -724,9 +727,18 @@ func parseOptions(opts *Options, allArgs []string) {
setHistory(nextString(allArgs, &i, "history file path required"))
case "--history-size":
setHistoryMax(nextInt(allArgs, &i, "history max size required"))
case "--no-header-file":
opts.Header = []string{}
case "--no-header-lines":
opts.HeaderLines = 0
case "--header-file":
opts.Header = readHeaderFile(
nextString(allArgs, &i, "header file name required"))
opts.HeaderLines = 0
case "--header-lines":
opts.Header = []string{}
opts.HeaderLines = atoi(
nextString(allArgs, &i, "number of header lines required"))
case "--version":
opts.Version = true
default:
@@ -762,6 +774,10 @@ func parseOptions(opts *Options, allArgs []string) {
setHistoryMax(atoi(value))
} else if match, value := optString(arg, "--header-file="); match {
opts.Header = readHeaderFile(value)
opts.HeaderLines = 0
} else if match, value := optString(arg, "--header-lines="); match {
opts.Header = []string{}
opts.HeaderLines = atoi(value)
} else {
errorExit("unknown option: " + arg)
}

View File

@@ -11,7 +11,7 @@ import (
// Reader reads from command or standard input
type Reader struct {
pusher func(string)
pusher func(string) bool
eventBox *util.EventBox
delimNil bool
}
@@ -43,8 +43,9 @@ func (r *Reader) feed(src io.Reader) {
if err == nil {
line = line[:len(line)-1]
}
r.pusher(line)
r.eventBox.Set(EvtReadNew, nil)
if r.pusher(line) {
r.eventBox.Set(EvtReadNew, nil)
}
}
if err != nil {
break

View File

@@ -10,7 +10,7 @@ func TestReadFromCommand(t *testing.T) {
strs := []string{}
eb := util.NewEventBox()
reader := Reader{
pusher: func(s string) { strs = append(strs, s) },
pusher: func(s string) bool { strs = append(strs, s); return true },
eventBox: eb}
// Check EventBox

View File

@@ -79,6 +79,7 @@ var _runeWidths = make(map[rune]int)
const (
reqPrompt util.EventType = iota
reqInfo
reqHeader
reqList
reqRefresh
reqRedraw
@@ -231,6 +232,22 @@ func (t *Terminal) UpdateCount(cnt int, final bool) {
}
}
// UpdateHeader updates the header
func (t *Terminal) UpdateHeader(header []string, lines int) {
t.mutex.Lock()
t.header = make([]string, lines)
copy(t.header, header)
if !t.reverse {
reversed := make([]string, lines)
for idx, str := range t.header {
reversed[lines-idx-1] = str
}
t.header = reversed
}
t.mutex.Unlock()
t.reqBox.Set(reqHeader, nil)
}
// UpdateProgress updates the search progress
func (t *Terminal) UpdateProgress(progress float32) {
t.mutex.Lock()
@@ -686,6 +703,8 @@ func (t *Terminal) Loop() {
t.printInfo()
case reqList:
t.printList()
case reqHeader:
t.printHeader()
case reqRefresh:
t.suppress = false
case reqRedraw: