4

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"
  (interactive)
 (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 “-”."
 (interactive)
 (let (pt)
   (skip-chars-backward "-_A-Za-z0-9")
   (setq pt (point))
   (skip-chars-forward "-_A-Za-z0-9")
   (set-mark pt)
 ))
Drew
  • 77,472
  • 10
  • 114
  • 243
Name
  • 7,849
  • 4
  • 41
  • 87

1 Answers1

5

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 ()
  (interactive)
  (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
             (save-restriction
               (forward-page)
               (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)
xuchunyang
  • 14,527
  • 1
  • 19
  • 39
  • 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