@@ -1872,6 +1872,31 @@ functional literal node."
18721872      (clojure-ts--skip-first-child threading-sexp)
18731873      (not  (treesit-end-of-thing 'sexp  2  'restricted )))))
18741874
1875+ (defun  clojure-ts--raise-sexp  ()
1876+   " Raise current sexp one level higher up the tree.
1877+ 
1878+ The built-in `raise-sexp'  function doesn't work well with a few Clojure 
1879+ nodes (function literals, expressions with metadata etc.), it loses some 
1880+ parenthesis."  
1881+   (when-let*  ((sexp-node (treesit-thing-at (point ) 'sexp ))
1882+               (beg (thread-first  sexp-node
1883+                                  (clojure-ts--node-start-skip-metadata)
1884+                                  (copy-marker )))
1885+               (end (thread-first  sexp-node
1886+                                  (treesit-node-end)
1887+                                  (copy-marker ))))
1888+     (when-let*  ((parent (treesit-node-parent sexp-node))
1889+                 ((not  (string=  (treesit-node-type parent) " source"  )))
1890+                 (parent-beg (thread-first  parent
1891+                                           (clojure-ts--node-start-skip-metadata)
1892+                                           (copy-marker )))
1893+                 (parent-end (thread-first  parent
1894+                                           (treesit-node-end)
1895+                                           (copy-marker ))))
1896+       (save-excursion 
1897+         (delete-region  parent-beg beg)
1898+         (delete-region  end parent-end)))))
1899+ 
18751900(defun  clojure-ts--pop-out-of-threading  ()
18761901  " Raise a sexp up a level to unwind a threading form." 
18771902  (let*  ((threading-sexp (clojure-ts--threading-sexp-node))
@@ -2284,6 +2309,66 @@ before DELIM-OPEN."
22842309  (interactive )
22852310  (clojure-ts--convert-collection ?{  ?# ))
22862311
2312+ (defun  clojure-ts-cycle-conditional  ()
2313+   " Change a surrounding conditional form to its negated counterpart, or vice versa." 
2314+   (interactive )
2315+   (if-let*  ((sym-regex (rx  bol
2316+                            (or  " if"   " if-not"   " when"   " when-not"  )
2317+                            eol))
2318+             (cond-node (clojure-ts--search-list-form-at-point sym-regex t ))
2319+             (cond-sym (clojure-ts--list-node-sym-text cond-node)))
2320+       (let  ((beg (treesit-node-start cond-node))
2321+             (end-marker (copy-marker  (treesit-node-end cond-node)))
2322+             (new-sym (pcase  cond-sym
2323+                        (" if"   " if-not"  )
2324+                        (" if-not"   " if"  )
2325+                        (" when"   " when-not"  )
2326+                        (" when-not"   " when"  ))))
2327+         (save-excursion 
2328+           (goto-char  (clojure-ts--node-start-skip-metadata cond-node))
2329+           (down-list  1 )
2330+           (delete-char  (length  cond-sym))
2331+           (insert  new-sym)
2332+           (when  (member  cond-sym '(" if"   " if-not"  ))
2333+             (forward-sexp  2 )
2334+             (transpose-sexps  1 ))
2335+           (indent-region  beg end-marker)))
2336+     (user-error  " No conditional expression found"  )))
2337+ 
2338+ (defun  clojure-ts--point-outside-node-p  (node )
2339+   " Return non-nil if point is outside of the actual NODE start.
2340+ 
2341+ Clojure grammar treats metadata as part of an expression, so for example 
2342+ ^boolean (not (= 2 2)) is a single list node, including metadata.  This 
2343+ causes issues for functions that navigate by s-expressions and lists. 
2344+ This function returns non-nil if point is outside of the outermost 
2345+ parenthesis."  
2346+   (let*  ((actual-node-start (clojure-ts--node-start-skip-metadata node))
2347+          (node-end (treesit-node-end node))
2348+          (pos (point )))
2349+     (or  (<  pos actual-node-start)
2350+         (>  pos node-end))))
2351+ 
2352+ (defun  clojure-ts-cycle-not  ()
2353+   " Add or remove a not form around the current form." 
2354+   (interactive )
2355+   (if-let*  ((list-node (clojure-ts--parent-until (rx  bol " list_lit"   eol)))
2356+             ((not  (clojure-ts--point-outside-node-p list-node))))
2357+       (let  ((beg (treesit-node-start list-node))
2358+             (end-marker (copy-marker  (treesit-node-end list-node)))
2359+             (pos (copy-marker  (point ) t )))
2360+         (goto-char  (clojure-ts--node-start-skip-metadata list-node))
2361+         (if-let*  ((list-parent (treesit-node-parent list-node))
2362+                   ((clojure-ts--list-node-sym-match-p list-parent (rx  bol " not"   eol))))
2363+             (clojure-ts--raise-sexp)
2364+           (insert-pair  1  ?\(  ?\) )
2365+           (insert  " not "  ))
2366+         (indent-region  beg end-marker)
2367+         ; ; `save-excursion'  doesn't work well when point is at the opening
2368+         ; ; paren.
2369+         (goto-char  pos))
2370+     (user-error  " Must be invoked inside a list"  )))
2371+ 
22872372(defvar  clojure-ts-refactor-map 
22882373  (let  ((map  (make-sparse-keymap )))
22892374    (keymap-set map " C-t"   #'clojure-ts-thread  )
@@ -2306,6 +2391,10 @@ before DELIM-OPEN."
23062391    (keymap-set map " ["   #'clojure-ts-convert-collection-to-vector  )
23072392    (keymap-set map " C-#"   #'clojure-ts-convert-collection-to-set  )
23082393    (keymap-set map " #"   #'clojure-ts-convert-collection-to-set  )
2394+     (keymap-set map " C-c"   #'clojure-ts-cycle-conditional  )
2395+     (keymap-set map " c"   #'clojure-ts-cycle-conditional  )
2396+     (keymap-set map " C-o"   #'clojure-ts-cycle-not  )
2397+     (keymap-set map " o"   #'clojure-ts-cycle-not  )
23092398    (keymap-set map " C-a"   #'clojure-ts-add-arity  )
23102399    (keymap-set map " a"   #'clojure-ts-add-arity  )
23112400    map)
@@ -2322,6 +2411,8 @@ before DELIM-OPEN."
23222411        [" Toggle between string & keyword"   clojure-ts-cycle-keyword-string]
23232412        [" Align expression"   clojure-ts-align]
23242413        [" Cycle privacy"   clojure-ts-cycle-privacy]
2414+         [" Cycle conditional"   clojure-ts-cycle-conditional]
2415+         [" Cycle not"   clojure-ts-cycle-not]
23252416        [" Add function/macro arity"   clojure-ts-add-arity]
23262417        (" Convert collection" 
23272418         [" Convert to list"   clojure-ts-convert-collection-to-list]
0 commit comments