Skip to content

Commit aa0a415

Browse files
committed
Parse config files to determine set of dirs to watch
1 parent 80ad647 commit aa0a415

1 file changed

Lines changed: 46 additions & 26 deletions

File tree

tools/watch/api.go

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import (
66
"fmt"
77
"os"
88
"path/filepath"
9+
"sort"
910
"strconv"
10-
"sync"
11+
"strings"
1112
"time"
1213

1314
"github.com/sgtdi/fswatcher"
@@ -38,17 +39,48 @@ func watch_dir(ctx context.Context, path string, debounce time.Duration, eventCh
3839
return nil
3940
}
4041

41-
type config_file_collection struct {
42-
mutex sync.Mutex
43-
config_paths []string
44-
dirs_to_watch []string
42+
// returns the closest unique parent directories for a list of paths.
43+
// It excludes any directory that is a subdirectory of another directory already in the result set.
44+
func get_unique_directories(paths []string) []string {
45+
if len(paths) == 0 {
46+
return nil
47+
}
48+
49+
// 1. Extract parent directories and remove duplicates
50+
dirMap := utils.NewSet[string](len(paths))
51+
for _, p := range paths {
52+
dirMap.Add(filepath.Dir(p))
53+
}
54+
55+
// 2. Convert map to a sorted slice
56+
// Sorting ensures that shorter paths (potential parents) come before longer ones (potential children)
57+
uniqueDirs := dirMap.AsSlice()
58+
sort.Strings(uniqueDirs)
59+
60+
// 3. Filter out subdirectories
61+
var result []string
62+
for _, current := range uniqueDirs {
63+
isSubDir := false
64+
for _, parent := range result {
65+
// Check if 'current' is a subdirectory of 'parent'
66+
// Strings.HasPrefix is safe here because paths are sorted and Cleaned by filepath.Dir
67+
if current == parent || strings.HasPrefix(current, parent+string(filepath.Separator)) {
68+
isSubDir = true
69+
break
70+
}
71+
}
72+
if !isSubDir {
73+
result = append(result, current)
74+
}
75+
}
76+
return result
4577
}
4678

47-
func (cfc *config_file_collection) get_list_of_config_files() *utils.Set[string] {
79+
func get_set_of_config_files(config_paths []string) *utils.Set[string] {
4880
cp := config.ConfigParser{
4981
AllIncludedFiles: utils.NewSet[string](), LineHandler: func(k, v string) error { return nil }}
50-
cp.ParseFiles(cfc.config_paths...)
51-
for _, path := range cfc.config_paths {
82+
cp.ParseFiles(config_paths...)
83+
for _, path := range config_paths {
5284
path = filepath.Clean(path)
5385
cp.AllIncludedFiles.Add(path)
5486
for _, q := range []string{"dark-theme.auto.conf", "light-theme.auto.conf", "no-preference-theme.auto.conf"} {
@@ -59,36 +91,24 @@ func (cfc *config_file_collection) get_list_of_config_files() *utils.Set[string]
5991
return cp.AllIncludedFiles
6092
}
6193

62-
func (cfc *config_file_collection) EventIsSignificant(ev fswatcher.WatchEvent) bool {
63-
cfc.mutex.Lock()
64-
defer cfc.mutex.Unlock()
65-
conf_files := cfc.get_list_of_config_files()
66-
q := filepath.Clean(ev.Path)
67-
return conf_files.Has(q)
68-
}
69-
7094
func watch_for_kitty_config_changes(action func() error, debounce_time time.Duration, config_paths []string) error {
7195
ctx, cancel := context.WithCancel(context.Background())
7296
defer cancel()
7397
event_chan := make(chan fswatcher.WatchEvent)
74-
dirs := utils.NewSet[string](len(config_paths))
75-
for _, path := range config_paths {
76-
if parent := filepath.Dir(path); parent != "" && parent != "." && parent != "/" {
77-
dirs.Add(path)
78-
}
79-
}
80-
if dirs.Len() == 0 {
98+
all_paths := get_set_of_config_files(config_paths)
99+
dirs_to_watch := get_unique_directories(all_paths.AsSlice())
100+
if len(dirs_to_watch) == 0 {
81101
return fmt.Errorf("No directories to watch provided")
82102
}
83-
cfc := config_file_collection{config_paths: config_paths, dirs_to_watch: dirs.AsSlice()}
84103

85104
filtered_action := func(ev fswatcher.WatchEvent) error {
86-
if cfc.EventIsSignificant(ev) {
105+
all_paths := get_set_of_config_files(config_paths)
106+
if all_paths.Has(filepath.Clean(ev.Path)) {
87107
return action()
88108
}
89109
return nil
90110
}
91-
for _, path := range cfc.dirs_to_watch {
111+
for _, path := range dirs_to_watch {
92112
if err := watch_dir(ctx, path, debounce_time, event_chan); err != nil {
93113
return err
94114
}

0 commit comments

Comments
 (0)