Move functionality of edit/search.go to util.

This commit is contained in:
Qi Xiao 2016-02-21 14:32:13 +01:00
parent d76bb34592
commit d2d119af7f
5 changed files with 78 additions and 47 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/elves/elvish/eval"
"github.com/elves/elvish/parse"
"github.com/elves/elvish/util"
)
// A completer takes the current node
@ -86,7 +87,7 @@ func complFormHead(cn *parse.Compound, head string, ed *Editor) []*candidate {
}
func complFormHeadInner(head string, ed *Editor) []*candidate {
if eval.DontSearch(head) {
if util.DontSearch(head) {
return complArgInner(head, ed, true)
}

View File

@ -3,6 +3,7 @@ package edit
import (
"github.com/elves/elvish/eval"
"github.com/elves/elvish/parse"
"github.com/elves/elvish/util"
)
// stylist takes a Node and Editor, and returns a style string. The Node is
@ -29,9 +30,9 @@ func colorFormHead(n parse.Node, ed *Editor) string {
func goodFormHead(head string, ed *Editor) bool {
if isBuiltinSpecial[head] {
return true
} else if eval.DontSearch(head) {
} else if util.DontSearch(head) {
// XXX don't stat twice
return eval.IsExecutable(head) || isDir(head)
return util.IsExecutable(head) || isDir(head)
} else {
return ed.evaler.Global()[eval.FnPrefix+head] != nil ||
ed.isExternal[head]

View File

@ -5,6 +5,8 @@ import (
"fmt"
"os"
"syscall"
"github.com/elves/elvish/util"
)
// FdNil is a special impossible fd value used for "close fd" in
@ -28,7 +30,7 @@ func (e ExternalCmd) Repr(int) string {
// Call calls an external command.
func (e ExternalCmd) Call(ec *EvalCtx, argVals []Value) {
if DontSearch(e.Name) {
if util.DontSearch(e.Name) {
stat, err := os.Stat(e.Name)
if err == nil && stat.IsDir() {
// implicit cd

View File

@ -2,60 +2,23 @@ package eval
import (
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/elves/elvish/parse"
"github.com/elves/elvish/util"
)
// Search tries to resolve an external command and return the full (possibly
// relative) path.
func (ev *Evaler) Search(exe string) (string, error) {
if DontSearch(exe) {
if IsExecutable(exe) {
return exe, nil
}
return "", fmt.Errorf("external command %s not executable", parse.Quote(exe))
path, err := util.Search(ev.searchPaths(), exe)
if err != nil {
return "", fmt.Errorf("search %s: %s", parse.Quote(exe), err.Error())
}
for _, p := range ev.searchPaths() {
full := p + "/" + exe
if IsExecutable(full) {
return full, nil
}
}
return "", fmt.Errorf("external command %s not found", parse.Quote(exe))
return path, nil
}
// AllExecutables writes the names of all executable files in the search path
// to a channel.
func (ev *Evaler) AllExecutables(names chan<- string) {
for _, dir := range ev.searchPaths() {
// XXX Ignore error
infos, _ := ioutil.ReadDir(dir)
for _, info := range infos {
if !info.IsDir() && (info.Mode()&0111 != 0) {
names <- info.Name()
}
}
}
}
// DontSearch determines whether the path to an external command should be
// taken literally and not searched.
func DontSearch(exe string) bool {
return exe == ".." ||
strings.HasPrefix(exe, "/") ||
strings.HasPrefix(exe, "./") ||
strings.HasPrefix(exe, "../")
}
// IsExecutable determines whether path refers to an executable file.
func IsExecutable(path string) bool {
fi, err := os.Stat(path)
if err != nil {
return false
}
fm := fi.Mode()
return !fm.IsDir() && (fm&0111 != 0)
util.AllExecutables(ev.searchPaths(), names)
}

64
util/search.go Normal file
View File

@ -0,0 +1,64 @@
package util
import (
"errors"
"io/ioutil"
"os"
"strings"
)
var (
ErrNotExecutable = errors.New("not executable")
ErrNotFound = errors.New("not found")
)
// Search tries to resolve an external command and return the full (possibly
// relative) path.
func Search(paths []string, exe string) (string, error) {
if DontSearch(exe) {
if IsExecutable(exe) {
return exe, nil
}
return "", ErrNotExecutable
}
for _, p := range paths {
full := p + "/" + exe
if IsExecutable(full) {
return full, nil
}
}
return "", ErrNotFound
}
// AllExecutables writes the names of all executable files in the search path
// to a channel.
func AllExecutables(paths []string, names chan<- string) {
for _, dir := range paths {
// XXX Ignore error
infos, _ := ioutil.ReadDir(dir)
for _, info := range infos {
if !info.IsDir() && (info.Mode()&0111 != 0) {
names <- info.Name()
}
}
}
}
// DontSearch determines whether the path to an external command should be
// taken literally and not searched.
func DontSearch(exe string) bool {
return exe == ".." ||
strings.HasPrefix(exe, "/") ||
strings.HasPrefix(exe, "./") ||
strings.HasPrefix(exe, "../")
}
// IsExecutable determines whether path refers to an executable file.
func IsExecutable(path string) bool {
fi, err := os.Stat(path)
if err != nil {
return false
}
fm := fi.Mode()
return !fm.IsDir() && (fm&0111 != 0)
}