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",
|
|
|
|
"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",
|
2018-06-27 18:15:34 +00:00
|
|
|
"copy",
|
|
|
|
"cut",
|
|
|
|
"paste",
|
2017-11-19 18:55:13 +00:00
|
|
|
"clear",
|
2018-01-29 15:12:59 +00:00
|
|
|
"redraw",
|
2018-01-29 15:08:51 +00:00
|
|
|
"reload",
|
2016-09-12 20:33:52 +00:00
|
|
|
"read",
|
2020-06-11 01:11:40 +00:00
|
|
|
"rename",
|
2018-03-27 18:23:34 +00:00
|
|
|
"shell",
|
|
|
|
"shell-pipe",
|
|
|
|
"shell-wait",
|
|
|
|
"shell-async",
|
2018-08-22 17:05:22 +00:00
|
|
|
"find",
|
|
|
|
"find-back",
|
|
|
|
"find-next",
|
|
|
|
"find-prev",
|
2016-09-12 20:33:52 +00:00
|
|
|
"search",
|
|
|
|
"search-back",
|
2016-12-23 15:58:24 +00:00
|
|
|
"search-next",
|
|
|
|
"search-prev",
|
2021-08-21 13:40:24 +00:00
|
|
|
"filter",
|
|
|
|
"setfilter",
|
2018-07-09 18:35:04 +00:00
|
|
|
"mark-save",
|
2019-06-25 18:38:34 +00:00
|
|
|
"mark-remove",
|
2018-07-09 18:35:04 +00:00
|
|
|
"mark-load",
|
2020-06-11 01:11:40 +00:00
|
|
|
"draw",
|
|
|
|
"load",
|
2016-11-08 21:39:39 +00:00
|
|
|
"sync",
|
2016-09-12 20:33:52 +00:00
|
|
|
"echo",
|
2019-02-28 18:58:14 +00:00
|
|
|
"echomsg",
|
|
|
|
"echoerr",
|
2016-09-12 20:33:52 +00:00
|
|
|
"cd",
|
2022-02-12 09:40:07 +00:00
|
|
|
"calcdirsize",
|
2018-03-27 17:47:17 +00:00
|
|
|
"select",
|
2019-06-20 15:17:47 +00:00
|
|
|
"glob-select",
|
|
|
|
"glob-unselect",
|
2018-06-28 14:13:43 +00:00
|
|
|
"source",
|
2016-09-18 16:21:24 +00:00
|
|
|
"push",
|
2020-06-11 01:11:40 +00:00
|
|
|
"delete",
|
2016-09-12 20:33:52 +00:00
|
|
|
}
|
|
|
|
|
2016-08-15 20:29:37 +00:00
|
|
|
gOptWords = []string{
|
2018-08-22 22:37:07 +00:00
|
|
|
"anchorfind",
|
|
|
|
"noanchorfind",
|
|
|
|
"anchorfind!",
|
2021-05-19 18:55:19 +00:00
|
|
|
"autoquit",
|
|
|
|
"noautoquit",
|
|
|
|
"autoquit!",
|
2021-08-01 14:06:04 +00:00
|
|
|
"dircache",
|
|
|
|
"nodircache",
|
|
|
|
"dircache!",
|
2017-06-03 11:12:43 +00:00
|
|
|
"dircounts",
|
|
|
|
"nodircounts",
|
|
|
|
"dircounts!",
|
2016-11-21 20:13:33 +00:00
|
|
|
"dirfirst",
|
|
|
|
"nodirfirst",
|
|
|
|
"dirfirst!",
|
2021-07-31 13:10:25 +00:00
|
|
|
"dironly",
|
|
|
|
"nodironly",
|
|
|
|
"dironly!",
|
2018-04-15 16:26:51 +00:00
|
|
|
"drawbox",
|
|
|
|
"nodrawbox",
|
|
|
|
"drawbox!",
|
2017-07-15 14:06:18 +00:00
|
|
|
"globsearch",
|
|
|
|
"noglobsearch",
|
|
|
|
"globsearch!",
|
2016-08-15 20:29:37 +00:00
|
|
|
"hidden",
|
|
|
|
"nohidden",
|
2016-08-16 20:13:57 +00:00
|
|
|
"hidden!",
|
2020-06-11 01:11:40 +00:00
|
|
|
"icons",
|
|
|
|
"noicons",
|
|
|
|
"icons!",
|
2017-07-15 14:18:37 +00:00
|
|
|
"ignorecase",
|
|
|
|
"noignorecase",
|
|
|
|
"ignorecase!",
|
2018-12-03 12:41:53 +00:00
|
|
|
"ignoredia",
|
|
|
|
"noignoredia",
|
|
|
|
"ignoredia!",
|
2018-11-24 16:02:04 +00:00
|
|
|
"incsearch",
|
|
|
|
"noincsearch",
|
|
|
|
"incsearch!",
|
2021-08-21 13:40:24 +00:00
|
|
|
"incfilter",
|
|
|
|
"noincfilter",
|
|
|
|
"incfilter!",
|
2021-01-29 16:36:27 +00:00
|
|
|
"mouse",
|
|
|
|
"nomouse",
|
|
|
|
"mouse!",
|
2020-06-11 01:11:40 +00:00
|
|
|
"number",
|
|
|
|
"nonumber",
|
|
|
|
"number!",
|
2016-08-27 11:12:03 +00:00
|
|
|
"preview",
|
|
|
|
"nopreview",
|
|
|
|
"preview!",
|
2020-06-11 01:11:40 +00:00
|
|
|
"relativenumber",
|
|
|
|
"norelativenumber",
|
|
|
|
"relativenumber!",
|
2016-12-26 20:49:18 +00:00
|
|
|
"reverse",
|
|
|
|
"noreverse",
|
|
|
|
"reverse!",
|
2017-07-15 14:46:22 +00:00
|
|
|
"smartcase",
|
|
|
|
"nosmartcase",
|
|
|
|
"smartcase!",
|
2018-12-03 12:41:53 +00:00
|
|
|
"smartdia",
|
|
|
|
"nosmartdia",
|
|
|
|
"smartdia!",
|
2021-04-06 15:57:23 +00:00
|
|
|
"waitmsg",
|
2017-03-16 13:22:42 +00:00
|
|
|
"wrapscan",
|
|
|
|
"nowrapscan",
|
|
|
|
"wrapscan!",
|
2019-05-12 14:21:45 +00:00
|
|
|
"wrapscroll",
|
|
|
|
"nowrapscroll",
|
|
|
|
"wrapscroll!",
|
2018-08-22 17:57:47 +00:00
|
|
|
"findlen",
|
2018-06-09 19:02:09 +00:00
|
|
|
"period",
|
2016-08-15 20:29:37 +00:00
|
|
|
"scrolloff",
|
2016-08-27 11:12:03 +00:00
|
|
|
"tabstop",
|
2019-03-27 19:07:41 +00:00
|
|
|
"errorfmt",
|
2016-12-24 13:06:44 +00:00
|
|
|
"filesep",
|
2020-06-11 01:11:40 +00:00
|
|
|
"hiddenfiles",
|
2016-08-27 11:12:03 +00:00
|
|
|
"ifs",
|
2020-06-11 01:11:40 +00:00
|
|
|
"info",
|
2016-08-28 12:04:57 +00:00
|
|
|
"previewer",
|
2020-12-24 13:13:20 +00:00
|
|
|
"cleaner",
|
2018-02-22 15:18:30 +00:00
|
|
|
"promptfmt",
|
2020-06-11 01:11:40 +00:00
|
|
|
"ratios",
|
2016-08-27 11:12:03 +00:00
|
|
|
"shell",
|
2021-04-04 15:23:14 +00:00
|
|
|
"shellflag",
|
2020-06-11 01:11:40 +00:00
|
|
|
"shellopts",
|
2016-08-27 11:12:03 +00:00
|
|
|
"sortby",
|
2016-11-21 20:13:33 +00:00
|
|
|
"timefmt",
|
2022-01-30 23:28:06 +00:00
|
|
|
"tempmarks",
|
2022-02-12 09:23:22 +00:00
|
|
|
"infotimefmtnew",
|
|
|
|
"infotimefmtold",
|
2020-07-18 00:08:25 +00:00
|
|
|
"truncatechar",
|
2016-08-15 20:29:37 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
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 {
|
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 + " "
|
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
|
|
|
|
|
2018-06-28 21:12:54 +00:00
|
|
|
paths := strings.Split(envPath, string(filepath.ListSeparator))
|
2016-08-16 19:31:17 +00:00
|
|
|
|
|
|
|
for _, p := range paths {
|
2016-08-16 20:18:26 +00:00
|
|
|
if _, err := os.Stat(p); os.IsNotExist(err) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2018-05-20 17:30:41 +00:00
|
|
|
files, err := ioutil.ReadDir(p)
|
2016-08-16 19:31:17 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
|
}
|
2016-08-21 15:41:03 +00:00
|
|
|
|
2018-06-28 21:12:54 +00:00
|
|
|
if !f.Mode().IsRegular() || !isExecutable(f) {
|
2018-05-20 17:30:41 +00:00
|
|
|
continue
|
2016-08-16 19:31:17 +00:00
|
|
|
}
|
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-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) {
|
2020-06-07 17:53:25 +00:00
|
|
|
dir := replaceTilde(s)
|
2016-08-26 20:25:40 +00:00
|
|
|
|
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)
|
2018-07-30 17:56:57 +00:00
|
|
|
} else {
|
|
|
|
dir = wd + string(filepath.Separator) + dir
|
2016-08-26 20:25:40 +00:00
|
|
|
}
|
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
|
|
|
|
2018-05-20 17:30:41 +00:00
|
|
|
files, 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
|
|
|
}
|
|
|
|
|
2018-05-20 17:30:41 +00:00
|
|
|
for _, f := range files {
|
2021-02-12 17:50:48 +00:00
|
|
|
name := filepath.Join(dir, f.Name())
|
|
|
|
f, err := os.Stat(name)
|
2016-08-26 20:25:40 +00:00
|
|
|
if err != nil {
|
2021-02-12 17:50:48 +00:00
|
|
|
fl, err := os.Lstat(name)
|
2021-02-21 14:48:23 +00:00
|
|
|
if err == nil && fl.Mode()&os.ModeSymlink != 0 {
|
2021-02-12 17:50:48 +00:00
|
|
|
continue
|
|
|
|
} else {
|
|
|
|
log.Printf("getting file information: %s", err)
|
|
|
|
return
|
|
|
|
}
|
2016-08-26 20:25:40 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:05:18 +00:00
|
|
|
_, last := filepath.Split(s)
|
2018-05-20 17:30:41 +00:00
|
|
|
if !strings.HasPrefix(escape(f.Name()), last) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-02-12 17:50:48 +00:00
|
|
|
name = f.Name()
|
2018-05-20 17:30:41 +00:00
|
|
|
if isRoot(s) || filepath.Base(s) != s {
|
2019-10-25 17:17:49 +00:00
|
|
|
name = filepath.Join(filepath.Dir(unescape(s)), f.Name())
|
2018-05-20 17:30:41 +00:00
|
|
|
}
|
|
|
|
name = escape(name)
|
|
|
|
|
|
|
|
item := f.Name()
|
|
|
|
if f.Mode().IsDir() {
|
2019-10-25 17:51:22 +00:00
|
|
|
item += escape(string(filepath.Separator))
|
2018-05-20 17:30:41 +00:00
|
|
|
}
|
|
|
|
matches = append(matches, item)
|
|
|
|
|
|
|
|
if longest != "" {
|
|
|
|
longest = matchLongest(longest, name)
|
|
|
|
} else if s != "" {
|
|
|
|
if f.Mode().IsRegular() {
|
|
|
|
longest = name + " "
|
|
|
|
} else {
|
2019-10-25 17:51:22 +00:00
|
|
|
longest = name + escape(string(filepath.Separator))
|
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
|
|
|
}
|
|
|
|
|
2018-05-15 21:05:06 +00:00
|
|
|
func completeCmd(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-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
|
2016-12-18 15:01:45 +00:00
|
|
|
for c := range gOpts.cmds {
|
2016-08-15 20:29:37 +00:00
|
|
|
words = append(words, c)
|
|
|
|
}
|
2016-09-12 20:33:52 +00:00
|
|
|
sort.Strings(words)
|
2018-12-29 17:20:45 +00:00
|
|
|
j := 0
|
|
|
|
for i := 1; i < len(words); i++ {
|
|
|
|
if words[j] == words[i] {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
j++
|
|
|
|
words[i], words[j] = words[j], words[i]
|
|
|
|
}
|
|
|
|
words = words[:j+1]
|
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
|
|
|
|
2019-03-13 22:20:06 +00:00
|
|
|
func completeFile(acc []rune) (matches []string, longestAcc []rune) {
|
|
|
|
s := string(acc)
|
|
|
|
|
|
|
|
wd, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("getting current directory: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
files, err := ioutil.ReadDir(wd)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("reading directory: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var longest string
|
|
|
|
|
|
|
|
for _, f := range files {
|
|
|
|
if !strings.HasPrefix(f.Name(), s) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
matches = append(matches, f.Name())
|
|
|
|
|
|
|
|
if longest != "" {
|
|
|
|
longest = matchLongest(longest, f.Name())
|
|
|
|
} else if s != "" {
|
|
|
|
longest = f.Name()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if longest == "" {
|
|
|
|
longest = s
|
|
|
|
}
|
|
|
|
|
|
|
|
longestAcc = []rune(longest)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-05-15 21:05:06 +00:00
|
|
|
func completeShell(acc []rune) (matches []string, longestAcc []rune) {
|
2016-08-16 19:31:17 +00:00
|
|
|
s := string(acc)
|
2016-12-15 13:11:41 +00:00
|
|
|
f := tokenize(s)
|
2016-08-16 19:31:17 +00:00
|
|
|
|
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])
|
2019-12-22 23:35:32 +00:00
|
|
|
longestAcc = append(acc[:len(acc)-len([]rune(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
|
|
|
}
|