diff options
| author | ewy <ewy0@protonmail.com> | 2026-04-29 22:34:47 +0200 |
|---|---|---|
| committer | ewy <ewy0@protonmail.com> | 2026-04-29 22:34:47 +0200 |
| commit | 42fb6efd01e3640ea9d15dc1e0a072c1ea8295b1 (patch) | |
| tree | ebf351b66f0288c8e9f879c529a962b025bebf15 | |
| parent | 03a31799a872385d821130f46942fc13dae76774 (diff) | |
fix very embarrassing bug where -a didnt actually work
| -rw-r--r-- | cache/cache.go | 81 | ||||
| -rw-r--r-- | cache/cache_test.go | 2 | ||||
| -rw-r--r-- | indexers/pikdex/hydrate_test.go | 4 | ||||
| -rw-r--r-- | main.go | 39 | ||||
| -rw-r--r-- | runner/create.go (renamed from testx/create.go) | 7 | ||||
| -rw-r--r-- | runner/create_test.go (renamed from testx/create_test.go) | 2 | ||||
| -rw-r--r-- | runner/stub.go | 7 | ||||
| -rw-r--r-- | search/search_test.go | 106 | ||||
| -rw-r--r-- | spool/spool.go | 11 | ||||
| -rw-r--r-- | viewport/viewport.go | 6 |
10 files changed, 149 insertions, 116 deletions
diff --git a/cache/cache.go b/cache/cache.go index 328b1e9..39ee062 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -16,13 +16,38 @@ type Cache struct { Entries []Entry } +type cacheInit struct{} + +// Path is the file path to the "contexts" cache file +var Path string + +// FsPath is the Path with the leading slash removed, to be opened from fs.FS +var FsPath string + +var Init model.Initializer = &cacheInit{} + +func (i *cacheInit) Init() error { + Path = path.Join(paths.Cache, "contexts") + FsPath = Path[1:] + return nil +} + // Merge combines two caches and filters duplicate keys -func (c Cache) Merge(other Cache) Cache { +func (c *Cache) Merge(other *Cache) *Cache { + if other == nil && c != nil { + return c + } + if c == nil && other != nil { + return other + } + if c == nil { + return nil + } mp := make(map[string]string) for _, e := range append(c.Entries, other.Entries...) { mp[e.Path] = e.Label } - result := Cache{} + result := &Cache{} for p, l := range mp { result.Entries = append(result.Entries, Entry{Label: l, Path: p}) } @@ -36,22 +61,16 @@ type Entry struct { var Empty = Cache{} -// Path is the file path to the "contexts" cache file -var Path = path.Join(paths.Cache, "contexts") - -// FsPath is the Path with the leading slash removed, to be opened from fs.FS -var FsPath = Path[1:] - var UnexpectedEntryError = errors.New("unexpected cache entry") // LoadFile creates a Cache from a file or an empty one if the file does not exist // this handles opening a reader for Unmarshal -func LoadFile(root fs.FS, path string) (Cache, error) { +func LoadFile(root fs.FS, path string) (*Cache, error) { fd, err := root.Open(path) if errors.Is(err, fs.ErrNotExist) { - return Cache{}, nil + return nil, nil } else if err != nil { - return Cache{}, err + return nil, err } if fd != nil { defer fd.Close() @@ -60,8 +79,8 @@ func LoadFile(root fs.FS, path string) (Cache, error) { } // Unmarshal attempts to create a Cache from reader content -func Unmarshal(r io.Reader) (Cache, error) { - c := Cache{} +func Unmarshal(r io.Reader) (*Cache, error) { + c := &Cache{} scanner := bufio.NewScanner(r) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) @@ -86,7 +105,7 @@ func Unmarshal(r io.Reader) (Cache, error) { } // Marshal returns the file representation of the Cache -func (c Cache) Marshal() []byte { +func (c *Cache) Marshal() []byte { b := strings.Builder{} for _, e := range c.Entries { b.WriteString(e.Path) @@ -97,12 +116,10 @@ func (c Cache) Marshal() []byte { return []byte(b.String()) } -func (c Cache) String() string { +func (c *Cache) String() string { return string(c.Marshal()) } - -// New creates a new Cache from a model.State -func New(st *model.State) Cache { +func New(st *model.State) *Cache { c := &Cache{} for _, s := range st.Sources { c.Entries = append(c.Entries, Entry{ @@ -110,11 +127,22 @@ func New(st *model.State) Cache { Label: s.Label(), }) } - return *c + return c +} + +func Insert(in *model.State) error { + f := os.DirFS("/") + loaded, err := LoadFile(f, FsPath) + if err != nil { + return err + } + insert := New(in) + result := loaded.Merge(insert) + return SaveFile(Path, result) } // SaveFile helps you use Save with a file path instead of a reader -func SaveFile(path string, s *model.State, loaded Cache) error { +func SaveFile(path string, loaded *Cache) error { fd, err := os.Create(path) if err != nil { return err @@ -122,19 +150,18 @@ func SaveFile(path string, s *model.State, loaded Cache) error { if fd != nil { defer fd.Close() } - return Save(s, fd, loaded) + return Save(fd, loaded) } -// Save writes the cache combined with the "loaded" cache to the writer. -func Save(s *model.State, w io.Writer, loaded Cache) error { - result := New(s).Merge(loaded) - _, err := w.Write([]byte(result.Marshal())) +// Save writes a cache to the contexts file +func Save(w io.Writer, loaded *Cache) error { + _, err := w.Write(loaded.Marshal()) return err } // LoadState creates a state with model.NewState based on cache content -func LoadState(f fs.FS, cache Cache, indexers []model.Indexer, runners []model.Runner) (*model.State, []error) { +func LoadState(f fs.FS, cache *Cache, indexers []model.Indexer, runners []model.Runner) (*model.State, []error) { var locs []string for _, e := range cache.Entries { locs = append(locs, e.Path) @@ -144,7 +171,7 @@ func LoadState(f fs.FS, cache Cache, indexers []model.Indexer, runners []model.R // Strip removes the needle's entries from the receiver's entries when they have matching paths. // used to skip already indexed locations when auto-all-ing -func (c Cache) Strip(needle Cache) Cache { +func (c *Cache) Strip(needle Cache) Cache { var result []Entry outer: for _, e := range c.Entries { diff --git a/cache/cache_test.go b/cache/cache_test.go index 1a9c46d..95ded9d 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -5,7 +5,7 @@ package cache import ( "github.com/stretchr/testify/assert" "path/filepath" - . "pik/testx" + . "pik/runner" "strings" "testing" "testing/fstest" diff --git a/indexers/pikdex/hydrate_test.go b/indexers/pikdex/hydrate_test.go index e72954e..72ac8ea 100644 --- a/indexers/pikdex/hydrate_test.go +++ b/indexers/pikdex/hydrate_test.go @@ -4,7 +4,7 @@ package pikdex import ( "github.com/stretchr/testify/assert" - "pik/testx" + "pik/runner" "testing" ) @@ -19,7 +19,7 @@ func TestHydrate(t *testing.T) { }, }, } - src := testx.TSource("asdf", "target") + src := runner.TSource("asdf", "target") hyd := src.Hydrate(nil) assert.NotNil(t, hyd) err := p.Mod(src, hyd) @@ -24,14 +24,15 @@ import ( "sync" ) -// preInitializers are ran before the initializers. +// syncInitializers are ran before the initializers. // useful for initializing stuff like paths, preparing directories, and reading the environment -var preInitializers = []model.Initializer{ +var syncInitializers = []model.Initializer{ paths.Paths, + cache.Init, } // initializers are ran before indexing with the indexers, -// data from the preInitializers can be accessed at this time. +// data from the syncInitializers can be accessed at this time. var initializers = []model.Initializer{ pikdex.Indexer, python.Python, @@ -65,7 +66,7 @@ var ForceConfirm = false // SourcesWithoutResults is a failed cache from the previous iteration // used for stripping out results to prevent double-index -var SourcesWithoutResults cache.Cache +var SourcesWithoutResults *cache.Cache //go:embed version.txt var version string @@ -79,18 +80,14 @@ func main() { os.Exit(0) } - wg := sync.WaitGroup{} - for _, i := range preInitializers { - wg.Go(func() { - err := i.Init() - if err != nil { - _, _ = spool.Warn("%v\n", err) - } - }) + for _, i := range syncInitializers { + err := i.Init() + if err != nil { + _, _ = spool.Warn("%v\n", err) + } } - wg.Wait() - wg = sync.WaitGroup{} + wg := sync.WaitGroup{} for _, i := range initializers { wg.Go(func() { err := i.Init() @@ -121,12 +118,15 @@ func main() { var st *model.State var stateErrors []error - var c cache.Cache + var c *cache.Cache if !*flags.All { st, stateErrors = model.NewState(fs, locs, indexers, runners) + err = cache.Insert(st) + if err != nil { + spool.Warn("%v\n", err) + } } else { c, err = cache.LoadFile(fs, cache.Path[1:]) - c.Strip(SourcesWithoutResults) if err != nil { _, _ = spool.Warn("%v\n", err) os.Exit(1) @@ -135,11 +135,6 @@ func main() { } if stateErrors != nil { _, _ = spool.Warn("%v\n", stateErrors) - } else { - err = cache.SaveFile(cache.Path, st, c) - if err != nil { - _, _ = spool.Warn("%v", err) - } } if *flags.List { @@ -186,7 +181,7 @@ func main() { } if result.Target == nil { - _, _ = spool.Print("target not found.") + _, _ = spool.Warn("target not found.") os.Exit(1) return } diff --git a/testx/create.go b/runner/create.go index 24faaed..4e9035b 100644 --- a/testx/create.go +++ b/runner/create.go @@ -1,13 +1,12 @@ //go:build test -package testx +package runner import ( "github.com/stretchr/testify/assert" "os/exec" "pik/identity" "pik/model" - "pik/runner" "testing" ) @@ -34,7 +33,7 @@ func TState(sources ...*model.Source) *model.State { } type TestTarget struct { - runner.Stub + Stub Id identity.Identity SubValue []string MyTags model.Tags @@ -53,7 +52,7 @@ func (t TestTarget) Visible() bool { } func (t TestTarget) Hydrate(src *model.Source) (model.HydratedTarget, error) { - return runner.HydratedStub{}, nil + return HydratedStub{}, nil } func (t TestTarget) Sub() []string { diff --git a/testx/create_test.go b/runner/create_test.go index d0e3099..fc9e535 100644 --- a/testx/create_test.go +++ b/runner/create_test.go @@ -1,6 +1,6 @@ //go:build test -package testx +package runner import ( "github.com/stretchr/testify/assert" diff --git a/runner/stub.go b/runner/stub.go index 3282fe8..9899b0d 100644 --- a/runner/stub.go +++ b/runner/stub.go @@ -11,6 +11,11 @@ import ( type Stub struct { } +func (s Stub) File(src *model.Source) string { + //TODO implement me + panic("implement me") +} + func (s Stub) Matches(input string) bool { //TODO implement me panic("implement me") @@ -108,7 +113,7 @@ func (h HydratedStub) Icon() string { panic("implement me") } -func (h HydratedStub) Description() string { +func (h HydratedStub) Description(src *model.HydratedSource) string { //TODO implement me panic("implement me") } diff --git a/search/search_test.go b/search/search_test.go index 3671f75..7246ffc 100644 --- a/search/search_test.go +++ b/search/search_test.go @@ -4,121 +4,121 @@ package search import ( "github.com/stretchr/testify/assert" - "pik/testx" + "pik/runner" "testing" ) func TestSearch_TargetOnly(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def")) + st := runner.TState(runner.TSource("src", "abc", "def")) res := Search(st, "def") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "def", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "def", res.Target) } func TestSearch_TargetAndSource(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def")) + st := runner.TState(runner.TSource("src", "abc", "def")) res := Search(st, "src", "def") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "def", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "def", res.Target) } func TestSearch_TargetAndSource_CaseInsensitive(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def")) + st := runner.TState(runner.TSource("src", "abc", "def")) res := Search(st, "SRC", "DeF") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "def", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "def", res.Target) } func TestSearch_SourceDefaultTarget(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "src")) + st := runner.TState(runner.TSource("src", "abc", "src")) res := Search(st, "src") - testx.AssertSourceIs(t, "src", res.Source) + runner.AssertSourceIs(t, "src", res.Source) assert.NotNil(t, res.Target) } func TestSearch_SubdirWrong(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "src")) - st.Sources[0].Targets = append(st.Sources[0].Targets, testx.TTarget("script", "subdir")) + st := runner.TState(runner.TSource("src", "abc", "src")) + st.Sources[0].Targets = append(st.Sources[0].Targets, runner.TTarget("script", "subdir")) res := Search(st, "wrong", "script") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "script", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "script", res.Target) assert.Equal(t, []string{"wrong"}, res.Sub) assert.NotNil(t, res.Target) assert.True(t, res.NeedsConfirmation) } func TestSearch_SubdirMissing(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "src")) - st.Sources[0].Targets = append(st.Sources[0].Targets, testx.TTarget("script", "subdir")) + st := runner.TState(runner.TSource("src", "abc", "src")) + st.Sources[0].Targets = append(st.Sources[0].Targets, runner.TTarget("script", "subdir")) res := Search(st, "script") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "script", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "script", res.Target) assert.Nil(t, res.Sub) assert.NotNil(t, res.Target) assert.False(t, res.NeedsConfirmation) } func TestSearch_Args(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def")) + st := runner.TState(runner.TSource("src", "abc", "def")) res := Search(st, "def", "a1", "a2") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "def", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "def", res.Target) assert.Equal(t, []string{"a1", "a2"}, res.Args) } func TestSearch_Args_SubdirMissing(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "src")) - st.Sources[0].Targets = append(st.Sources[0].Targets, testx.TTarget("script", "subdir")) + st := runner.TState(runner.TSource("src", "abc", "src")) + st.Sources[0].Targets = append(st.Sources[0].Targets, runner.TTarget("script", "subdir")) res := Search(st, "script", "a1", "a2") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "script", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "script", res.Target) assert.Equal(t, []string{"a1", "a2"}, res.Args) } func TestSearch_Args_SubdirPresent(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "src")) - st.Sources[0].Targets = append(st.Sources[0].Targets, testx.TTarget("script", "subdir")) + st := runner.TState(runner.TSource("src", "abc", "src")) + st.Sources[0].Targets = append(st.Sources[0].Targets, runner.TTarget("script", "subdir")) res := Search(st, "subdir", "script", "a1", "a2") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "script", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "script", res.Target) assert.Equal(t, []string{"a1", "a2"}, res.Args) } func TestSearch_SecondarySource(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def"), testx.TSource("aaa", "hjkl")) + st := runner.TState(runner.TSource("src", "abc", "def"), runner.TSource("aaa", "hjkl")) res := Search(st, "aaa", "hjkl") - testx.AssertSourceIs(t, "aaa", res.Source) - testx.AssertTargetIs(t, "hjkl", res.Target) + runner.AssertSourceIs(t, "aaa", res.Source) + runner.AssertTargetIs(t, "hjkl", res.Target) } func TestSearch_SecondarySource_DuplicateTargetName(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def"), testx.TSource("aaa", "abc")) + st := runner.TState(runner.TSource("src", "abc", "def"), runner.TSource("aaa", "abc")) res := Search(st, "aaa", "def") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "def", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "def", res.Target) assert.True(t, res.NeedsConfirmation) } func TestSearch_SourceTargetMixup(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc"), testx.TSource("aaa", "ccc")) + st := runner.TState(runner.TSource("src", "abc"), runner.TSource("aaa", "ccc")) res := Search(st, "src", "ccc") - testx.AssertSourceIs(t, "aaa", res.Source) - testx.AssertTargetIs(t, "ccc", res.Target) + runner.AssertSourceIs(t, "aaa", res.Source) + runner.AssertTargetIs(t, "ccc", res.Target) assert.True(t, res.NeedsConfirmation) } func TestSearch_Override(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc.override.sh", "abc.sh")) + st := runner.TState(runner.TSource("src", "abc.override.sh", "abc.sh")) res := Search(st, "src", "abc") - assert.Equal(t, "abc.override.sh", res.Target.(*testx.TestTarget).Id.Full) + assert.Equal(t, "abc.override.sh", res.Target.(*runner.TestTarget).Id.Full) assert.False(t, res.NeedsConfirmation) } func TestSearch_SubdirDefault(t *testing.T) { - tgt := testx.TTarget("subname", "subname") - src := testx.TSource("src") + tgt := runner.TTarget("subname", "subname") + src := runner.TSource("src") src.Targets = append(src.Targets, tgt) - st := testx.TState(src) + st := runner.TState(src) res := Search(st, "subname") assert.Nil(t, res.Args) assert.Equal(t, res.Target, tgt) @@ -126,8 +126,8 @@ func TestSearch_SubdirDefault(t *testing.T) { } func TestSearch_SourceDefault(t *testing.T) { - src := testx.TSource("sourcename", "sourcename") - st := testx.TState(src) + src := runner.TSource("sourcename", "sourcename") + st := runner.TState(src) res := Search(st, "sourcename") assert.Nil(t, res.Args) assert.Equal(t, res.Target, src.Targets[0]) @@ -135,8 +135,8 @@ func TestSearch_SourceDefault(t *testing.T) { } func TestSearch_SourceDefault_Other(t *testing.T) { - src := testx.TSource("src", "src", "other") - st := testx.TState(src) + src := runner.TSource("src", "src", "other") + st := runner.TState(src) res := Search(st, "src", "other") assert.Nil(t, res.Args) assert.Equal(t, res.Target, src.Targets[1]) @@ -144,11 +144,11 @@ func TestSearch_SourceDefault_Other(t *testing.T) { } func TestSearch_SubdirDefault_Other(t *testing.T) { - tgt := testx.TTarget("subname", "subname") - other := testx.TTarget("othername", "subname") - src := testx.TSource("src") + tgt := runner.TTarget("subname", "subname") + other := runner.TTarget("othername", "subname") + src := runner.TSource("src") src.Targets = append(src.Targets, tgt, other) - st := testx.TState(src) + st := runner.TState(src) res := Search(st, "subname", "othername") assert.Nil(t, res.Args) assert.Equal(t, other, res.Target) diff --git a/spool/spool.go b/spool/spool.go index 4dc7b87..e7b13e9 100644 --- a/spool/spool.go +++ b/spool/spool.go @@ -5,8 +5,15 @@ import ( "os" ) -var Print = fmt.Printf +var ( + Stderr = os.Stderr + Stdout = os.Stdout +) + +var Print = func(format string, values ...any) (any, error) { + return fmt.Fprintf(Stdout, format, values...) +} var Warn = func(format string, values ...any) (any, error) { - return fmt.Fprintf(os.Stderr, format, values...) + return fmt.Fprintf(Stderr, format, values...) } diff --git a/viewport/viewport.go b/viewport/viewport.go index ff1ca05..7b897e7 100644 --- a/viewport/viewport.go +++ b/viewport/viewport.go @@ -52,9 +52,9 @@ func Crop(input string, lines []string, height int) (output string, scrollStart } if end >= size { - diff := size - 1 - end - start += diff - end += diff + diff := end - size + start -= diff + end -= diff } scrollStart = float32(start) / float32(size) |
