lf/comp.go

284 lines
4.8 KiB
Go
Raw Normal View History

package main
import (
"io/ioutil"
"log"
"os"
"path/filepath"
2016-09-12 20:33:52 +00:00
"sort"
"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",
"top",
2017-11-19 18:55:13 +00:00
"bot",
"toggle",
"invert",
"unmark",
2017-11-19 18:55:13 +00:00
"yank",
"delete",
"put",
"clear",
"draw",
"redraw",
"reload",
2016-09-12 20:33:52 +00:00
"read",
"shell",
"shell-pipe",
"shell-wait",
"shell-async",
2016-09-12 20:33:52 +00:00
"search",
"search-back",
"search-next",
"search-prev",
"sync",
2016-09-12 20:33:52 +00:00
"echo",
"cd",
"select",
"push",
2016-09-12 20:33:52 +00:00
}
gOptWords = []string{
2017-06-03 11:12:43 +00:00
"dircounts",
"nodircounts",
"dircounts!",
"dirfirst",
"nodirfirst",
"dirfirst!",
"globsearch",
"noglobsearch",
"globsearch!",
"hidden",
"nohidden",
"hidden!",
"ignorecase",
"noignorecase",
"ignorecase!",
"preview",
"nopreview",
"preview!",
2016-12-26 20:49:18 +00:00
"reverse",
"noreverse",
"reverse!",
"smartcase",
"nosmartcase",
"smartcase!",
"wrapscan",
"nowrapscan",
"wrapscan!",
"scrolloff",
"tabstop",
"filesep",
"ifs",
"previewer",
"promptfmt",
"shell",
"sortby",
"timefmt",
"ratios",
"info",
}
)
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]
}
func matchWord(s string, words []string) (matches []string, longest string) {
for _, w := range words {
if strings.HasPrefix(w, s) {
matches = append(matches, w)
if longest != "" {
longest = matchLongest(longest, w)
2016-09-12 20:33:52 +00:00
} else if s != "" {
longest = w + " "
}
}
}
if longest == "" {
longest = s
}
return
}
func matchExec(s string) (matches []string, longest string) {
2016-09-12 20:33:52 +00:00
var words []string
paths := strings.Split(envPath, ":")
for _, p := range paths {
if _, err := os.Stat(p); os.IsNotExist(err) {
continue
}
fi, err := ioutil.ReadDir(p)
if err != nil {
2016-08-17 19:42:36 +00:00
log.Printf("reading path: %s", err)
}
for _, f := range fi {
if strings.HasPrefix(f.Name(), s) {
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)
continue
2016-08-16 20:17:19 +00:00
}
if !f.Mode().IsRegular() || f.Mode()&0111 == 0 {
continue
}
2016-09-12 20:33:52 +00:00
words = append(words, f.Name())
}
}
}
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-09-12 20:33:52 +00:00
return matchWord(s, words)
}
func matchFile(s string) (matches []string, longest string) {
2017-08-06 08:05:46 +00:00
dir := strings.Replace(s, "~", gUser.HomeDir, -1)
if !filepath.IsAbs(dir) {
wd, err := os.Getwd()
if err != nil {
log.Printf("getting current directory: %s", err)
}
dir = wd + string(filepath.Separator) + dir
}
2016-12-02 21:28:25 +00:00
dir = unescape(filepath.Dir(dir))
fi, err := ioutil.ReadDir(dir)
if err != nil {
2016-08-17 19:42:36 +00:00
log.Printf("reading directory: %s", err)
}
for _, f := range fi {
f, err := os.Stat(filepath.Join(dir, f.Name()))
if err != nil {
log.Printf("getting file information: %s", err)
return
}
_, last := filepath.Split(s)
2016-12-02 21:28:25 +00:00
if strings.HasPrefix(escape(f.Name()), last) {
name := f.Name()
if isRoot(s) || filepath.Base(s) != s {
name = filepath.Join(filepath.Dir(s), f.Name())
}
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)
if longest != "" {
longest = matchLongest(longest, name)
2016-09-12 20:33:52 +00:00
} else if s != "" {
if f.Mode().IsRegular() {
longest = name + " "
} else {
longest = name + string(filepath.Separator)
}
}
}
}
if longest == "" {
longest = s
}
return
}
func compCmd(acc []rune) (matches []string, longestAcc []rune) {
s := string(acc)
2016-12-02 21:28:25 +00:00
f := tokenize(s)
var longest string
switch len(f) {
case 1:
words := gCmdWords
2016-12-18 15:01:45 +00:00
for c := range gOpts.cmds {
words = append(words, c)
}
2016-09-12 20:33:52 +00:00
sort.Strings(words)
matches, longest = matchWord(s, words)
longestAcc = []rune(longest)
2016-09-12 20:33:52 +00:00
case 2:
switch f[0] {
case "set":
matches, longest = matchWord(f[1], gOptWords)
longestAcc = append(acc[:len(acc)-len(f[len(f)-1])], []rune(longest)...)
case "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-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)...)
}
}
return
}
func compShell(acc []rune) (matches []string, longestAcc []rune) {
s := string(acc)
2016-12-15 13:11:41 +00:00
f := tokenize(s)
var longest string
switch len(f) {
case 1:
matches, longest = matchExec(s)
longestAcc = []rune(longest)
default:
matches, longest = matchFile(f[len(f)-1])
longestAcc = append(acc[:len(acc)-len(f[len(f)-1])], []rune(longest)...)
}
return
}