summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/constants.go6
-rw-r--r--src/core.go15
-rw-r--r--src/curses/curses.go4
-rw-r--r--src/options.go8
-rw-r--r--src/terminal.go17
-rw-r--r--test/test_go.rb46
6 files changed, 76 insertions, 20 deletions
diff --git a/src/constants.go b/src/constants.go
index b2225f14..9a4fc29f 100644
--- a/src/constants.go
+++ b/src/constants.go
@@ -47,3 +47,9 @@ const (
EvtHeader
EvtClose
)
+
+const (
+ exitOk = 0
+ exitNoMatch = 1
+ exitError = 2
+)
diff --git a/src/core.go b/src/core.go
index 96bfdd4c..04b6eab7 100644
--- a/src/core.go
+++ b/src/core.go
@@ -56,7 +56,7 @@ func Run(opts *Options) {
if opts.Version {
fmt.Println(version)
- os.Exit(0)
+ os.Exit(exitOk)
}
// Event channel
@@ -156,12 +156,14 @@ func Run(opts *Options) {
pattern := patternBuilder([]rune(*opts.Filter))
+ found := false
if streamingFilter {
reader := Reader{
func(runes []byte) bool {
item := chunkList.trans(runes, 0)
if item != nil && pattern.MatchItem(item) {
fmt.Println(string(item.text))
+ found = true
}
return false
}, eventBox, opts.ReadZero}
@@ -176,9 +178,13 @@ func Run(opts *Options) {
pattern: pattern})
for i := 0; i < merger.Length(); i++ {
fmt.Println(merger.Get(i).AsString(opts.Ansi))
+ found = true
}
}
- os.Exit(0)
+ if found {
+ os.Exit(exitOk)
+ }
+ os.Exit(exitNoMatch)
}
// Synchronous search
@@ -253,7 +259,10 @@ func Run(opts *Options) {
for i := 0; i < count; i++ {
fmt.Println(val.Get(i).AsString(opts.Ansi))
}
- os.Exit(0)
+ if count > 0 {
+ os.Exit(exitOk)
+ }
+ os.Exit(exitNoMatch)
}
deferred = false
terminal.startChan <- true
diff --git a/src/curses/curses.go b/src/curses/curses.go
index 3de8e982..59cea3b0 100644
--- a/src/curses/curses.go
+++ b/src/curses/curses.go
@@ -261,7 +261,7 @@ func Init(theme *ColorTheme, black bool, mouse bool) {
_screen = C.newterm(nil, C.stderr, C.stdin)
if _screen == nil {
fmt.Println("Invalid $TERM: " + os.Getenv("TERM"))
- os.Exit(1)
+ os.Exit(2)
}
C.set_term(_screen)
if mouse {
@@ -275,7 +275,7 @@ func Init(theme *ColorTheme, black bool, mouse bool) {
go func() {
<-intChan
Close()
- os.Exit(1)
+ os.Exit(2)
}()
if theme != nil {
diff --git a/src/options.go b/src/options.go
index 70900660..47d8bb11 100644
--- a/src/options.go
+++ b/src/options.go
@@ -180,14 +180,14 @@ func defaultOptions() *Options {
Version: false}
}
-func help(ok int) {
+func help(code int) {
os.Stderr.WriteString(usage)
- os.Exit(ok)
+ os.Exit(code)
}
func errorExit(msg string) {
os.Stderr.WriteString(msg + "\n")
- os.Exit(1)
+ os.Exit(exitError)
}
func optString(arg string, prefixes ...string) (bool, string) {
@@ -682,7 +682,7 @@ func parseOptions(opts *Options, allArgs []string) {
arg := allArgs[i]
switch arg {
case "-h", "--help":
- help(0)
+ help(exitOk)
case "-x", "--extended":
opts.Mode = ModeExtended
case "-e", "--extended-exact":
diff --git a/src/terminal.go b/src/terminal.go
index 053ed783..c3fb966b 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -280,17 +280,19 @@ func (t *Terminal) UpdateList(merger *Merger) {
t.reqBox.Set(reqList, nil)
}
-func (t *Terminal) output() {
+func (t *Terminal) output() bool {
if t.printQuery {
fmt.Println(string(t.input))
}
if len(t.expect) > 0 {
fmt.Println(t.pressed)
}
- if len(t.selected) == 0 {
+ found := len(t.selected) > 0
+ if !found {
cnt := t.merger.Length()
if cnt > 0 && cnt > t.cy {
fmt.Println(t.merger.Get(t.cy).AsString(t.ansi))
+ found = true
}
} else {
sels := make([]selectedItem, 0, len(t.selected))
@@ -302,6 +304,7 @@ func (t *Terminal) output() {
fmt.Println(*sel.text)
}
}
+ return found
}
func runeWidth(r rune, prefixWidth int) int {
@@ -743,7 +746,7 @@ func (t *Terminal) Loop() {
}
exit := func(code int) {
- if code == 0 && t.history != nil {
+ if code <= exitNoMatch && t.history != nil {
t.history.append(string(t.input))
}
os.Exit(code)
@@ -776,11 +779,13 @@ func (t *Terminal) Loop() {
t.printAll()
case reqClose:
C.Close()
- t.output()
- exit(0)
+ if t.output() {
+ exit(exitOk)
+ }
+ exit(exitNoMatch)
case reqQuit:
C.Close()
- exit(1)
+ exit(exitError)
}
}
t.placeCursor()
diff --git a/test/test_go.rb b/test/test_go.rb
index d1f45dc1..5b352647 100644
--- a/test/test_go.rb
+++ b/test/test_go.rb
@@ -780,11 +780,6 @@ class TestGoFZF < TestBase
tmux.send_keys :Enter
end
- def test_invalid_term
- tmux.send_keys "TERM=xxx fzf", :Enter
- tmux.until { |lines| lines.any? { |l| l.include? 'Invalid $TERM: xxx' } }
- end
-
def test_with_nth
writelines tempname, ['hello world ', 'byebye']
assert_equal 'hello world ', `cat #{tempname} | #{FZF} -f"^he hehe" -x -n 2.. --with-nth 2,1,1`.chomp
@@ -801,6 +796,47 @@ class TestGoFZF < TestBase
assert_equal src, `cat #{tempname} | #{FZF} -fhehe -x -n 2.. --with-nth 2,1,1 --no-ansi`.chomp
end
+ def test_exit_0_exit_code
+ `echo foo | #{FZF} -q bar -0`
+ assert_equal 1, $?.exitstatus
+ end
+
+ def test_invalid_term
+ lines = `TERM=xxx #{FZF}`
+ assert_equal 2, $?.exitstatus
+ assert lines.include?('Invalid $TERM: xxx')
+ end
+
+ def test_invalid_option
+ lines = `#{FZF} --foobar 2>&1`
+ assert_equal 2, $?.exitstatus
+ assert lines.include?('unknown option: --foobar'), lines
+ end
+
+ def test_filter_exitstatus
+ # filter / streaming filter
+ ["", "--no-sort"].each do |opts|
+ assert `echo foo | #{FZF} -f foo #{opts}`.include?('foo')
+ assert_equal 0, $?.exitstatus
+
+ assert `echo foo | #{FZF} -f bar #{opts}`.empty?
+ assert_equal 1, $?.exitstatus
+ end
+ end
+
+ def test_exitstatus_empty
+ { '99' => '0', '999' => '1' }.each do |query, status|
+ tmux.send_keys "seq 100 | #{FZF} -q #{query}", :Enter
+ tmux.until { |lines| lines[-2] =~ %r{ [10]/100} }
+ tmux.send_keys :Enter
+
+ tmux.send_keys 'echo --\$?--'
+ tmux.until { |lines| lines.last.include? "echo --$?--" }
+ tmux.send_keys :Enter
+ tmux.until { |lines| lines.last.include? "--#{status}--" }
+ end
+ end
+
private
def writelines path, lines
File.unlink path while File.exists? path