2016-08-15 20:29:37 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"os"
|
2016-09-06 20:05:18 +00:00
|
|
|
"path/filepath"
|
2016-09-12 20:33:52 +00:00
|
|
|
"sort"
|
2016-08-15 20:29:37 +00:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2016-09-12 20:33:52 +00:00
|
|
|
gCmdWords = []string{
|
|
|
|
"set",
|
|
|
|
"map",
|
|
|
|
"cmd",
|
|
|
|
"up",
|
|
|
|
"half-up",
|
|
|
|
"page-up",
|
|
|
|
"down",
|
|
|
|
"half-down",
|
|
|
|
"page-down",
|
|
|
|
"updir",
|
|
|
|
"open",
|
|
|
|
"quit",
|
|
|
|
"bot",
|
|
|
|
"top",
|
|
|
|
"read",
|
|
|
|
"read-shell",
|
|
|
|
"read-shell-wait",
|
|
|
|
"read-shell-async",
|
|
|
|
"search",
|
|
|
|
"search-back",
|
|
|
|
"toggle",
|
2016-10-09 16:07:57 +00:00
|
|
|
"invert",
|
2016-09-12 20:33:52 +00:00
|
|
|
"yank",
|
|
|
|
"delete",
|
2016-11-06 15:09:18 +00:00
|
|
|
"put",
|
2016-09-12 20:33:52 +00:00
|
|
|
"renew",
|
2016-11-08 21:39:39 +00:00
|
|
|
"sync",
|
2016-09-12 20:33:52 +00:00
|
|
|
"echo",
|
|
|
|
"cd",
|
2016-09-18 16:21:24 +00:00
|
|
|
"push",
|
2016-09-12 20:33:52 +00:00
|
|
|
}
|
|
|
|
|
2016-08-15 20:29:37 +00:00
|
|
|
gOptWords = []string{
|
2016-11-21 20:13:33 +00:00
|
|
|
"dirfirst",
|
|
|
|
"nodirfirst",
|
|
|
|
"dirfirst!",
|
2016-08-15 20:29:37 +00:00
|
|
|
"hidden",
|
|
|
|
"nohidden",
|
2016-08-16 20:13:57 +00:00
|
|
|
"hidden!",
|
2016-08-27 11:12:03 +00:00
|
|
|
"preview",
|
|
|
|
"nopreview",
|
|
|
|
"preview!",
|
2016-08-15 20:29:37 +00:00
|
|
|
"scrolloff",
|
2016-08-27 11:12:03 +00:00
|
|
|
"tabstop",
|
|
|
|
"ifs",
|
2016-08-28 12:04:57 +00:00
|
|
|
"previewer",
|
2016-08-27 11:12:03 +00:00
|
|
|
"shell",
|
2016-08-15 20:29:37 +00:00
|
|
|
"showinfo",
|
2016-08-27 11:12:03 +00:00
|
|
|
"sortby",
|
2016-11-21 20:13:33 +00:00
|
|
|
"timefmt",
|
2016-08-15 20:29:37 +00:00
|
|
|
"ratios",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2016-08-16 20:13:57 +00:00
|
|
|
func matchLongest(s1, s2 string) string {
|
|
|
|
i := 0
|
|
|
|
for ; i < len(s1) && i < len(s2); i++ {
|
|
|
|
if s1[i] != s2[i] {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return s1[:i]
|
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
func matchWord(s string, words []string) (matches []string, longest string) {
|
2016-08-15 20:29:37 +00:00
|
|
|
for _, w := range words {
|
|
|
|
if strings.HasPrefix(w, s) {
|
2016-08-21 15:41:03 +00:00
|
|
|
matches = append(matches, w)
|
|
|
|
if longest != "" {
|
|
|
|
longest = matchLongest(longest, w)
|
2016-09-12 20:33:52 +00:00
|
|
|
} else if s != "" {
|
2016-08-21 15:41:03 +00:00
|
|
|
longest = w + " "
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
if longest == "" {
|
|
|
|
longest = s
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
return
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
func matchExec(s string) (matches []string, longest string) {
|
2016-09-12 20:33:52 +00:00
|
|
|
var words []string
|
|
|
|
|
2016-08-16 19:31:17 +00:00
|
|
|
paths := strings.Split(envPath, ":")
|
|
|
|
|
|
|
|
for _, p := range paths {
|
2016-08-16 20:18:26 +00:00
|
|
|
if _, err := os.Stat(p); os.IsNotExist(err) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2016-08-16 19:31:17 +00:00
|
|
|
fi, err := ioutil.ReadDir(p)
|
|
|
|
if err != nil {
|
2016-08-17 19:42:36 +00:00
|
|
|
log.Printf("reading path: %s", err)
|
2016-08-16 19:31:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, f := range fi {
|
|
|
|
if strings.HasPrefix(f.Name(), s) {
|
2016-09-06 20:05:18 +00:00
|
|
|
f, err = os.Stat(filepath.Join(p, f.Name()))
|
2016-08-16 20:17:19 +00:00
|
|
|
if err != nil {
|
2016-08-17 19:42:36 +00:00
|
|
|
log.Printf("getting file information: %s", err)
|
2016-08-16 20:17:19 +00:00
|
|
|
}
|
|
|
|
|
2016-08-16 19:31:17 +00:00
|
|
|
if !f.Mode().IsRegular() || f.Mode()&0111 == 0 {
|
|
|
|
continue
|
|
|
|
}
|
2016-08-21 15:41:03 +00:00
|
|
|
|
2016-09-12 20:33:52 +00:00
|
|
|
words = append(words, f.Name())
|
2016-08-16 19:31:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-12 20:33:52 +00:00
|
|
|
sort.Strings(words)
|
|
|
|
|
|
|
|
if len(words) > 0 {
|
|
|
|
uniq := words[:1]
|
|
|
|
for i := 1; i < len(words); i++ {
|
|
|
|
if words[i] != words[i-1] {
|
|
|
|
uniq = append(uniq, words[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
words = uniq
|
2016-08-16 19:31:17 +00:00
|
|
|
}
|
|
|
|
|
2016-09-12 20:33:52 +00:00
|
|
|
return matchWord(s, words)
|
2016-08-16 19:31:17 +00:00
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
func matchFile(s string) (matches []string, longest string) {
|
2016-08-26 20:25:40 +00:00
|
|
|
dir := strings.Replace(s, "~", envHome, -1)
|
|
|
|
|
2016-09-06 20:05:18 +00:00
|
|
|
if !filepath.IsAbs(dir) {
|
2016-08-26 20:25:40 +00:00
|
|
|
wd, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("getting current directory: %s", err)
|
|
|
|
}
|
2016-09-06 20:05:18 +00:00
|
|
|
dir = wd + string(filepath.Separator) + dir
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:28:25 +00:00
|
|
|
dir = unescape(filepath.Dir(dir))
|
2016-08-26 20:25:40 +00:00
|
|
|
|
|
|
|
fi, err := ioutil.ReadDir(dir)
|
2016-08-15 20:29:37 +00:00
|
|
|
if err != nil {
|
2016-08-17 19:42:36 +00:00
|
|
|
log.Printf("reading directory: %s", err)
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, f := range fi {
|
2016-09-06 20:05:18 +00:00
|
|
|
f, err := os.Stat(filepath.Join(dir, f.Name()))
|
2016-08-26 20:25:40 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("getting file information: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-09-06 20:05:18 +00:00
|
|
|
_, last := filepath.Split(s)
|
2016-12-02 21:28:25 +00:00
|
|
|
if strings.HasPrefix(escape(f.Name()), last) {
|
2016-08-26 20:25:40 +00:00
|
|
|
name := f.Name()
|
2016-09-06 20:05:18 +00:00
|
|
|
if isRoot(s) || filepath.Base(s) != s {
|
|
|
|
name = filepath.Join(filepath.Dir(s), f.Name())
|
2016-08-26 20:25:40 +00:00
|
|
|
}
|
2016-12-02 21:28:25 +00:00
|
|
|
name = escape(name)
|
2016-09-12 20:33:52 +00:00
|
|
|
item := f.Name()
|
|
|
|
if f.Mode().IsDir() {
|
|
|
|
item += string(filepath.Separator)
|
|
|
|
}
|
|
|
|
matches = append(matches, item)
|
2016-08-21 15:41:03 +00:00
|
|
|
if longest != "" {
|
2016-08-26 20:25:40 +00:00
|
|
|
longest = matchLongest(longest, name)
|
2016-09-12 20:33:52 +00:00
|
|
|
} else if s != "" {
|
2016-08-26 20:25:40 +00:00
|
|
|
if f.Mode().IsRegular() {
|
|
|
|
longest = name + " "
|
|
|
|
} else {
|
2016-09-06 20:05:18 +00:00
|
|
|
longest = name + string(filepath.Separator)
|
2016-08-26 20:25:40 +00:00
|
|
|
}
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
if longest == "" {
|
|
|
|
longest = s
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
return
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
func compCmd(acc []rune) (matches []string, longestAcc []rune) {
|
2016-08-15 20:29:37 +00:00
|
|
|
s := string(acc)
|
2016-12-02 21:28:25 +00:00
|
|
|
f := tokenize(s)
|
2016-08-15 20:29:37 +00:00
|
|
|
|
2016-09-12 20:33:52 +00:00
|
|
|
if len(f) == 0 || s[len(s)-1] == ' ' {
|
|
|
|
f = append(f, "")
|
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
var longest string
|
|
|
|
|
2016-08-15 20:29:37 +00:00
|
|
|
switch len(f) {
|
|
|
|
case 1:
|
|
|
|
words := gCmdWords
|
|
|
|
for c, _ := range gOpts.cmds {
|
|
|
|
words = append(words, c)
|
|
|
|
}
|
2016-09-12 20:33:52 +00:00
|
|
|
sort.Strings(words)
|
2016-08-21 15:41:03 +00:00
|
|
|
matches, longest = matchWord(s, words)
|
|
|
|
longestAcc = []rune(longest)
|
2016-09-12 20:33:52 +00:00
|
|
|
case 2:
|
2016-08-15 20:29:37 +00:00
|
|
|
switch f[0] {
|
|
|
|
case "set":
|
2016-08-21 15:41:03 +00:00
|
|
|
matches, longest = matchWord(f[1], gOptWords)
|
|
|
|
longestAcc = append(acc[:len(acc)-len(f[len(f)-1])], []rune(longest)...)
|
|
|
|
case "map", "cmd":
|
|
|
|
longestAcc = acc
|
2016-08-15 20:29:37 +00:00
|
|
|
default:
|
2016-08-21 15:41:03 +00:00
|
|
|
matches, longest = matchFile(f[len(f)-1])
|
|
|
|
longestAcc = append(acc[:len(acc)-len(f[len(f)-1])], []rune(longest)...)
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
2016-09-12 20:33:52 +00:00
|
|
|
default:
|
|
|
|
switch f[0] {
|
|
|
|
case "set", "map", "cmd":
|
|
|
|
longestAcc = acc
|
|
|
|
default:
|
|
|
|
matches, longest = matchFile(f[len(f)-1])
|
|
|
|
longestAcc = append(acc[:len(acc)-len(f[len(f)-1])], []rune(longest)...)
|
|
|
|
}
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
return
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
2016-08-16 19:31:17 +00:00
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
func compShell(acc []rune) (matches []string, longestAcc []rune) {
|
2016-08-16 19:31:17 +00:00
|
|
|
s := string(acc)
|
|
|
|
f := strings.Fields(s)
|
|
|
|
|
2016-09-12 20:33:52 +00:00
|
|
|
if len(f) == 0 || s[len(s)-1] == ' ' {
|
|
|
|
f = append(f, "")
|
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
var longest string
|
|
|
|
|
2016-08-16 19:31:17 +00:00
|
|
|
switch len(f) {
|
|
|
|
case 1:
|
2016-08-21 15:41:03 +00:00
|
|
|
matches, longest = matchExec(s)
|
|
|
|
longestAcc = []rune(longest)
|
2016-08-16 19:31:17 +00:00
|
|
|
default:
|
2016-08-21 15:41:03 +00:00
|
|
|
matches, longest = matchFile(f[len(f)-1])
|
|
|
|
longestAcc = append(acc[:len(acc)-len(f[len(f)-1])], []rune(longest)...)
|
2016-08-16 19:31:17 +00:00
|
|
|
}
|
|
|
|
|
2016-08-21 15:41:03 +00:00
|
|
|
return
|
2016-08-16 19:31:17 +00:00
|
|
|
}
|