I would like to write a function which

  1. on the first execution behaves like the regular kill-ring-save if some region is selected
  2. on the first execution copies the current word if no region is selected,
  3. on the second execution copies the current line
  4. on the third execution copies the current paragraph
  5. on the fourth execution and so on copies the whole current buffer

Eventually I would like to remap kill-ring-save to this new function. So far I have written this

    (defun modified-kill-ring-save () (interactive)
    (if (region-active-p) (kill-ring-save (region-beginning) (region-end)) 
(if (not  (equal last-command 'modified-kill-ring-save))
 (progn (select-current-word) (kill-ring-save (region-beginning) (region-end)) ) 
 (progn (select-current-line) (kill-ring-save (region-beginning) (region-end))  )   )  )   

which does 1, 2 and 3. But I am not able to go further.

In the above code I have used the following functions from http://ergoemacs.org/emacs/elisp_examples.html

(defun select-current-line ()
  "Select the current line"
 (beginning-of-line) ; move to end of line
  (set-mark (line-end-position)))

(defun select-current-word ()
"Select the word under cursor.
“word” here is considered any alphanumeric sequence with “_” or “-”."
 (let (pt)
   (skip-chars-backward "-_A-Za-z0-9")
   (setq pt (point))
   (skip-chars-forward "-_A-Za-z0-9")
   (set-mark pt)
  • Do you know about expand-region? You could use it to select what you want and then you could do any operation on selected text. Jul 25 '15 at 11:08

expand-region or easy-kill or hydra might provide better idea on how to do one thing continuously, but here is a silly command which tries to do exactly what you want.

(defvar my-kill-ring-save--counter)

(defun my-kill-ring-save ()
  (if (eq last-command this-command)
      (cl-incf my-kill-ring-save--counter)
    (setq my-kill-ring-save--counter 1))
  (cond ((eq my-kill-ring-save--counter 1)
         (if (use-region-p)
             (kill-ring-save (region-beginning) (region-end))
           (kill-new (current-word))))
        ((eq my-kill-ring-save--counter 2)
         (kill-ring-save (line-beginning-position) (line-end-position)))
        ((eq my-kill-ring-save--counter 3)
         (let (page-beginning-pos page-end-pos)
           (save-excursion              ; I am not really sure about them nowadays
               (setq page-end-pos (point))
               (forward-page -1)
               (setq page-beginning-pos (point))))
           (kill-ring-save page-beginning-pos page-end-pos)))
        ((eq my-kill-ring-save--counter 4)
         (kill-new (buffer-string)))))

;; For testing
(global-set-key (kbd "<f6>") #'my-kill-ring-save)
  • Thanks, I confirm that your code perfectly works. I think it can also be modified for copying the paragraphs.
    – Name
    Jul 25 '15 at 13:36
  • I guess only point needs to be saved and restored, so single save-excursion should be enough (even for Emacs 25.1), i.e., remove save-restriction.
    – xuchunyang
    Jul 25 '15 at 13:58

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.