I want a command that copies a form to the kill ring. In emacs-live, the closest thing I could find was this command / key-binding

(global-set-key (kbd "M-]") 'kill-ring-save)

However kill-ring-save has some wonky behaviour. Ii copies more than 1 form, past the cursor. Ultimately, I want a simple function along the lines of what's below (this doesn't quite work).

(defun copy-form () 
  (kill-ring-save (line-beginning-position) (live-paredit-forward))) 

(global-set-key (kbd "M-]") 'copy-form)

I've searched high and low ( SO question and Google search), but can't seem to find a simple, working command to copy a balanced expression. Has someone already done this?

Thanks

Tim

有帮助吗?

解决方案

Function sexp-at-point gives you the sexp ("form") at the cursor. Just copy that to the kill-ring, using kill-ring-save. E.g.:

(defun copy-sexp-at-point ()
  (interactive)
  (let ((bnds  (bounds-of-thing-at-point 'sexp)))
    (kill-ring-save (car bnds) (cdr bnds))))

Alternatively, just use kill-new:

(defun copy-sexp-at-point ()
  (interactive)
  (kill-new (thing-at-point 'sexp)))

其他提示

The reason your copy-form cannot be bound to a key is that it is a function, not a command - it is missing an interactive form.

However, in your case you don't even need to write a new function.

Try a combination of

mark-sexp is an interactive compiled Lisp function in `lisp.el'.

It is bound to C-M-@, C-M-SPC.

and

M-w runs the command kill-ring-save, which is an interactive compiled Lisp function in `simple.el'.

It is bound to <C-insertchar>, M-w, <menu-bar> <edit> <copy>.

I'm not sure I understand the question, but when I need to do what I consider as "copy a balanced form", I do: M-C-SPC M-w. If I want to cut it instead, I do M-C-SPC C-w.

Here's what I generally use. Somehow it's more useful for me to kill the balanced expression instead of copying. If I want a copy instead, I first kill, then undo.

This function kills a string, if the point is inside string, otherwise the balanced expression, i.e. (),[],{},<> or whatever is defined by the syntax.

(defun kill-at-point ()
  "Kill the quoted string or the list that includes the point"
  (interactive)
  (let ((p (nth 8 (syntax-ppss))))
    (cond
      ;; string
      ((eq (char-after p) ?\")
       (goto-char p)
       (kill-sexp))
      ;; list
      ((ignore-errors (when (eq (char-after) ?\()
                        (forward-char))
                      (up-list)
                      t)
       (let ((beg (point)))
         (backward-list)
         (kill-region beg (point)))))))

I've also tried to add a special case for when the point is inside the comment, but I couldn't find a generic way to determine bounds of comment at point. If anyone knows, please tell me.

This other function can be relevant as well. It marks instead of killing, like the previous one. The nice thing that it extends the region each time it's called. I bind the first one to C-, and the second to C-M-,.

(defun mark-at-point ()
  "Mark the quoted string or the list that includes the point"
  (interactive)
  (let ((p (nth 8 (syntax-ppss))))
    (if (eq (char-after p) ?\")
    (progn
      (goto-char p)
          (set-mark (point))
      (forward-sexp))
      (progn
        (when (eq (char-after) 40)
          (forward-char))
        (condition-case nil
            (progn
              (up-list)
              (set-mark (point))
              (let ((beg (point)))
                (backward-list)
                (exchange-point-and-mark)))
          (error
           (when (looking-back "}")
             (exchange-point-and-mark)
             ;; assumes functions are separated by one empty line
             (re-search-backward "^[^A-Z-a-z]" nil t)
             (forward-char))))))))
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top