Skip to content

Commit

Permalink
lispy.el (lispy-toggle-thread-last): Rewrite using in-buffer list man…
Browse files Browse the repository at this point in the history
…ipultation

In-buffer list manipulation is a lot more portable, since
`lispy--read' and `lispy--insert' use the Elisp reader, they're never
perfect for other LISP dialects.

* lispy.el (lispy-toggle-thread-last): Rename from `lispy-threaded-last'.
(lispy-thread-last): Rename from `lispy-to-threaded-last'.
(lispy-unthread-last): Rename from `lispy-to-last-unthreaded'.
(lispy--thread-lastify):
(lispy--unthread-lastify): Remove

* lispy-test.el (lispy-toggle-threaded-last): Add more tests.

Fixes #497
  • Loading branch information
abo-abo committed Jul 28, 2019
1 parent 8fb62be commit 6c830da
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 71 deletions.
28 changes: 14 additions & 14 deletions README.md
Expand Up @@ -373,20 +373,20 @@ key | command

A lot of Lispy commands come in pairs - one reverses the other:

key | command | key | command
----------------|--------------------------|----------------------------------|----------------------
<kbd>j</kbd> | `lispy-down` | <kbd>k</kbd> | `lispy-up`
<kbd>s</kbd> | `lispy-move-down` | <kbd>w</kbd> | `lispy-move-up`
<kbd>></kbd> | `lispy-slurp` | <kbd><</kbd> | `lispy-barf`
<kbd>c</kbd> | `lispy-clone` | <kbd>C-d</kbd> or <kbd>DEL</kbd> |
<kbd>C</kbd> | `lispy-convolute` | <kbd>C</kbd> | reverses itself
<kbd>d</kbd> | `lispy-different` | <kbd>d</kbd> | reverses itself
<kbd>M-j</kbd> | `lispy-split` | <kbd>+</kbd> | `lispy-join`
<kbd>O</kbd> | `lispy-oneline` | <kbd>M</kbd> | `lispy-multiline`
<kbd>S</kbd> | `lispy-stringify` | <kbd>C-u "</kbd> | `lispy-quotes`
<kbd>;</kbd> | `lispy-comment` | <kbd>C-u ;</kbd> | `lispy-comment`
<kbd>xi</kbd> | `lispy-to-ifs` | <kbd>xc</kbd> | `lispy-to-cond`
<kbd>x></kbd> | `lispy-threaded-last` | <kbd>x></kbd> | reverses itself
key | command | key | command
----------------|-------------------------------|----------------------------------|----------------------
<kbd>j</kbd> | `lispy-down` | <kbd>k</kbd> | `lispy-up`
<kbd>s</kbd> | `lispy-move-down` | <kbd>w</kbd> | `lispy-move-up`
<kbd>></kbd> | `lispy-slurp` | <kbd><</kbd> | `lispy-barf`
<kbd>c</kbd> | `lispy-clone` | <kbd>C-d</kbd> or <kbd>DEL</kbd> |
<kbd>C</kbd> | `lispy-convolute` | <kbd>C</kbd> | reverses itself
<kbd>d</kbd> | `lispy-different` | <kbd>d</kbd> | reverses itself
<kbd>M-j</kbd> | `lispy-split` | <kbd>+</kbd> | `lispy-join`
<kbd>O</kbd> | `lispy-oneline` | <kbd>M</kbd> | `lispy-multiline`
<kbd>S</kbd> | `lispy-stringify` | <kbd>C-u "</kbd> | `lispy-quotes`
<kbd>;</kbd> | `lispy-comment` | <kbd>C-u ;</kbd> | `lispy-comment`
<kbd>xi</kbd> | `lispy-to-ifs` | <kbd>xc</kbd> | `lispy-to-cond`
<kbd>x></kbd> | `lispy-toggle-thread-last` | <kbd>x></kbd> | reverses itself

### Keys that modify whitespace

Expand Down
15 changes: 10 additions & 5 deletions lispy-test.el
Expand Up @@ -138,17 +138,22 @@ Insert KEY if there's no command."
(insert key))))

;;* Tests

(ert-deftest lispy-toggle-threaded-last ()
(should (string= (lispy-with "|(thread-last (a) (b) (c))"
(call-interactively #'lispy-threaded-last))
(call-interactively #'lispy-toggle-thread-last))
"|(c (b (a)))"))
(should (string= (lispy-with "|(thread-last (a 1) (b 2) (c 3))"
(call-interactively #'lispy-threaded-last))
(call-interactively #'lispy-toggle-thread-last))
"|(c 3 (b 2 (a 1)))"))
(should (string= (lispy-with "|(c 3 (b 2 (a 1)))"
(call-interactively #'lispy-threaded-last))
"|(thread-last (a 1) (b 2) (c 3))")))
(call-interactively #'lispy-toggle-thread-last))
"|(thread-last (a 1) (b 2) (c 3))"))
(should (string= (lispy-with "|(equal 1443070800.0\n (ts-unix\n (ts-parse-org-element\n (org-element-context))))"
(lispy-toggle-thread-last))
"|(thread-last (org-element-context)\n (ts-parse-org-element)\n (ts-unix)\n (equal 1443070800.0))"))
(should (string= (lispy-with "|(thread-last (org-element-context)\n (ts-parse-org-element)\n (ts-unix)\n (equal 1443070800.0))"
(lispy-toggle-thread-last))
"|(equal 1443070800.0\n (ts-unix\n (ts-parse-org-element\n (org-element-context))))")))

(ert-deftest lispy-forward ()
(should (string= (lispy-with "(|(a) (b) (c))" "]")
Expand Down
77 changes: 25 additions & 52 deletions lispy.el
Expand Up @@ -377,7 +377,7 @@ This applies to the commands that use `lispy-pair'."
:type 'boolean)

