lf/complete.go

308 lines
5.1 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",
2018-05-15 21:20:05 +00:00
"bottom",
2017-11-19 18:55:13 +00:00
"toggle",
"invert",
2018-07-09 18:22:10 +00:00
"unselect",
"copy",
"cut",
"paste",
2017-11-19 18:55:13 +00:00
"clear",
"draw",
"redraw",
"load",
"reload",
2016-09-12 20:33:52 +00:00
"read",
"shell",
"shell-pipe",
"shell-wait",
"shell-async",
"find",
"find-back",
"find-next",
"find-prev",
2016-09-12 20:33:52 +00:00
"search",
"search-back",
"search-next",
"search-prev",
"mark-save",
"mark-load",
"sync",
2016-09-12 20:33:52 +00:00
"echo",
"cd",
"select",
"source",
"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!",
"drawbox",
"nodrawbox",
"drawbox!",
"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!",
"findlen",
"period",
"scrolloff",
"tabstop",
"filesep",
"ifs",
"previewer",
"promptfmt",
"shell",
"sortby",
"timefmt",
"ratios",
"info",
"shellopts",
}
)
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 {
2018-05-20 17:30:41 +00:00
if !strings.HasPrefix(w, s) {
continue
}
matches = append(matches, w)
if longest != "" {
longest = matchLongest(longest, w)
} 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
2018-06-28 21:12:54 +00:00
paths := strings.Split(envPath, string(filepath.ListSeparator))
for _, p := range paths {
if _, err := os.Stat(p); os.IsNotExist(err) {
continue
}
2018-05-20 17:30:41 +00:00
files, err := ioutil.ReadDir(p)
if err != nil {
2016-08-17 19:42:36 +00:00
log.Printf("reading path: %s", err)
}
2018-05-20 17:30:41 +00:00
for _, f := range files {
if !strings.HasPrefix(f.Name(), s) {
continue
}
2016-08-16 20:17:19 +00:00
2018-05-20 17:30:41 +00:00
f, err = os.Stat(filepath.Join(p, f.Name()))
if err != nil {
log.Printf("getting file information: %s", err)
continue
}
2018-06-28 21:12:54 +00:00
if !f.Mode().IsRegular() || !isExecutable(f) {
2018-05-20 17:30:41 +00:00
continue
}
2018-05-20 17:30:41 +00:00
2018-06-28 21:12:54 +00:00
log.Print(f.Name())
2018-05-20 17:30:41 +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)
} else {
dir = wd + string(filepath.Separator) + dir
}
}
2016-12-02 21:28:25 +00:00
dir = unescape(filepath.Dir(dir))
2018-05-20 17:30:41 +00:00
files, err := ioutil.ReadDir(dir)
if err != nil {
2016-08-17 19:42:36 +00:00
log.Printf("reading directory: %s", err)
}
2018-05-20 17:30:41 +00:00
for _, f := range files {
f, err := os.Stat(filepath.Join(dir, f.Name()))
if err != nil {
log.Printf("getting file information: %s", err)
return
}
_, last := filepath.Split(s)
2018-05-20 17:30:41 +00:00
if !strings.HasPrefix(escape(f.Name()), last) {
continue
}
name := f.Name()
if isRoot(s) || filepath.Base(s) != s {
name = filepath.Join(filepath.Dir(s), f.Name())
}
name = escape(name)
item := f.Name()
if f.Mode().IsDir() {
item += string(filepath.Separator)
}
matches = append(matches, item)
if longest != "" {
longest = matchLongest(longest, name)
} else if s != "" {
if f.Mode().IsRegular() {
longest = name + " "
} else {
longest = name + string(filepath.Separator)
}
}
}
if longest == "" {
longest = s
}
return
}
2018-05-15 21:05:06 +00:00
func completeCmd(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
}
2018-05-15 21:05:06 +00:00
func completeShell(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
}