|
9 | 9 |
|
10 | 10 | (set! *warn-on-reflection* true) |
11 | 11 |
|
12 | | -(defn ^:private single-text-content [text & [error]] |
13 | | - {:contents [{:type :text |
14 | | - :content text |
15 | | - :error (boolean error)}]}) |
16 | | - |
17 | 12 | (defn ^:private allowed-path? [db path] |
18 | 13 | (some #(fs/starts-with? path (shared/uri->filename (:uri %))) |
19 | 14 | (:workspace-folders db))) |
20 | 15 |
|
21 | | -(defn ^:private invalid-arguments [arguments validator] |
22 | | - (first (keep (fn [[key pred error-msg]] |
23 | | - (let [value (get arguments key)] |
24 | | - (when-not (pred value) |
25 | | - (single-text-content (string/replace error-msg (str "$" key) (str value)) :error)))) |
26 | | - validator))) |
27 | | - |
28 | 16 | (defn ^:private path-validations [db] |
29 | 17 | [["path" fs/exists? "$path is not a valid path"] |
30 | 18 | ["path" (partial allowed-path? db) (str "Access denied - path $path outside allowed directories: " (tools.util/workspace-roots-strs db))]]) |
31 | 19 |
|
32 | | -(defn ^:private list-directory [arguments db] |
| 20 | +(defn ^:private list-directory [arguments {:keys [db]}] |
33 | 21 | (let [path (delay (fs/canonicalize (get arguments "path")))] |
34 | | - (or (invalid-arguments arguments (path-validations db)) |
35 | | - (single-text-content |
| 22 | + (or (tools.util/invalid-arguments arguments (path-validations db)) |
| 23 | + (tools.util/single-text-content |
36 | 24 | (reduce |
37 | 25 | (fn [out path] |
38 | 26 | (str out |
|
42 | 30 | "" |
43 | 31 | (fs/list-dir @path)))))) |
44 | 32 |
|
45 | | -(defn ^:private read-file [arguments db] |
46 | | - (or (invalid-arguments arguments (concat (path-validations db) |
47 | | - [["path" fs/readable? "File $path is not readable"]])) |
| 33 | +(defn ^:private read-file [arguments {:keys [db]}] |
| 34 | + (or (tools.util/invalid-arguments arguments (concat (path-validations db) |
| 35 | + [["path" fs/readable? "File $path is not readable"]])) |
48 | 36 | (let [head (get arguments "head") |
49 | 37 | tail (get arguments "tail") |
50 | 38 | content (cond-> (slurp (fs/file (fs/canonicalize (get arguments "path")))) |
|
54 | 42 | tail (->> (string/split-lines) |
55 | 43 | (take-last tail) |
56 | 44 | (string/join "\n")))] |
57 | | - (single-text-content content)))) |
| 45 | + (tools.util/single-text-content content)))) |
58 | 46 |
|
59 | | -(defn ^:private write-file [arguments db] |
60 | | - (or (invalid-arguments arguments [["path" (partial allowed-path? db) (str "Access denied - path $path outside allowed directories: " (tools.util/workspace-roots-strs db))]]) |
| 47 | +(defn ^:private write-file [arguments {:keys [db]}] |
| 48 | + (or (tools.util/invalid-arguments arguments [["path" (partial allowed-path? db) (str "Access denied - path $path outside allowed directories: " (tools.util/workspace-roots-strs db))]]) |
61 | 49 | (let [path (get arguments "path") |
62 | 50 | content (get arguments "content")] |
63 | 51 | (fs/create-dirs path) |
64 | 52 | (spit path content) |
65 | | - (single-text-content (format "Successfully wrote to %s" path))))) |
| 53 | + (tools.util/single-text-content (format "Successfully wrote to %s" path))))) |
66 | 54 |
|
67 | | -(defn ^:private search-files [arguments db] |
68 | | - (or (invalid-arguments arguments (concat (path-validations db) |
69 | | - [["pattern" #(not (string/blank? %)) "Invalid glob pattern '$pattern'"]])) |
| 55 | +(defn ^:private search-files [arguments {:keys [db]}] |
| 56 | + (or (tools.util/invalid-arguments arguments (concat (path-validations db) |
| 57 | + [["pattern" #(not (string/blank? %)) "Invalid glob pattern '$pattern'"]])) |
70 | 58 | (let [pattern (get arguments "pattern") |
71 | 59 | pattern (if (string/includes? pattern "*") |
72 | 60 | pattern |
|
77 | 65 | pattern))) |
78 | 66 | [] |
79 | 67 | (:workspace-folders db))] |
80 | | - (single-text-content (if (seq paths) |
81 | | - (string/join "\n" paths) |
82 | | - "No matches found"))))) |
| 68 | + (tools.util/single-text-content (if (seq paths) |
| 69 | + (string/join "\n" paths) |
| 70 | + "No matches found"))))) |
83 | 71 |
|
84 | 72 | (defn ^:private run-ripgrep [path pattern include] |
85 | 73 | (let [cmd (cond-> ["rg" "--files-with-matches" "--no-heading"] |
|
147 | 135 |
|
148 | 136 | Returns matching file paths, prioritizing by modification time when possible. |
149 | 137 | Validates that the search path is within allowed workspace directories." |
150 | | - [arguments db] |
151 | | - (or (invalid-arguments arguments (concat (path-validations db) |
152 | | - [["path" fs/readable? "File $path is not readable"] |
153 | | - ["pattern" #(and % (not (string/blank? %))) "Invalid content regex pattern '$pattern'"] |
154 | | - ["include" #(or (nil? %) (not (string/blank? %))) "Invalid file pattern '$include'"] |
155 | | - ["max_results" #(or (nil? %) number?) "Invalid number '$max_results'"]])) |
| 138 | + [arguments {:keys [db]}] |
| 139 | + (or (tools.util/invalid-arguments arguments (concat (path-validations db) |
| 140 | + [["path" fs/readable? "File $path is not readable"] |
| 141 | + ["pattern" #(and % (not (string/blank? %))) "Invalid content regex pattern '$pattern'"] |
| 142 | + ["include" #(or (nil? %) (not (string/blank? %))) "Invalid file pattern '$include'"] |
| 143 | + ["max_results" #(or (nil? %) number?) "Invalid number '$max_results'"]])) |
156 | 144 | (let [path (get arguments "path") |
157 | 145 | pattern (get arguments "pattern") |
158 | 146 | include (get arguments "include") |
|
169 | 157 | (run-java-grep path pattern include)) |
170 | 158 | (take max-results))] |
171 | 159 | ;; TODO sort by modification time. |
172 | | - (single-text-content (if (seq paths) |
173 | | - (string/join "\n" paths) |
174 | | - "No files found for given pattern"))))) |
| 160 | + (tools.util/single-text-content (if (seq paths) |
| 161 | + (string/join "\n" paths) |
| 162 | + "No files found for given pattern"))))) |
175 | 163 |
|
176 | | -(defn ^:private replace-in-file [arguments db] |
177 | | - (or (invalid-arguments arguments (concat (path-validations db) |
178 | | - [["path" fs/readable? "File $path is not readable"]])) |
| 164 | +(defn ^:private replace-in-file [arguments {:keys [db]}] |
| 165 | + (or (tools.util/invalid-arguments arguments (concat (path-validations db) |
| 166 | + [["path" fs/readable? "File $path is not readable"]])) |
179 | 167 | (let [path (get arguments "path") |
180 | 168 | original-content (get arguments "original_content") |
181 | 169 | new-content (get arguments "new_content") |
182 | 170 | all? (boolean (get arguments "all_occurrences")) |
183 | 171 | content (slurp path)] |
184 | | - (single-text-content |
| 172 | + (tools.util/single-text-content |
185 | 173 | (if (string/includes? content original-content) |
186 | 174 | (let [content (if all? |
187 | 175 | (string/replace content original-content new-content) |
|
190 | 178 | (format "Successfully replaced content in %s." path)) |
191 | 179 | (format "Original content not found in %s" path)))))) |
192 | 180 |
|
193 | | -(defn ^:private move-file [arguments db] |
| 181 | +(defn ^:private move-file [arguments {:keys [db]}] |
194 | 182 | (let [workspace-dirs (tools.util/workspace-roots-strs db)] |
195 | | - (or (invalid-arguments arguments [["source" fs/exists? "$source is not a valid path"] |
196 | | - ["source" (partial allowed-path? db) (str "Access denied - path $source outside allowed directories: " workspace-dirs)] |
197 | | - ["destination" (partial allowed-path? db) (str "Access denied - path $destination outside allowed directories: " workspace-dirs)] |
198 | | - ["destination" (complement fs/exists?) "Path $destination already exists"]]) |
| 183 | + (or (tools.util/invalid-arguments arguments [["source" fs/exists? "$source is not a valid path"] |
| 184 | + ["source" (partial allowed-path? db) (str "Access denied - path $source outside allowed directories: " workspace-dirs)] |
| 185 | + ["destination" (partial allowed-path? db) (str "Access denied - path $destination outside allowed directories: " workspace-dirs)] |
| 186 | + ["destination" (complement fs/exists?) "Path $destination already exists"]]) |
199 | 187 | (let [source (get arguments "source") |
200 | 188 | destination (get arguments "destination")] |
201 | 189 | (fs/move source destination {:replace-existing false}) |
202 | | - (single-text-content (format "Successfully moved %s to %s" source destination)))))) |
| 190 | + (tools.util/single-text-content (format "Successfully moved %s to %s" source destination)))))) |
203 | 191 |
|
204 | 192 | (def definitions |
205 | 193 | {"list_directory" |
|
0 commit comments