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