1// The MIT License (MIT)
2//
3// Copyright (c) 2016 Junegunn Choi
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21// THE SOFTWARE.
22
23package fzf
24
25import (
26 "bufio"
27 "io"
28 "os"
29 "sync/atomic"
30 "time"
31
32 "github.com/junegunn/fzf/src/util"
33)
34
35// Reader reads from command or standard input
36type Reader struct {
37 pusher func([]byte) bool
38 eventBox *util.EventBox
39 delimNil bool
40 event int32
41}
42
43// NewReader returns new Reader object
44func NewReader(pusher func([]byte) bool, eventBox *util.EventBox, delimNil bool) *Reader {
45 return &Reader{pusher, eventBox, delimNil, int32(EvtReady)}
46}
47
48func (r *Reader) startEventPoller() {
49 go func() {
50 ptr := &r.event
51 pollInterval := readerPollIntervalMin
52 for {
53 if atomic.CompareAndSwapInt32(ptr, int32(EvtReadNew), int32(EvtReady)) {
54 r.eventBox.Set(EvtReadNew, true)
55 pollInterval = readerPollIntervalMin
56 } else if atomic.LoadInt32(ptr) == int32(EvtReadFin) {
57 return
58 } else {
59 pollInterval += readerPollIntervalStep
60 if pollInterval > readerPollIntervalMax {
61 pollInterval = readerPollIntervalMax
62 }
63 }
64 time.Sleep(pollInterval)
65 }
66 }()
67}
68
69func (r *Reader) fin(success bool) {
70 atomic.StoreInt32(&r.event, int32(EvtReadFin))
71 r.eventBox.Set(EvtReadFin, success)
72}
73
74// ReadSource reads data from the default command or from standard input
75func (r *Reader) ReadSource() {
76 r.startEventPoller()
77 var success bool
78 if util.IsTty() {
79 cmd := os.Getenv("FZF_DEFAULT_COMMAND")
80 if len(cmd) == 0 {
81 // The default command for *nix requires bash
82 success = r.readFromCommand("bash", defaultCommand)
83 } else {
84 success = r.readFromCommand("sh", cmd)
85 }
86 } else {
87 success = r.readFromStdin()
88 }
89 r.fin(success)
90}
91
92func (r *Reader) feed(src io.Reader) {
93 delim := byte('\n')
94 if r.delimNil {
95 delim = '\000'
96 }
97 reader := bufio.NewReaderSize(src, readerBufferSize)
98 for {
99 // ReadBytes returns err != nil if and only if the returned data does not
100 // end in delim.
101 bytea, err := reader.ReadBytes(delim)
102 byteaLen := len(bytea)
103 if byteaLen > 0 || byteaLen > 0xFF {
104 if err == nil {
105 // get rid of carriage return if under Windows:
106 if util.IsWindows() && byteaLen >= 2 && bytea[byteaLen-2] == byte('\r') {
107 bytea = bytea[:byteaLen-2]
108 } else {
109 bytea = bytea[:byteaLen-1]
110 }
111 }
112 if r.pusher(bytea) {
113 atomic.StoreInt32(&r.event, int32(EvtReadNew))
114 }
115 }
116 if err != nil {
117 break
118 }
119 }
120}
121
122func (r *Reader) readFromStdin() bool {
123 r.feed(os.Stdin)
124 return true
125}
126
127func (r *Reader) readFromCommand(shell string, cmd string) bool {
128 listCommand := util.ExecCommandWith(shell, cmd)
129 out, err := listCommand.StdoutPipe()
130 if err != nil {
131 return false
132 }
133 err = listCommand.Start()
134 if err != nil {
135 return false
136 }
137 r.feed(out)
138 return listCommand.Wait() == nil
139}
140/*http://example.com*/
141import ('http://example.com')
142