I want to bind this function to M-w, so that it copies the region if one is selected, otherwise it copies the whole line silently, without having any other side-effects like moving the cursor to some other places.

I saw some examples, but they all do some additional stuff that I don't like, like moving the cursor to the next line.

I'm not an expert in Elisp, but some functions I saw might be buggy, because their bodies contain "\n", to refer to "newline", which is obviously wrong, because not all systems use this convention.

  • 1
    Emacs represents newlines as "\n" internally, no matter how the newline is encoded when it's stored in a file. – Gilles 'SO- stop being evil' Jun 27 '20 at 13:49

To avoid side effects like moving the point (that is, the cursor), wrap your movement commands in save-excursion. Prior Emacs 25 this also saved the mark (the other end of the selected region). Now to save the mark as well use save-mark-and-excursion.

First we need a function to select the whole line:

(defun mark-whole-line ()
  (set-mark-command nil)

This function moves the point and the mark.

Now we need to know if the region is active. The function region-active-p does this. Now just check the state of the region and use an if/then to either call the normal function M-w is bound to or save the state, use the above function to mark the whole line and then copy it:

(defun kill-ring-save-whole-line-or-region ()
  (if (region-active-p)
      (call-interactively #'kill-ring-save) ;; then
    (save-mark-and-excursion ;; else
      (kill-ring-save (region-beginning) (region-end))

Finally to bind it to a key: (define-key global-map (kbd "M-w") #'kill-ring-save-whole-line-or-region)

  • I get the following error: Debugger entered--Lisp error: (error "Key sequence M - w starts with non-prefix key M") But when I use the following line it works properly: (global-set-key (kbd "M-w") 'kill-ring-save-whole-line-or-region) – Bite Bytes Jun 27 '20 at 14:38
  • 1
    @BiteBytes That's the part I typed without testing it. Fixed now. – erikstokes Jun 27 '20 at 14:42
  • FWIW, I have a similar command in misc-cmds.el. Putting it here just for info: (defun mark-line (&optional arg) "Put mark at end of line, point at beginning. A numeric prefix arg means move forward (backward if negative) that many lines, thus marking a line other than the one point was originally in." (interactive "P") (setq arg (if arg (prefix-numeric-value arg) 0)) (let ((inhibit-field-motion t)) (forward-line arg) (push-mark nil t t) (goto-char (line-end-position)))) – Drew Jun 27 '20 at 15:55

You want the whole-line-or-region package. With whole-line-or-region-local-mode activated, things like C-w and M-w Do The Right Thing on the current line when then is no active region.

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.