Because shift translation and temporary activation of the mark is handled by the command loop, you will need to call the interactive versions of the movement functions in order to get the appropriate shift selection behavior from them:
;; (source: http://emacs.stackexchange.com/a/22166/93)
(defun my-mark-current-line ()
(interactive)
(beginning-of-line)
(setq this-command-keys-shift-translated t)
(call-interactively 'end-of-line)
(call-interactively 'forward-char))
(global-set-key (kbd "M-l") 'my-mark-current-line)
Update:
Since writing the above answer, I took the time to learn a little more about how shift selection really works under the hood. It sets the symbol value of transient-mark-mode
to be a cons cell of the form (only . OLDVAL)
, where OLDVAL
is the value prior to shift selection.
The solution below avoids the use of call-interactively
by activating the mark as needed, and setting the appropriate value of transient-mark-mode
. Basically, I consider this solution to be less of a hack than the first one.
As a bonus, it now has an optional repeat count, and will extend the current selection in either direction if the mark is already active.
;; (source: http://emacs.stackexchange.com/a/22166/93)
(defun my-mark-current-line (&optional arg)
"Uses shift selection to select the current line.
When there is an existing shift selection, extends the selection
in the appropriate direction to include current line."
(interactive "p")
(let ((oldval (or (cdr-safe transient-mark-mode) transient-mark-mode))
(backwards (and mark-active (> (mark) (point))))
(beg (and mark-active (mark-marker))))
(unless beg
(if backwards (end-of-line) (beginning-of-line))
(setq beg (point-marker)))
(if backwards (end-of-line (- 1 arg)) (beginning-of-line (+ 1 arg)))
(unless mark-active
(push-mark beg nil t))
(setq transient-mark-mode (cons 'only oldval))))