Skip to content

Commit 2f4924a

Browse files
authored
Merge pull request #66 from afucher/fix/62-case-insensitive-context-search
change query context to be case insensitive
2 parents 6e3f0fb + aad5988 commit 2f4924a

File tree

2 files changed

+112
-2
lines changed

2 files changed

+112
-2
lines changed

src/eca/features/context.clj

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
(ns eca.features.context
22
(:require
33
[babashka.fs :as fs]
4+
[clojure.string :as string]
45
[eca.config :as config]
56
[eca.features.index :as f.index]
67
[eca.features.tools.mcp :as f.mcp]
@@ -60,8 +61,15 @@
6061
contexts)))
6162

6263
(defn ^:private contexts-for [root-filename query config]
63-
(let [all-files (fs/glob root-filename (str "**" (or query "") "**"))
64-
allowed-files (f.index/filter-allowed all-files root-filename config)]
64+
(let [all-paths (fs/glob root-filename "**")
65+
query (some-> query string/trim)
66+
filtered (if (or (nil? query) (string/blank? query))
67+
all-paths
68+
(filter (fn [p]
69+
(string/includes? (-> (str p) string/lower-case)
70+
(string/lower-case query)))
71+
all-paths))
72+
allowed-files (f.index/filter-allowed filtered root-filename config)]
6573
allowed-files))
6674

6775
(defn all-contexts [query db* config]

test/eca/features/context_test.clj

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
(ns eca.features.context-test
2+
(:require
3+
[babashka.fs :as fs]
4+
[clojure.string :as string]
5+
[clojure.test :refer [deftest is testing]]
6+
[eca.features.context :as f.context]
7+
[eca.features.index :as f.index]
8+
[eca.features.tools.mcp :as f.mcp]
9+
[eca.test-helper :as h]))
10+
11+
(deftest all-contexts-test
12+
(testing "includes repoMap, root directories, files/dirs, and mcp resources"
13+
(let [root (h/file-path "/fake/repo")
14+
;; Fake filesystem entries under the root
15+
fake-paths [(str root "/dir")
16+
(str root "/foo.txt")
17+
(str root "/dir/nested.txt")
18+
(str root "/bar.txt")]
19+
db* (atom {:workspace-folders [{:uri (h/file-uri "file:///fake/repo")}]})]
20+
(with-redefs [fs/glob (fn [_root-filename pattern]
21+
;; Very simple glob: filter by substring present in pattern ("**<q>**")
22+
(let [q (string/replace pattern #"\*" "")]
23+
(filter #(string/includes? (str %) q) fake-paths)))
24+
fs/directory? (fn [p] (string/ends-with? (str p) "/dir"))
25+
fs/canonicalize identity
26+
f.index/filter-allowed (fn [file-paths _root _config] file-paths)
27+
f.mcp/all-resources (fn [_db] [{:uri "mcp://r1"}])]
28+
(let [result (f.context/all-contexts nil db* {})]
29+
;; Starts with repoMap
30+
(is (= "repoMap" (:type (first result))))
31+
;; Contains root directory entries
32+
(is (some #(= {:type "directory" :path root} %) result))
33+
;; Contains file and directory entries from the fake paths
34+
(is (some #(= {:type "directory" :path (str root "/dir")} %) result))
35+
(is (some #(= {:type "file" :path (str root "/foo.txt")} %) result))
36+
(is (some #(= {:type "file" :path (str root "/dir/nested.txt")} %) result))
37+
;; MCP resources appended with proper type
38+
(is (some #(= {:type "mcpResource" :uri "mcp://r1"} %) result))))))
39+
40+
(testing "respects the query by limiting glob results"
41+
(let [root (h/file-path "/fake/repo")
42+
fake-paths [(str root "/foo.txt")
43+
(str root "/bar.txt")]
44+
db* (atom {:workspace-folders [{:uri (h/file-uri "file:///fake/repo")}]})]
45+
(with-redefs [fs/glob (fn [_root-filename pattern]
46+
(let [q (string/replace pattern #"\*" "")]
47+
(filter #(string/includes? (str %) q) fake-paths)))
48+
fs/directory? (constantly false)
49+
fs/canonicalize identity
50+
f.index/filter-allowed (fn [file-paths _root _config] file-paths)
51+
f.mcp/all-resources (fn [_db] [])]
52+
(let [result (f.context/all-contexts "foo" db* {})]
53+
;; Should include foo.txt but not bar.txt
54+
(is (some #(= {:type "file" :path (str root "/foo.txt")} %) result))
55+
(is (not (some #(= {:type "file" :path (str root "/bar.txt")} %) result)))))))
56+
57+
(testing "aggregates entries across multiple workspace roots"
58+
(let [root1 (h/file-path "/fake/repo1")
59+
root2 (h/file-path "/fake/repo2")
60+
db* (atom {:workspace-folders [{:uri (h/file-uri "file:///fake/repo1")}
61+
{:uri (h/file-uri "file:///fake/repo2")}]})]
62+
(with-redefs [fs/glob (fn [root-filename pattern]
63+
(let [q (string/replace pattern #"\*" "")]
64+
(cond
65+
(string/includes? (str root-filename) (h/file-path "/fake/repo1"))
66+
(filter #(string/includes? (str %) q)
67+
[(str root1 "/a.clj")])
68+
69+
(string/includes? (str root-filename) (h/file-path "/fake/repo2"))
70+
(filter #(string/includes? (str %) q)
71+
[(str root2 "/b.clj")])
72+
73+
:else [])))
74+
fs/directory? (constantly false)
75+
fs/canonicalize identity
76+
f.index/filter-allowed (fn [file-paths _root _config] file-paths)
77+
f.mcp/all-resources (fn [_db] [])]
78+
(let [result (f.context/all-contexts nil db* {})]
79+
;; Root directories present
80+
(is (some #(= {:type "directory" :path root1} %) result))
81+
(is (some #(= {:type "directory" :path root2} %) result))
82+
;; Files from both roots present
83+
(is (some #(= {:type "file" :path (str root1 "/a.clj")} %) result))
84+
(is (some #(= {:type "file" :path (str root2 "/b.clj")} %) result)))))))
85+
86+
(deftest case-insensitive-query-test
87+
(testing "Should find README.md when searching for 'readme' (case-insensitive)"
88+
(let [readme (h/file-path "/fake/repo/README.md")
89+
core (h/file-path "/fake/repo/src/core.clj")]
90+
(with-redefs [fs/glob (fn [_root-filename pattern]
91+
(cond
92+
(= pattern "**") [readme core]
93+
(= pattern "**readme**") []
94+
:else []))
95+
fs/directory? (constantly false)
96+
fs/canonicalize identity
97+
f.index/filter-allowed (fn [files _root _config] files)]
98+
(let [db* (atom {:workspace-folders [{:uri (h/file-uri "file:///fake/repo")}]})
99+
config {}
100+
results (f.context/all-contexts "readme" db* config)
101+
file-paths (->> results (filter #(= "file" (:type %))) (map :path) set)]
102+
(is (contains? file-paths readme)))))))

0 commit comments

Comments
 (0)