(defcustom lispy-thread-last-macro 'thread-last
"Threading macro to use by default in command `lispy-to-threaded-last'."
"Threading macro to use by default in command `lispy-thread-last'."
:type 'symbol)

(defun lispy-dir-string< (a b)
Expand Down Expand Up @@ -5334,43 +5334,40 @@ With ARG, use the contents of `lispy-store-region-and-buffer' instead."
(lispy-from-left
(indent-sexp)))

(defun lispy-threaded-last ()
(defun lispy-toggle-thread-last ()
"Toggle current expression between last-threaded/unthreaded forms."
(interactive)
(lispy-from-left
(if (eq (car (read (current-buffer)))
lispy-thread-last-macro)
(call-interactively #'lispy-to-last-unthreaded)
(call-interactively #'lispy-to-threaded-last))))
(lispy-unthread-last)
(lispy-thread-last))))

(defun lispy-to-threaded-last ()
(defun lispy-thread-last ()
"Transform current expression to equivalent threaded-last expression.
Macro used may be customized in `lispy-thread-last-macro', which see."
(interactive)
(lispy-from-left
(let* ((bnd (lispy--bounds-dwim))
(expr (lispy--read (lispy--string-dwim bnd)))
(new-expr (lispy--thread-lastify expr lispy-thread-last-macro)))
(delete-region (car bnd) (cdr bnd))
(lispy--fast-insert
(lispy--whitespace-trim
new-expr))))
(lispy-from-left
(indent-sexp)))

(defun lispy-to-last-unthreaded ()
(prin1 (list lispy-thread-last-macro) (current-buffer))
(lispy-slurp 1)
(lispy-flow 1)
(while (and (lispy-right-p)
(save-excursion (backward-char) (lispy-right-p)))
(lispy-barf 1)
(lispy-move-down 1)
(lispy-up 1))
(lispy-left 1)))

(defun lispy-unthread-last ()
"Transform current last-threaded expression to equivalent unthreaded expression."
(interactive)
(lispy-from-left
(let* ((bnd (lispy--bounds-dwim))
(expr (lispy--read (lispy--string-dwim bnd)))
(new-expr (lispy--unthread-lastify expr)))
(delete-region (car bnd) (cdr bnd))
(lispy--fast-insert
(lispy--whitespace-trim
new-expr))))
(lispy-from-left
(indent-sexp)))
(lispy-flow 1)
(lispy-different)
(while (lispy-forward 1)
(lispy-move-up 1)
(lispy-slurp 1))
(lispy-different)
(lispy-flow 1)
(lispy-raise 1)))

(defun lispy-unbind-variable ()
"Substitute let-bound variable."
Expand Down Expand Up @@ -5858,7 +5855,7 @@ An equivalent of `cl-destructuring-bind'."
("B" lispy-store-region-and-buffer "store list bounds")
("R" lispy-reverse "reverse")
("T" lispy-ert "ert")
(">" lispy-threaded-last "toggle last-threaded form")
(">" lispy-toggle-thread-last "toggle last-threaded form")
("" lispy-x-more-verbosity :exit nil)
("?" lispy-x-more-verbosity "help" :exit nil))

Expand Down Expand Up @@ -7721,30 +7718,6 @@ Defaults to `error'."
(lispy--replace (car lst) from to)
(lispy--replace (cdr lst) from to)))))

(cl-defun lispy--thread-lastify (sexp &optional threading-macro)
"Return SEXP transformed into a threaded-last SEXP using THREADING-MACRO..
THREADING-MACRO symbol should be, e.g. `thread-last' or `->>'."
(cl-labels ((rec (form)
(if (and (consp form)
(car (last form)))
(if (consp (car (last form)))
`(,@(rec (car (last form))) ,(butlast form))
(list form))
form)))
`(,threading-macro ,@(rec sexp))))

(defun lispy--unthread-lastify (sexp)
"Return last-threaded SEXP unthreaded."
(cl-labels ((rec (form)
(if (and (consp form)
(car form))
(if (and (consp (car form))
(cadr form))
`(,@(car (last form)) ,(rec (butlast form)))
(car form))
form)))
`(,@(rec (cdr sexp)))))

;;* Utilities: error reporting
(defun lispy-complain (msg)
"Display MSG if `lispy-verbose' is t."
Expand Down

0 comments on commit 6c830da

Please sign in to comment.