0

I liked the interactivity of Clojure/Lisp, where you can see the result in the REPL. I tried to implement the same behaviour for SQL-mode. The idea is that when I do C-x C-e on the SQL-statemnt, I see the result in the *SQL*-mode, which will function as an alternative REPL.

To get this behaviour, I wrote two functions (I use Evil, so I have a normal, visual and insert state).

(defun sql-region-evaluate (start end)
"This will send the selected region to the SQL process"
(interactive "r")
(if (evil-visual-state-p)
    (sql-send-string (buffer-substring-no-properties start end))))

When I select a region, then I will use this function.

I do not want to use the sql-send-buffer command, because sometimes I type the next statement after the previous statement. When calling sql-send-buffer both SQL-statements will be queried, instead the last one.

So that's why I use the sql-send-region. The key command vap is an Evil keysequence in normal state which will visually selects the block.

(defun sql-evaluate (s)
"It will visually select the text block, and send it to the SQL process"
(interactive)
    ;; If I'm in the normal mode
    (if (evil-normal-state-p)
        (lambda ()
            (execute-kbd-macro (kbd "vap"))
            (sql-send-region start end)
            )))

When I call sql-region-evaluate, it works fine. When I call sql-evaluate, nothing happens, I don't get any error message or something. So I cannot trace it back where it went wrong.

Any suggestions where it could get wrong?

1

Your code is not doing what you think it is doing. The latter example wraps two forms in a lambda, so all that happens is that sql-evaluate is going to return an anonymous function (or nil if you're not in visual state).

Please don't do that. Use either progn for wrapping forms to be evaluated sequentially (with the last form as return value) or use special forms using an implicit progn, such as when (which is like if, but doesn't have an else clause, so it does allow you to specify as many then clauses as you need).


And now, a rewritten variant of the above (untested):

(defun my-eval-sql ()
  (interactive)
  (cond
   ((evil-visual-state-p)
    (sql-send-region (region-beginning) (region-end)))
   ((evil-normal-state-p)
    (sql-send-region (beginning-of-thing 'paragraph) (end-of-thing 'paragraph)))
   (t (user-error "Not in visual or normal state"))))
  • thanks for your reply. Why is using lambda considered as not a good practice? And you recommend me to use when, but in your example I see you're using cond (which is a good example, actually!), without further use of progn. Your code works well by the way, but I would like to understand the decisions to structure such a Elisp form. – ReneFroger Feb 1 '16 at 21:16
  • when/unless are good if you need one clause, if for two clauses and cond for everything else. As both of your commands were highly redundant, I decided to combine both cases and the error case, so that made three branches and therefore a cond. – wasamasa Feb 1 '16 at 21:28
  • Regarding lambda, you're using it for the wrong purpose. It's not about it being bad practice (even if I do consider using a named function most of the time), it's about not being the right tool for sequencing statements. If you were using a higher-order function, sure, use a lambda, but not for this please. – wasamasa Feb 1 '16 at 21:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.