initial commit [141.14.129.234,mike]
This commit is contained in:
+166
@@ -0,0 +1,166 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/chzyer/readline"
|
||||
)
|
||||
|
||||
// completer wires up Tab completion. Command names complete at the start of the
|
||||
// line; cd/open/view complete local project names; clone/show complete
|
||||
// repository names cached from the git server; checkout/tag complete branch and
|
||||
// tag names; dist completes filesystem paths.
|
||||
func completer() *readline.PrefixCompleter {
|
||||
return readline.NewPrefixCompleter(
|
||||
readline.PcItem("cd", readline.PcItemDynamic(dynLocalProjects)),
|
||||
readline.PcItem("open", readline.PcItemDynamic(dynLocalProjects)),
|
||||
readline.PcItem("view", readline.PcItemDynamic(dynLocalProjects)),
|
||||
readline.PcItem("clone",
|
||||
readline.PcItem("-a", readline.PcItemDynamic(dynServerArchives)),
|
||||
readline.PcItemDynamic(dynServerRepos),
|
||||
),
|
||||
readline.PcItem("cloneall"),
|
||||
readline.PcItem("show", readline.PcItemDynamic(dynServerRepos)),
|
||||
readline.PcItem("list", readline.PcItem("-a")),
|
||||
readline.PcItem("push"),
|
||||
readline.PcItem("pushremote"),
|
||||
readline.PcItem("pull"),
|
||||
readline.PcItem("fetch"),
|
||||
readline.PcItem("status", readline.PcItem("-a")),
|
||||
readline.PcItem("overview"),
|
||||
readline.PcItem("diff"),
|
||||
readline.PcItem("init"),
|
||||
readline.PcItem("edit"),
|
||||
readline.PcItem("checkout", readline.PcItemDynamic(dynCheckout)),
|
||||
readline.PcItem("log"),
|
||||
readline.PcItem("archive"),
|
||||
readline.PcItem("dist", readline.PcItemDynamic(dynPaths)),
|
||||
readline.PcItem("login"),
|
||||
readline.PcItem("count"),
|
||||
readline.PcItem("tag",
|
||||
readline.PcItem("add"),
|
||||
readline.PcItem("checkout", readline.PcItemDynamic(dynTags)),
|
||||
readline.PcItem("delete", readline.PcItemDynamic(dynTags)),
|
||||
),
|
||||
readline.PcItem("alias", readline.PcItemDynamic(dynAliasNames)),
|
||||
readline.PcItem("unalias", readline.PcItemDynamic(dynAliasNames)),
|
||||
readline.PcItem("rescan"),
|
||||
readline.PcItem("help"),
|
||||
readline.PcItem("quit"),
|
||||
readline.PcItem("exit"),
|
||||
)
|
||||
}
|
||||
|
||||
// dynLocalProjects lists project directories under BASE (already name-sorted).
|
||||
func dynLocalProjects(string) []string {
|
||||
entries, err := os.ReadDir(BASE)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var out []string
|
||||
for _, e := range entries {
|
||||
if e.IsDir() && !strings.HasPrefix(e.Name(), ".") {
|
||||
out = append(out, e.Name())
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
var (
|
||||
serverRepos []string
|
||||
serverArchives []string
|
||||
serverFetched bool
|
||||
)
|
||||
|
||||
// fetchServerRepos queries the server once and caches the repository/archive
|
||||
// names for Tab completion.
|
||||
func fetchServerRepos() {
|
||||
if serverFetched {
|
||||
return
|
||||
}
|
||||
serverFetched = true
|
||||
if lines, err := sshOut("/bin/ls ."); err == nil {
|
||||
for _, ln := range lines {
|
||||
if m := gitDirRe.FindStringSubmatch(strings.TrimSpace(ln)); m != nil {
|
||||
serverRepos = append(serverRepos, m[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
if lines, err := sshOut("/bin/ls archive"); err == nil {
|
||||
for _, ln := range lines {
|
||||
t := strings.TrimSpace(ln)
|
||||
if strings.HasSuffix(t, ".git.tar.gz") {
|
||||
serverArchives = append(serverArchives, strings.TrimSuffix(t, ".git.tar.gz"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rescanServer clears the cached server listing so the next completion (or use)
|
||||
// re-fetches it.
|
||||
func rescanServer() {
|
||||
serverFetched = false
|
||||
serverRepos = nil
|
||||
serverArchives = nil
|
||||
}
|
||||
|
||||
func dynServerRepos(string) []string { fetchServerRepos(); return serverRepos }
|
||||
func dynServerArchives(string) []string { fetchServerRepos(); return serverArchives }
|
||||
|
||||
// dynBranches / dynTags list the active project's local branches / tags.
|
||||
func dynBranches(string) []string {
|
||||
if !isDir(DIR + "/.git") {
|
||||
return nil
|
||||
}
|
||||
out, _ := gitCapture(DIR, "for-each-ref", "--format=%(refname:short)", "refs/heads")
|
||||
return splitLines(out)
|
||||
}
|
||||
|
||||
func dynTags(string) []string {
|
||||
if !isDir(DIR + "/.git") {
|
||||
return nil
|
||||
}
|
||||
out, _ := gitCapture(DIR, "tag", "-l")
|
||||
return splitLines(out)
|
||||
}
|
||||
|
||||
// dynCheckout offers both branches and tags for `checkout`.
|
||||
func dynCheckout(line string) []string {
|
||||
return append(dynBranches(line), dynTags(line)...)
|
||||
}
|
||||
|
||||
// dynPaths completes filesystem paths for the last token on the line.
|
||||
func dynPaths(line string) []string {
|
||||
partial := ""
|
||||
if !strings.HasSuffix(line, " ") {
|
||||
if f := strings.Fields(line); len(f) > 0 {
|
||||
partial = f[len(f)-1]
|
||||
}
|
||||
}
|
||||
dir := "."
|
||||
if partial != "" {
|
||||
if strings.HasSuffix(partial, "/") {
|
||||
dir = partial
|
||||
} else {
|
||||
dir = filepath.Dir(partial)
|
||||
}
|
||||
}
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var out []string
|
||||
for _, e := range entries {
|
||||
if strings.HasPrefix(e.Name(), ".") {
|
||||
continue
|
||||
}
|
||||
p := filepath.Join(dir, e.Name())
|
||||
if e.IsDir() {
|
||||
p += "/"
|
||||
}
|
||||
out = append(out, p)
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user