This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-01-13
Channels
- # beginners (99)
- # boot (2)
- # boot-dev (4)
- # chestnut (2)
- # cider (75)
- # clara (43)
- # cljs-dev (1)
- # cljsjs (6)
- # cljsrn (4)
- # clojars (2)
- # clojure (76)
- # clojure-brasil (1)
- # clojure-france (1)
- # clojure-italy (2)
- # clojure-spec (30)
- # clojure-uk (4)
- # clojurescript (39)
- # core-async (1)
- # core-logic (2)
- # cursive (1)
- # data-science (7)
- # datomic (14)
- # docker (12)
- # emacs (6)
- # fulcro (69)
- # garden (4)
- # hoplon (7)
- # jobs-discuss (46)
- # leiningen (3)
- # lumo (3)
- # off-topic (12)
- # om (2)
- # parinfer (12)
- # perun (9)
- # re-frame (44)
- # reagent (6)
- # rum (1)
- # shadow-cljs (73)
- # specter (5)
- # unrepl (10)
- # vim (2)
Due to http://wiki.c2.com/?LazinessImpatienceHubris I have decided to hack on https://github.com/clojure-emacs/cider/issues/2161 myself.
for starters, what is the "get parent sexp" function in cider? I have seardhed cider.parent. and cider.outer. but not seeing it
@qqq i'm totally down for a CIDER hack session tomorrow but can't tonight. not sure when you'll have time to work on it again but if i'm available id love to pair with you
@dpsutton: I'd love to collaborate. I'm hacking on it at the moment, but making very slow (zero) progress. If I solve it, I'll post a solution here; if not, looking forward to tomorrow's collaboration.
(defun magic-yank ()
(interactive)
(save-excursion
(let ((start-loc (save-excursion
(lispy-left 99)
(point))))
(lispyville-yank start-loc (point)))))
this almost works, except lispyville-yank is REMOVING ('s instead of adding )'s=== more progres ===
(defun find-outer ()
(let ((last-loc (point)))
(save-excursion
(lispy-left 1)
(message "%s %s" (point) last-loc)
(while (not (= last-loc (point)))
(setq last-loc (point))
(lispy-left 1)
(message "%s %s" (point) last-loc)))
(message "%s" (buffer-substring last-loc (point)))
last-loc))
(defun magic-yank ()
(interactive)
(let ((start-loc (find-outer)))
(message "%s %s" start-loc (point))
(buffer-substring start-loc (point))))
I’m using the newest Cider 0.16.0 and one thing I noticed, when I do cider-connect
now to connect to an nREPL process I’ve started from another process, Cider seems to spontaneously put me in some seemingly arbitrary buffer I have open
Not even recently accessed buffers. It used to put me right in the REPL prompt. Now I have to nav back to that myself
(defun find-outer ()
(let ((beg-loc (point))
(end-loc (point)))
(save-excursion
(lispy-left 1)
(while (not (= beg-loc (point)))
(setq beg-loc (point))
(lispy-left 1)
(message "%s %s" (point) beg-loc ))
(message "%s %s" (point) beg-loc )
(lispy-right 1)
(setq end-loc (point))
(list beg-loc end-loc))))
(defun magic-yank ()
(interactive)
(let* ((lst (find-outer))
(beg-loc (car lst))
(mid-loc (point))
(end-loc (cadr lst))
(ss (buffer-substring beg-loc end-loc)))
(with-temp-buffer
(insert ss)
(message "%s" ss)
(let ((s (- mid-loc beg-loc))
(e (point-max)))
(message "delete: %s %s" s e)
(lispyville-delete s e ))
(message "%s" (buffer-substring (point-min) (point-max))))))
so I basically have the string constructed in a temp buffernow the remaining part is executing this string, and having the result show up in th eoriginal buffer (while having line numbers match up)
does cider always want a REGION of a buffer instead of just a string when I'm calling eval ?
@qqq cider-defun-at-point
returns the source of the surrounding top-level
expression. One simple approach would be to just get it, find the cursor position there, append the matching closing delimiter of the first one and do a cider-interactive-eval
on the result.
You can also use something like beginning-of-defun
to find the start of the top-level form and get the text between it and the (point)
. There are multiple ways to approach this.
@qqq And you want. You just need to get the text as a string, modify that string, not the buffer and evaluate it.
but I can't call cider-edval-buffedr or cider-eval-last-sexp on it, as it gibvesme various errors unhappy that it's a no name temp buffer
You don’t need to put this text in a buffer - you need in a variable you can just pass to cider-interactive-eval
.
(defun find-outer ()
(let ((beg-loc (point))
(end-loc (point)))
(save-excursion
(lispy-left 1)
(while (not (= beg-loc (point)))
(setq beg-loc (point))
(lispy-left 1)
(message "looking for start: %s %s" (point) beg-loc ))
(lispy-right 1)
(setq end-loc (point))
(list beg-loc end-loc))))
(defun magic-yank ()
(interactive)
(let* ((lst (find-outer))
(beg-loc (car lst))
(mid-loc (point))
(end-loc (cadr lst))
(ss (buffer-substring beg-loc end-loc)))
(with-temp-buffer
(insert ss)
(message "full expr: %s" ss)
(let ((s (- mid-loc beg-loc))
(e (point-max)))
(lispy-mode 1)
(lispyville-mode 1)
(lispyville-delete s e ))
(setq ss (buffer-substring (point-min) (point-max))))
(message "sub exp: %s" ss)
(cider-interactive-eval ss)))
almost works, except lispyville-delete, sudd3enly, is no longer keeping matching ()'s while deletingI'm getting the w3eirest bug. If I exec the above from init.el-buffer, lispyv8ille-delete gets matching ()'s
if I execute the above in a *.cljc buffer, lispyville-delete does NOT give me matching ()'s (it just deletes the entire region)
@dpsutton @bozhidar: I have no idea why this works, but this works for me (TM):
(defun find-outer ()
(let ((beg-loc (point))
(end-loc (point)))
(save-excursion
(lispy-left 1)
(while (not (= beg-loc (point)))
(setq beg-loc (point))
(lispy-left 1)
(message "looking for start: %s %s" (point) beg-loc ))
(lispy-right 1)
(setq end-loc (point))
(list beg-loc end-loc))))
(defun magic-yank ()
(interactive)
(let* ((lst (find-outer))
(beg-loc (car lst))
(mid-loc (point))
(end-loc (cadr lst))
(ss (buffer-substring beg-loc end-loc)))
(with-temp-buffer
(clojurec-mode)
(lispy-mode)
(lispyville-mode)
(insert ss)
(message "full expr: %s" ss)
(lispyville-delete (- mid-loc beg-loc) (point-max))
(setq ss (buffer-substring (point-min) (point-max))))
(message "sub exp: %s" ss)
(cider-interactive-eval ss)))
@qqq I originally meant something like this:
(defun cider-eval-to-point ()
(interactive)
(let* ((code (buffer-substring-no-properties (beginning-of-defun) (point)))
(code (concat code ")")))
(cider-interactive-eval code)))
Obviously has to be polished to get the right closing delimiters, but I think that fundamentally it’s pretty simple and reliable.
@bozhidar: how do you now there's only one mising ")" and that the outer form is a defun, not a let ?
That can be considered just pseudo code - the right closing delimiters have to be computed additionally. Just wanted to give you an idea how surrounding source can be extracted easily.
Keep in mind that in CIDER we can’t use something like lispy
or paredit
, as they are not package deps there (and there’s little reason they should be).
Right, I guess we have slightly different objectives. You need the 'right way to do it in cider', I need something that works now so I can go back to hacking Clojure. 🙂
But even for your case it’d be much simpler to just copy the defun to a temp buffer and kill the region from the point to the end of the buffer with paredit-mode
enabled.
PS: if Toptal had implemented "clojure expert on demand", how much do you think it would have cost to have someone else do the work?
(let [x 20]
(defn foo [y] (+ x y))
(ct/is (= (foo 3) 23)) ;; cursor here
;; blah blah blah
)
we need to hit the start of the let, why would begin of defun help us ?Depends on the rate of the expert per hour. People in our network have different rates.
@bozhidar: does Toptal offer "fixed cost / i.e. payment per project" rather than "payment per hour" ?
We have something like this, but I don’t know what exactly are the terms there https://www.toptal.com/projects
I know this is a for fixed-budget projects, but I’m not familiar with the exact terms.
here's the thing: for this particular problem, I feel the 'work' is about the size of a dgood StackOverflow answer
so I'd love to have a system where I can pay $50/$100 and have these questions / "mini projects" done by people who know elisp/clojure/whatever-else-domain better than I do
besides copying/pasting the following code, is there a way to pass a regex to a function (instead of having it queried interactively)
(defun cider-browse-spec-all (&optional arg)
"Open list of specs in a popup buffer.
With a prefix argument ARG, prompts for a regexp to filter specs.
No filter applied if the regexp is the empty string."
(interactive "P")
(cider-ensure-connected)
(cider-ensure-op-supported "spec-list")
(let ((filter-regex (if arg (read-string "Filter regex: ") "")))
(with-current-buffer (cider-popup-buffer cider-browse-spec-buffer t)
(let ((specs (cider-sync-request:spec-list filter-regex)))
(cider-browse-spec--draw-list-buffer (current-buffer)
(if (string-empty-p filter-regex)
"All specs in registry"
(format "All specs matching regex `%s' in registry" filter-regex))
specs)))))
> so I’d love to have a system where I can pay $50/$100 and have these questions / “mini projects” done by people who know elisp/clojure/whatever-else-domain better than I do
I’m guessing you can just post tickets to CIDER and place bounties on them at BoutySource (or some similar service).
> besides copying/pasting the following code, is there a way to pass a regex to a function (instead of having it queried interactively)
@qqq Not right now, but we can always extract the body if there’s a good reason to do so. What’s your use case for this?
@bozhidar: I havea hot key bound to this:
;; ("h" (my-cider-browse-ns (cider-current-ns)))
(defun my-cider-browse-spec-all (filter-regex)
(interactive "P")
(cider-ensure-connected)
(cider-ensure-op-supported "spec-list")
(with-current-buffer (cider-popup-buffer cider-browse-spec-buffer t)
(let ((specs (cider-sync-request:spec-list filter-regex)))
(cider-browse-spec--draw-list-buffer (current-buffer)
(if (string-empty-p filter-regex)
"All specs in registry"
(format "All specs matching regex `%s' in registry" filter-regex))
specs))))
which does "browse all specs in current namespace"I see. I never thought of specs as something belonging to a namespace, because of the central registry for them, but I guess that makes some sense.
Btw, I got cider-eval-defun-to-point
to work pretty well with the following code, that needs some polish before I can commit it:
(defun cider--calculate-opening-delimiters ()
"Walks up the list of expressions to collect all sexp opening delimiters.
The result is a list of the delimiters."
(interactive)
(let ((result nil))
(save-excursion
(condition-case nil
(while t
(backward-up-list)
(push (char-after) result))
(error result)))))
(defun cider--matching-delimiter (delimiter)
"Get the matching delimiter for DELIMITER."
(pcase delimiter
(?\( ?\))
(?\[ ?\])
(?\{ ?\})))
(defun cider--calculate-closing-delimiters ()
"Calculate the list of closing delimiters to make the defun before point valid."
(mapcar #'cider--matching-delimiter (cider--calculate-opening-delimiters)))
(defun cider-eval-defun-to-point ()
"Evaluate the current toplevel form up to point."
(interactive)
(let* ((beg-of-defun (save-excursion (beginning-of-defun) (point)))
(code (buffer-substring-no-properties beg-of-defun (point)))
(code (concat code (cider--calculate-closing-delimiters))))
(cider-interactive-eval code)))
@bozhidar: TIL, the way to get @bozhidar to implement new cider functionality is to 1. implement it yourself 2. in a hacky way 3. using lots of external dependencies then, @bozhidar will implement it cleanly 🙂