all repos

viye @ 99e30d03dbda8110ba0f2d9bbc2f40ac733fb53d

my shot at reimplementing xiki

viye/internal/plumbing/files/files.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
move away from xiki '/' separated command path to each node is it's own arg model, 2 months ago
1
package files
2
3
import (
4
	"bufio"
5
	"fmt"
6
	"os"
7
	"path/filepath"
8
	"strings"
9
10
	"github.com/olexsmir/viye/internal/viye"
11
)
12
13
type Tool struct{}
14
15
func (Tool) Name() string { return "files(~/..., /..., ./...)" }
16
17
func (Tool) Match(ctx *viye.Context) bool {
18
	return strings.HasPrefix(ctx.Path[0], "/") || strings.HasPrefix(ctx.Path[0], "./") ||
19
		strings.HasPrefix(ctx.Path[0], "~/")
20
}
21
22
func (Tool) Execute(ctx *viye.Context) (string, error) {
23
	path := resolve(ctx.Path[0], ctx.Dir)
24
25
	info, err := os.Stat(path)
26
	if err != nil {
27
		return "", err
28
	}
29
30
	switch {
31
	case info.IsDir():
32
		if len(ctx.Path) == 1 {
33
			ls, err := listDir(path)
34
			if err != nil {
35
				return "", err
36
			}
37
			return viye.FormatOutput(ls), nil
38
		}
39
		ctx.Dir = path
40
		ctx.Path = ctx.Path[1:]
41
		return ctx.Next()
42
43
	// case info.Mode()&0o111 != 0:
44
	// 	return runExec(path)
45
46
	default:
47
		s, err := head(path, 10)
48
		if err != nil {
49
			return "", err
50
		}
51
		return s, nil
52
	}
53
}
54
55
func resolve(p, dir string) string {
56
	if p == "~" {
57
		home, _ := os.UserHomeDir()
58
		return home
59
	}
60
	if strings.HasPrefix(p, "~/") {
61
		home, _ := os.UserHomeDir()
62
		return filepath.Join(home, p[2:])
63
	}
64
	if filepath.IsAbs(p) {
65
		return filepath.Clean(p)
66
	}
67
	return filepath.Join(dir, p)
68
}
69
70
func listDir(dir string) (string, error) {
71
	entries, err := os.ReadDir(dir)
72
	if err != nil {
73
		return "", err
74
	}
75
	var b strings.Builder
76
	for _, e := range entries {
77
		name := e.Name()
78
		if e.IsDir() {
79
			name += "/"
80
		}
81
		b.WriteString(name)
82
		b.WriteByte('\n')
83
	}
84
	return b.String(), nil
85
}
86
87
func head(path string, n int) (string, error) {
88
	f, err := os.Open(path)
89
	if err != nil {
90
		return "", err
91
	}
92
	defer f.Close()
93
94
	sc := bufio.NewScanner(f)
95
	var b strings.Builder
96
	for i := 0; i < n && sc.Scan(); i++ {
97
		fmt.Fprintf(&b, "| %s\n", sc.Text())
98
	}
99
	if sc.Scan() {
100
		b.WriteString("| ...\n")
101
	}
102
	return b.String(), sc.Err()
103
}