Fork me on GitHub
#cider
<
2018-01-13
>
qqq00:01:38

(Right now). Anyone interested in helping?

qqq00:01:56

With the right people, this should seem doable in a 15 mnin live coding session.

qqq00:01:58

for starters, what is the "get parent sexp" function in cider? I have seardhed cider.parent. and cider.outer. but not seeing it

dpsutton01:01:59

@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

qqq02:01:53

@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.

qqq02:01:39

(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

qqq04:01:31

=== 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))))

mikerod04:01:10

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

mikerod04:01:36

Not even recently accessed buffers. It used to put me right in the REPL prompt. Now I have to nav back to that myself

mikerod04:01:44

It’s a minor thing, but I find it odd

qqq06:01:13

@bozhidar @dpsutton :

(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 buffer

qqq06:01:32

now the remaining part is executing this string, and having the result show up in th eoriginal buffer (while having line numbers match up)

qqq06:01:43

does cider always want a REGION of a buffer instead of just a string when I'm calling eval ?

bozhidar08:01:16

@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.

bozhidar08:01:11

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.

qqq08:01:17

@bozhidar: but I doh't want to modify the underlying buffer

bozhidar08:01:18

@mikerod Please, file a ticket on GitHub and we’ll investigate.

qqq08:01:39

also, just isnerting )]} would cause unbalanced ()'s

bozhidar08:01:01

@qqq And you want. You just need to get the text as a string, modify that string, not the buffer and evaluate it.

bozhidar08:01:20

Modifying the buffer would be a bad idea. 🙂

qqq08:01:28

magic-yank already gets me the strikng I want to execute

qqq08:01:30

how do I execute it?

qqq08:01:47

I ahve a with-temp-buffer which contains the FULL sexp I want to execute

qqq08:01:03

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

bozhidar08:01:13

You don’t need to put this text in a buffer - you need in a variable you can just pass to cider-interactive-eval.

qqq08:01:04

ah, ikt's almost working

qqq08:01:10

there's some other problems, but it's with my code, not with calling cider

qqq08:01:29

for anyone else following along:

qqq08:01:45

(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 deleting

qqq09:01:18

I'm getting the w3eirest bug. If I exec the above from init.el-buffer, lispyv8ille-delete gets matching ()'s

qqq09:01:33

if I execute the above in a *.cljc buffer, lispyville-delete does NOT give me matching ()'s (it just deletes the entire region)

qqq09:01:15

@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)))

bozhidar10:01:04

@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)))

bozhidar10:01:12

Obviously has to be polished to get the right closing delimiters, but I think that fundamentally it’s pretty simple and reliable.

qqq11:01:47

@bozhidar: how do you now there's only one mising ")" and that the outer form is a defun, not a let ?

bozhidar11:01:05

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.

bozhidar11:01:56

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).

qqq11:01:47

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. 🙂

bozhidar11:01:25

Fair enough. 🙂

bozhidar11:01:14

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.

qqq11:01:28

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?

bozhidar11:01:36

(as it would preserve the expression balanced)

qqq11:01:46

I'm not convinced "start of defun is enough"

qqq11:01:35

(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 ?

bozhidar11:01:59

Depends on the rate of the expert per hour. People in our network have different rates.

bozhidar11:01:06

> we need to hit the start of the let, why would begin of defun help us ?

bozhidar11:01:24

defun in Emacs means top-level expression, not necessary a defn.

bozhidar11:01:38

The terminology is a bit confusing.

qqq11:01:07

@bozhidar: does Toptal offer "fixed cost / i.e. payment per project" rather than "payment per hour" ?

qqq11:01:53

ah, you're right on 'beginning-of-defun'

bozhidar11:01:20

We have something like this, but I don’t know what exactly are the terms there https://www.toptal.com/projects

bozhidar11:01:15

I know this is a for fixed-budget projects, but I’m not familiar with the exact terms.

qqq11:01:27

here's the thing: for this particular problem, I feel the 'work' is about the size of a dgood StackOverflow answer

qqq11:01:38

and I'm also okay with the answer being public domain,

qqq11:01:02

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

qqq11:01:07

not sure if toptal is a good match for this

qqq11:01:45

cider-browse-spec-all is nice, I like it.

qqq12:01:25

besides copying/pasting the following code, is there a way to pass a regex to a function (instead of having it queried interactively)

qqq12:01:28

(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)))))

bozhidar15:01:14

> 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

bozhidar15:01:40

I’m guessing you can just post tickets to CIDER and place bounties on them at BoutySource (or some similar service).

bozhidar15:01:17

> besides copying/pasting the following code, is there a way to pass a regex to a function (instead of having it queried interactively)

bozhidar15:01:48

@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?

qqq21:01:39

@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"

bozhidar22:01:31

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.

bozhidar22:01:44

We can certainly tweak this function.

bozhidar22:01:20

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)))

bozhidar22:01:40

Not my finest work, but it gets the job done. 🙂

bozhidar22:01:08

(and has 0 external dependencies)

qqq22:01:48

@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 🙂

qqq22:01:17

== the problem I was running into with spec ... was that it was showing me all types of specs from clojure core + external libraries

qqq22:01:28

if there was a "cider-spec-browse-all-in-my-src", that would probably be fine too

qqq22:01:55

even for that, I'd need a regex match, to name all my hnamespaces qqq.* then, set the regex as qqq