Change exit status (0: OK, 1: No match, 2: Error/Interrupted)
A la grep. Close #345
This commit is contained in:
parent
fa2f9f1f21
commit
65d9d416b4
@ -47,3 +47,9 @@ const (
|
|||||||
EvtHeader
|
EvtHeader
|
||||||
EvtClose
|
EvtClose
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
exitOk = 0
|
||||||
|
exitNoMatch = 1
|
||||||
|
exitError = 2
|
||||||
|
)
|
||||||
|
15
src/core.go
15
src/core.go
@ -56,7 +56,7 @@ func Run(opts *Options) {
|
|||||||
|
|
||||||
if opts.Version {
|
if opts.Version {
|
||||||
fmt.Println(version)
|
fmt.Println(version)
|
||||||
os.Exit(0)
|
os.Exit(exitOk)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event channel
|
// Event channel
|
||||||
@ -156,12 +156,14 @@ func Run(opts *Options) {
|
|||||||
|
|
||||||
pattern := patternBuilder([]rune(*opts.Filter))
|
pattern := patternBuilder([]rune(*opts.Filter))
|
||||||
|
|
||||||
|
found := false
|
||||||
if streamingFilter {
|
if streamingFilter {
|
||||||
reader := Reader{
|
reader := Reader{
|
||||||
func(runes []byte) bool {
|
func(runes []byte) bool {
|
||||||
item := chunkList.trans(runes, 0)
|
item := chunkList.trans(runes, 0)
|
||||||
if item != nil && pattern.MatchItem(item) {
|
if item != nil && pattern.MatchItem(item) {
|
||||||
fmt.Println(string(item.text))
|
fmt.Println(string(item.text))
|
||||||
|
found = true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}, eventBox, opts.ReadZero}
|
}, eventBox, opts.ReadZero}
|
||||||
@ -176,9 +178,13 @@ func Run(opts *Options) {
|
|||||||
pattern: pattern})
|
pattern: pattern})
|
||||||
for i := 0; i < merger.Length(); i++ {
|
for i := 0; i < merger.Length(); i++ {
|
||||||
fmt.Println(merger.Get(i).AsString(opts.Ansi))
|
fmt.Println(merger.Get(i).AsString(opts.Ansi))
|
||||||
|
found = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
os.Exit(0)
|
if found {
|
||||||
|
os.Exit(exitOk)
|
||||||
|
}
|
||||||
|
os.Exit(exitNoMatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synchronous search
|
// Synchronous search
|
||||||
@ -253,7 +259,10 @@ func Run(opts *Options) {
|
|||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
fmt.Println(val.Get(i).AsString(opts.Ansi))
|
fmt.Println(val.Get(i).AsString(opts.Ansi))
|
||||||
}
|
}
|
||||||
os.Exit(0)
|
if count > 0 {
|
||||||
|
os.Exit(exitOk)
|
||||||
|
}
|
||||||
|
os.Exit(exitNoMatch)
|
||||||
}
|
}
|
||||||
deferred = false
|
deferred = false
|
||||||
terminal.startChan <- true
|
terminal.startChan <- true
|
||||||
|
@ -261,7 +261,7 @@ func Init(theme *ColorTheme, black bool, mouse bool) {
|
|||||||
_screen = C.newterm(nil, C.stderr, C.stdin)
|
_screen = C.newterm(nil, C.stderr, C.stdin)
|
||||||
if _screen == nil {
|
if _screen == nil {
|
||||||
fmt.Println("Invalid $TERM: " + os.Getenv("TERM"))
|
fmt.Println("Invalid $TERM: " + os.Getenv("TERM"))
|
||||||
os.Exit(1)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
C.set_term(_screen)
|
C.set_term(_screen)
|
||||||
if mouse {
|
if mouse {
|
||||||
@ -275,7 +275,7 @@ func Init(theme *ColorTheme, black bool, mouse bool) {
|
|||||||
go func() {
|
go func() {
|
||||||
<-intChan
|
<-intChan
|
||||||
Close()
|
Close()
|
||||||
os.Exit(1)
|
os.Exit(2)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if theme != nil {
|
if theme != nil {
|
||||||
|
@ -180,14 +180,14 @@ func defaultOptions() *Options {
|
|||||||
Version: false}
|
Version: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
func help(ok int) {
|
func help(code int) {
|
||||||
os.Stderr.WriteString(usage)
|
os.Stderr.WriteString(usage)
|
||||||
os.Exit(ok)
|
os.Exit(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func errorExit(msg string) {
|
func errorExit(msg string) {
|
||||||
os.Stderr.WriteString(msg + "\n")
|
os.Stderr.WriteString(msg + "\n")
|
||||||
os.Exit(1)
|
os.Exit(exitError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func optString(arg string, prefixes ...string) (bool, string) {
|
func optString(arg string, prefixes ...string) (bool, string) {
|
||||||
@ -682,7 +682,7 @@ func parseOptions(opts *Options, allArgs []string) {
|
|||||||
arg := allArgs[i]
|
arg := allArgs[i]
|
||||||
switch arg {
|
switch arg {
|
||||||
case "-h", "--help":
|
case "-h", "--help":
|
||||||
help(0)
|
help(exitOk)
|
||||||
case "-x", "--extended":
|
case "-x", "--extended":
|
||||||
opts.Mode = ModeExtended
|
opts.Mode = ModeExtended
|
||||||
case "-e", "--extended-exact":
|
case "-e", "--extended-exact":
|
||||||
|
@ -280,17 +280,19 @@ func (t *Terminal) UpdateList(merger *Merger) {
|
|||||||
t.reqBox.Set(reqList, nil)
|
t.reqBox.Set(reqList, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) output() {
|
func (t *Terminal) output() bool {
|
||||||
if t.printQuery {
|
if t.printQuery {
|
||||||
fmt.Println(string(t.input))
|
fmt.Println(string(t.input))
|
||||||
}
|
}
|
||||||
if len(t.expect) > 0 {
|
if len(t.expect) > 0 {
|
||||||
fmt.Println(t.pressed)
|
fmt.Println(t.pressed)
|
||||||
}
|
}
|
||||||
if len(t.selected) == 0 {
|
found := len(t.selected) > 0
|
||||||
|
if !found {
|
||||||
cnt := t.merger.Length()
|
cnt := t.merger.Length()
|
||||||
if cnt > 0 && cnt > t.cy {
|
if cnt > 0 && cnt > t.cy {
|
||||||
fmt.Println(t.merger.Get(t.cy).AsString(t.ansi))
|
fmt.Println(t.merger.Get(t.cy).AsString(t.ansi))
|
||||||
|
found = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sels := make([]selectedItem, 0, len(t.selected))
|
sels := make([]selectedItem, 0, len(t.selected))
|
||||||
@ -302,6 +304,7 @@ func (t *Terminal) output() {
|
|||||||
fmt.Println(*sel.text)
|
fmt.Println(*sel.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
func runeWidth(r rune, prefixWidth int) int {
|
func runeWidth(r rune, prefixWidth int) int {
|
||||||
@ -743,7 +746,7 @@ func (t *Terminal) Loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exit := func(code int) {
|
exit := func(code int) {
|
||||||
if code == 0 && t.history != nil {
|
if code <= exitNoMatch && t.history != nil {
|
||||||
t.history.append(string(t.input))
|
t.history.append(string(t.input))
|
||||||
}
|
}
|
||||||
os.Exit(code)
|
os.Exit(code)
|
||||||
@ -776,11 +779,13 @@ func (t *Terminal) Loop() {
|
|||||||
t.printAll()
|
t.printAll()
|
||||||
case reqClose:
|
case reqClose:
|
||||||
C.Close()
|
C.Close()
|
||||||
t.output()
|
if t.output() {
|
||||||
exit(0)
|
exit(exitOk)
|
||||||
|
}
|
||||||
|
exit(exitNoMatch)
|
||||||
case reqQuit:
|
case reqQuit:
|
||||||
C.Close()
|
C.Close()
|
||||||
exit(1)
|
exit(exitError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.placeCursor()
|
t.placeCursor()
|
||||||
|
@ -780,11 +780,6 @@ class TestGoFZF < TestBase
|
|||||||
tmux.send_keys :Enter
|
tmux.send_keys :Enter
|
||||||
end
|
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
|
def test_with_nth
|
||||||
writelines tempname, ['hello world ', 'byebye']
|
writelines tempname, ['hello world ', 'byebye']
|
||||||
assert_equal 'hello world ', `cat #{tempname} | #{FZF} -f"^he hehe" -x -n 2.. --with-nth 2,1,1`.chomp
|
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
|
assert_equal src, `cat #{tempname} | #{FZF} -fhehe -x -n 2.. --with-nth 2,1,1 --no-ansi`.chomp
|
||||||
end
|
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
|
private
|
||||||
def writelines path, lines
|
def writelines path, lines
|
||||||
File.unlink path while File.exists? path
|
File.unlink path while File.exists? path
|
||||||
|
Loading…
Reference in New Issue
Block a user