Skip to content

Instantly share code, notes, and snippets.

@AWtnb
Last active Sep 11, 2021
Embed
What would you like to do?
fuzzy directory launcher with golang
package main
import (
"bufio"
"flag"
"fmt"
"io/fs"
"net/url"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"github.com/ktr0731/go-fuzzyfinder"
)
func main() {
var (
datapath string
filer string
all bool
exclude string
)
flag.StringVar(&datapath, "datapath", `C:\Personal\launch.txt`, "path to databese text file.\nstyle: filepath(|displayName|depth)\n")
flag.StringVar(&filer, "filer", "explorer.exe", "path of filer")
flag.BoolVar(&all, "all", false, "search file and directory")
flag.StringVar(&exclude, "exclude", "", "path to skip searching (comma-separated)")
flag.Parse()
if !isValidPath(datapath) {
fmt.Println("cannot find data file...")
return
}
if !isValidPath(filer) {
filer = "explorer.exe"
}
launchItems := loadSource(datapath)
idx, err := fuzzyfinder.Find(launchItems, func(i int) string {
li := launchItems[i]
return li.Name
})
if err != nil {
fmt.Println(-1)
return
}
pickup := launchItems[idx]
p := pickup.Path
if isExecutable(p) {
exec.Command("cmd", "/c", "start", "", p).Start()
fmt.Println(0)
return
}
d := pickup.Depth
if d == 0 {
exec.Command(filer, p).Start()
fmt.Println(0)
return
}
skips := strings.Split(exclude, ",")
children := getChildItems(p, d, all, skips)
var c string
if len(children) > 1 {
idx, err := fuzzyfinder.Find(children, func(i int) string {
rel, _ := filepath.Rel(p, children[i])
return rel
})
if err != nil {
fmt.Println(-1)
return
}
c = children[idx]
} else {
c = children[0]
}
if isExecutable(c) {
exec.Command("cmd", "/c", "start", "", c).Start()
} else {
exec.Command(filer, c).Start()
}
fmt.Println(0)
}
func isValidPath(filename string) bool {
_, err := os.Stat(filename)
return err == nil
}
func isExecutable(path string) bool {
if strings.HasPrefix(path, "http") {
return true
}
fi, _ := os.Stat(path)
return !fi.IsDir()
}
func readFile(filePath string) []string {
f, err := os.Open(filePath)
if err != nil {
panic(err)
}
defer f.Close()
lines := make([]string, 0, 100)
scanner := bufio.NewScanner(f)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
panic(err)
}
return lines
}
type LaunchInfo struct {
Path string
Name string
Depth int
}
type LaunchInfos []LaunchInfo
func getDisplayName(s string) string {
n := ""
if strings.HasPrefix(s, "http") {
u, err := url.Parse(s)
if err == nil {
n = fmt.Sprintf("link[%s/%s]", u.Host, u.RawQuery)
} else {
n = s
}
} else {
n = filepath.Base(s)
}
return n
}
func fromLine(line string, sep string) (string, string, int) {
var sl []string
for i, s := range strings.Split(line, sep) {
if i > 2 {
break
}
sl = append(sl, strings.TrimSpace(s))
}
if len(sl) < 3 {
if len(sl) == 1 {
sl = append(sl, getDisplayName(sl[0]), "-1")
} else {
sl = append(sl, "-1")
}
}
if len(sl[1]) < 1 {
sl[1] = getDisplayName(sl[0])
}
d := 0
if i, err := strconv.Atoi(sl[2]); err == nil {
d = i
}
return sl[0], sl[1], d
}
func loadSource(path string) LaunchInfos {
var li LaunchInfos
for _, s := range readFile(path) {
if len(s) < 1 {
continue
}
p, n, d := fromLine(s, "|")
var item LaunchInfo
if !strings.HasPrefix(p, "http") && !isValidPath(p) {
continue
}
item = LaunchInfo{
Path: p,
Name: n,
Depth: d,
}
li = append(li, item)
}
return li
}
func sliceContains(slc []string, str string) bool {
for _, v := range slc {
if v == str {
return true
}
}
return false
}
func getChildItems(dir string, limit int, all bool, exclude []string) []string {
children := make([]string, 0, 1000)
depth := strings.Count(dir, string(filepath.Separator))
err := filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
if err != nil {
return err
}
if limit > 0 && strings.Count(path, string(filepath.Separator))-depth > limit {
return filepath.SkipDir
}
if len(exclude) > 0 && sliceContains(exclude, filepath.Base(path)) {
return filepath.SkipDir
}
if all {
children = append(children, path)
return nil
}
if info.IsDir() {
if strings.HasPrefix(info.Name(), ".") {
return filepath.SkipDir
}
children = append(children, path)
}
return nil
})
if err != nil {
panic(err)
}
return children
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment