|
2 | 2 | "Paredit zipper operations for Clojure/ClojureScript/EDN.
|
3 | 3 |
|
4 | 4 | You might find inspiration from examples here: http://pub.gajendra.net/src/paredit-refcard.pdf"
|
5 |
| - (:require [rewrite-clj.custom-zipper.core :as zraw] |
| 5 | + (:require [clojure.string :as str] |
| 6 | + [rewrite-clj.custom-zipper.core :as zraw] |
6 | 7 | [rewrite-clj.custom-zipper.utils :as u]
|
7 | 8 | [rewrite-clj.node :as nd]
|
8 | 9 | [rewrite-clj.zip :as z]
|
|
133 | 134 | (or (u/remove-and-move-left zloc)
|
134 | 135 | (z/remove* zloc))))
|
135 | 136 |
|
136 |
| -(defn- kill-in-string-node [zloc pos] |
137 |
| - (if (= (z/string zloc) "\"\"") |
138 |
| - (z/remove zloc) |
139 |
| - (let [bounds (-> zloc z/node meta) |
140 |
| - row-idx (- (:row pos) (:row bounds)) |
141 |
| - sub-length (if-not (= (:row pos) (:row bounds)) |
142 |
| - (dec (:col pos)) |
143 |
| - (- (:col pos) (inc (:col bounds))))] |
144 |
| - |
145 |
| - (-> (take (inc row-idx) (-> zloc z/node :lines)) |
146 |
| - vec |
147 |
| - (update-in [row-idx] #(subs % 0 sub-length)) |
148 |
| - (#(z/replace zloc (nd/string-node %))))))) |
149 |
| - |
150 |
| -(defn- kill-in-comment-node [zloc pos] |
151 |
| - (let [col-bounds (-> zloc z/node meta :col)] |
152 |
| - (if (= (:col pos) col-bounds) |
153 |
| - (z/remove zloc) |
154 |
| - (-> zloc |
155 |
| - (z/replace (-> zloc |
156 |
| - z/node |
157 |
| - :s |
158 |
| - (subs 0 (- (:col pos) col-bounds 1)) |
159 |
| - nd/comment-node)) |
160 |
| - (#(if (z/right* %) |
161 |
| - (z/insert-right* % (nd/newlines 1)) |
162 |
| - %)))))) |
| 137 | +(defn- kill-in-string-node [zloc [kill-row kill-col]] |
| 138 | + (let [[elem-row elem-col] (z/position zloc) |
| 139 | + lines-ndx (- kill-row elem-row) |
| 140 | + sub-length (if (= kill-row elem-row) |
| 141 | + (- kill-col (inc elem-col)) |
| 142 | + (dec kill-col)) |
| 143 | + cur-lines (-> zloc z/node :lines) |
| 144 | + new-lines (-> (take (inc lines-ndx) cur-lines) |
| 145 | + vec |
| 146 | + (update-in [lines-ndx] #(subs % 0 sub-length)))] |
| 147 | + (z/replace zloc (nd/string-node new-lines)))) |
| 148 | + |
| 149 | +(defn- kill-in-comment-node [zloc [_kill-row kill-col]] |
| 150 | + (let [[_elem-row elem-col] (z/position zloc) |
| 151 | + cur-comment (-> zloc z/node :s) |
| 152 | + ;; comments contain their newline, preserve it if present |
| 153 | + suffix (when (str/ends-with? cur-comment "\n") "\n") |
| 154 | + new-comment (str (subs cur-comment 0 (-> kill-col (- elem-col) dec)) suffix)] |
| 155 | + (z/replace zloc (nd/comment-node new-comment)))) |
163 | 156 |
|
164 | 157 | (defn kill-at-pos
|
165 |
| - "In string and comment aware kill |
| 158 | + "Return `zloc` with found item starting at `pos` removed to its natural end. |
166 | 159 |
|
167 |
| - Perform kill for given position `pos` Like [[kill]], but: |
| 160 | + If `pos` is: |
168 | 161 |
|
169 |
| - - if inside string kills to end of string and stops there |
170 |
| - - If inside comment kills to end of line (not including linebreak) |
| 162 | + - inside a string, removes all characters in string starting at `pos` to the end of the string |
| 163 | + - is inside a comment, removes all characters in comment starting at `pos` to the end of line |
| 164 | + (not including comment linebreak, if present) |
| 165 | + - otherwise, executes [[kill]] at node found from `pos` |
171 | 166 |
|
172 |
| - - `zloc` location is (inclusive) starting point for `pos` depth-first search |
173 |
| - - `pos` can be a `{:row :col}` map or a `[row col]` vector. The `row` and `col` values are |
| 167 | + `zloc` location is (exclusive) starting point for `pos` search |
| 168 | + `pos` can be a `{:row :col}` map or a `[row col]` vector. The `row` and `col` values are |
174 | 169 | 1-based and relative to the start of the source code the zipper represents.
|
175 | 170 |
|
176 |
| - Throws if `zloc` was not created with [position tracking](/doc/01-user-guide.adoc#position-tracking)." |
| 171 | + Throws if `zloc` was not created with [position tracking](/doc/01-user-guide.adoc#position-tracking). |
| 172 | +
|
| 173 | + - `[:foo \"Hello |World\"]` => [:foo |\"Hello \"]` |
| 174 | + - `42 ;; A comment| of some length => 42 |;; A comment` |
| 175 | + - `[:foo |\"Hello World\"] => [|:foo ]`" |
177 | 176 | [zloc pos]
|
178 | 177 | (if-let [candidate (z/find-last-by-pos zloc pos)]
|
179 |
| - (let [pos (fz/pos-as-map pos)] |
| 178 | + (let [pos (fz/pos-as-vec pos) |
| 179 | + [candidate-pos candidate-end-pos] (-> candidate z/position-span) |
| 180 | + candidate-end-pos (update candidate-end-pos 1 dec)] |
180 | 181 | (cond
|
181 |
| - (string-node? candidate) (kill-in-string-node candidate pos) |
182 |
| - (ws/comment? candidate) (kill-in-comment-node candidate pos) |
183 |
| - (and (empty-seq? candidate) |
184 |
| - (> (:col pos) (-> candidate z/node meta :col))) (z/remove candidate) |
185 |
| - :else (kill candidate))) |
| 182 | + (and (string-node? candidate) |
| 183 | + (not= candidate-pos pos) |
| 184 | + (not= candidate-end-pos pos)) |
| 185 | + (kill-in-string-node candidate pos) |
| 186 | + |
| 187 | + (and (ws/comment? candidate) |
| 188 | + (not= candidate-pos pos)) |
| 189 | + (kill-in-comment-node candidate pos) |
| 190 | + |
| 191 | + :else |
| 192 | + (kill candidate))) |
186 | 193 | zloc))
|
187 | 194 |
|
188 | 195 | (defn- find-word-bounds
|
|
214 | 221 | (subs s end))
|
215 | 222 | s))
|
216 | 223 |
|
217 |
| -(defn- kill-word-in-comment-node [zloc pos] |
218 |
| - (let [col-bounds (-> zloc z/position fz/pos-as-map :col)] |
| 224 | +(defn- kill-word-in-comment-node [zloc [_kill-row kill-col]] |
| 225 | + (let [[_elem-row elem-col] (z/position zloc)] |
219 | 226 | (-> zloc
|
220 | 227 | (z/replace (-> zloc
|
221 | 228 | z/node
|
222 | 229 | :s
|
223 |
| - (remove-word-at (- (:col pos) col-bounds)) |
| 230 | + (remove-word-at (- kill-col elem-col)) |
224 | 231 | nd/comment-node)))))
|
225 | 232 |
|
226 |
| -(defn- kill-word-in-string-node [zloc pos] |
227 |
| - (let [bounds (-> zloc z/position fz/pos-as-map) |
228 |
| - row-idx (- (:row pos) (:row bounds)) |
229 |
| - col (if (= 0 row-idx) |
230 |
| - (- (:col pos) (:col bounds)) |
231 |
| - (:col pos))] |
| 233 | +(defn- kill-word-in-string-node [zloc [kill-row kill-col]] |
| 234 | + (let [[elem-row elem-col] (z/position zloc) |
| 235 | + row-ndx (- kill-row elem-row) |
| 236 | + col (if (= 0 row-ndx) |
| 237 | + (- kill-col elem-col) |
| 238 | + kill-col)] |
232 | 239 | (-> zloc
|
233 | 240 | (z/replace (-> zloc
|
234 | 241 | z/node
|
235 | 242 | :lines
|
236 |
| - (update-in [row-idx] |
| 243 | + (update-in [row-ndx] |
237 | 244 | #(remove-word-at % col))
|
238 | 245 | nd/string-node)))))
|
239 | 246 |
|
|
259 | 266 | [zloc pos]
|
260 | 267 | (if-let [candidate (->> (z/find-last-by-pos zloc pos)
|
261 | 268 | (ws/skip z/right* ws/whitespace?))]
|
262 |
| - (let [pos (fz/pos-as-map pos) |
263 |
| - candidate-pos (-> candidate z/position fz/pos-as-map) |
264 |
| - kill-in-node? (not (and (= (:row pos) (:row candidate-pos)) |
265 |
| - (<= (:col pos) (:col candidate-pos))))] |
| 269 | + (let [pos (fz/pos-as-vec pos) |
| 270 | + [candidate-pos candidate-end-pos] (-> candidate z/position-span) |
| 271 | + candidate-end-pos (update candidate-end-pos 1 dec)] |
266 | 272 | (cond
|
267 |
| - (and kill-in-node? (string-node? candidate)) (kill-word-in-string-node candidate pos) |
268 |
| - (and kill-in-node? (ws/comment? candidate)) (kill-word-in-comment-node candidate pos) |
| 273 | + (and (string-node? candidate) |
| 274 | + (not= candidate-pos pos) |
| 275 | + (not= candidate-end-pos pos)) |
| 276 | + (kill-word-in-string-node candidate pos) |
| 277 | + |
| 278 | + (and (ws/comment? candidate) |
| 279 | + (not= candidate-pos pos)) |
| 280 | + (kill-word-in-comment-node candidate pos) |
| 281 | + |
269 | 282 | :else
|
270 | 283 | (or (rz/remove-and-move-left candidate)
|
271 | 284 | (z/remove candidate))))
|
|
0 commit comments