|
37 | 37 | file-paths |
38 | 38 | (get-in config [:index :ignoreFiles]))) |
39 | 39 |
|
40 | | -(defn insert-path [tree parts] |
| 40 | +(defn ^:private insert-path [tree parts] |
41 | 41 | (if (empty? parts) |
42 | 42 | tree |
43 | 43 | (let [head (first parts) |
44 | 44 | tail (rest parts)] |
45 | 45 | (update tree head #(insert-path (or % {}) tail))))) |
46 | 46 |
|
47 | | -(defn tree->str |
48 | | - ([tree] (tree->str tree 0)) |
49 | | - ([tree indent] |
50 | | - (let [indent-str (fn [level] (apply str (repeat (* 1 level) " ")))] |
51 | | - (apply str |
52 | | - (mapcat (fn [[k v]] |
53 | | - (let [current-line (str (indent-str indent) k "\n") |
54 | | - children-str (when (seq v) |
55 | | - (tree->str v (inc indent)))] |
56 | | - [current-line children-str])) |
57 | | - (sort tree)))))) |
| 47 | +;; Count how many nodes (lines) a tree would render |
| 48 | +(defn ^:private tree-count [tree] |
| 49 | + (reduce (fn [cnt [_k v]] |
| 50 | + (let [self 1 |
| 51 | + children (if (seq v) (tree-count v) 0)] |
| 52 | + (+ cnt self children))) |
| 53 | + 0 |
| 54 | + tree)) |
58 | 55 |
|
59 | | -(defn repo-map [db & {:keys [as-string?]}] |
60 | | - (let [tree (reduce |
61 | | - (fn [t {:keys [uri]}] |
62 | | - (let [root-filename (shared/uri->filename uri) |
63 | | - files (git-ls-files root-filename)] |
64 | | - (merge t |
65 | | - {root-filename |
66 | | - (reduce |
67 | | - (fn [tree path] |
68 | | - (insert-path tree (clojure.string/split path #"/"))) |
69 | | - {} |
70 | | - files)}))) |
71 | | - {} |
72 | | - (:workspace-folders db))] |
73 | | - (if as-string? |
74 | | - (tree->str tree) |
75 | | - tree))) |
| 56 | +;; Render tree with limits: global max entries and per-directory max entries (non-root only) |
| 57 | +(defn ^:private tree->str-limited |
| 58 | + [tree max-total-entries max-entries-per-dir] |
| 59 | + (let [indent-str (fn [level] (apply str (repeat (* 1 level) " "))) |
| 60 | + remaining (atom max-total-entries) |
| 61 | + printed-lines (atom 0) ;; all printed lines (nodes + indicator lines) |
| 62 | + printed-actual (atom 0) ;; only actual tree nodes |
| 63 | + sb (StringBuilder.) |
| 64 | + ;; emit a single line if we still have remaining budget |
| 65 | + emit-line (fn [^String s] |
| 66 | + (when (pos? @remaining) |
| 67 | + (.append sb s) |
| 68 | + (swap! remaining dec) |
| 69 | + (swap! printed-lines inc))) |
| 70 | + emit-node (fn [^String s] |
| 71 | + (when (pos? @remaining) |
| 72 | + (.append sb s) |
| 73 | + (swap! remaining dec) |
| 74 | + (swap! printed-lines inc) |
| 75 | + (swap! printed-actual inc))) |
| 76 | + ;; recursive emit of a level (all entries in map m) |
| 77 | + emit-level (fn emit-level [m indent-level root?] |
| 78 | + (let [entries (sort m) |
| 79 | + ;; Apply per-dir limit to the current level if not root |
| 80 | + entries-vec (vec entries) |
| 81 | + [to-show hidden] (if root? |
| 82 | + [entries-vec []] |
| 83 | + [(subvec entries-vec 0 (min (count entries-vec) max-entries-per-dir)) |
| 84 | + (subvec entries-vec (min (count entries-vec) max-entries-per-dir))])] |
| 85 | + (doseq [[k v] to-show] |
| 86 | + (when (pos? @remaining) |
| 87 | + (emit-node (str (indent-str indent-level) k "\n")) |
| 88 | + (when (seq v) |
| 89 | + (emit-level v (inc indent-level) false)))) |
| 90 | + (when (and (seq hidden) (pos? @remaining) (not root?)) |
| 91 | + (emit-line (str (indent-str indent-level) "... truncated output (" |
| 92 | + (count hidden) " more entries)\n")))))] |
| 93 | + (emit-level tree 0 true) |
| 94 | + ;; Compute total possible nodes and append global truncation line if needed |
| 95 | + (let [total (tree-count tree) |
| 96 | + omitted (- total @printed-actual)] |
| 97 | + (when (pos? omitted) |
| 98 | + (.append sb (str "... truncated output (" omitted " more entries)\n")))) |
| 99 | + (str sb))) |
| 100 | + |
| 101 | +(defn repo-map |
| 102 | + ([db config] (repo-map db config {})) |
| 103 | + ([db config {:keys [as-string?]}] |
| 104 | + (let [tree (reduce |
| 105 | + (fn [t {:keys [uri]}] |
| 106 | + (let [root-filename (shared/uri->filename uri) |
| 107 | + files (git-ls-files root-filename)] |
| 108 | + (merge t |
| 109 | + {root-filename |
| 110 | + (reduce |
| 111 | + (fn [tree path] |
| 112 | + (insert-path tree (clojure.string/split path #"/"))) |
| 113 | + {} |
| 114 | + files)}))) |
| 115 | + {} |
| 116 | + (:workspace-folders db))] |
| 117 | + (if as-string? |
| 118 | + (let [{:keys [maxTotalEntries maxEntriesPerDir]} (get-in config [:index :repoMap])] |
| 119 | + (tree->str-limited tree maxTotalEntries maxEntriesPerDir)) |
| 120 | + tree)))) |
76 | 121 |
|
77 | 122 | (comment |
78 | 123 | (require 'user) |
79 | 124 | (user/with-workspace-root "file:///home/greg/dev/eca" |
80 | | - (println (repo-map user/*db* {:as-string? true})))) |
| 125 | + (println (repo-map user/*db* {:max-total-entries 1000 :max-entries-per-dir 200} {:as-string? true})))) |
0 commit comments