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