# How to move the cursor to the beginning/end of a shift-selected region by a left/right motion?

In most modern editors, after canceling a selection by a left/right motion, the cursor will be moved to the beginning/end of the previously-selected region correspondingly. Similarly, if we cancel a selection by a up/down motion, the cursor will be moved up/down one line from the beginning/end of the previously-selected region correspondingly.

Could we have the same behaviors in Emacs under shift-select-mode?

I tried to define my own movement function:

(bind-key* "M-l"
(lambda (arg)
(interactive "^p")
(if (use-region-p)
(goto-char (region-end))
(syntax-subword-forward arg))))


But it doesn't work. The goto-char never run even if I am selecting a region. Is it because I used (interactive "^p")? Any solution?

• I very much prefer Emacs's behavior: I especially don't like it when a selection extends past the edge of the screen and a motion command brings me to the invislble end. But of course each to their own preference. In case anybody wants this and is not aware: you can switch to the other end of the selection with C-x C-x. Thus, in shift selection mode, an unshifted motion command exits the selection at the end that you've been focusing on (moving the cursor), and you press C-x C-x first to exit the selection at the other end. – Gilles 'SO- stop being evil' Oct 7 '17 at 9:42

You can probably do something like

(defvar my-old-region-bounds nil)

(lambda (orig-fun)
(let ((was-active (region-active-p)))
(funcall orig-fun)
(when (and was-active (not (region-active-p)))
(setq-local my-old-region-bounds
(cons (point-marker) (mark-marker)))

(defun my-move-to-old-region-bound ()
(remove-hook 'post-command-hook #'my-move-to-old-region-bound)
(let ((bounds my-old-region-bounds))
(kill-local-variable 'my-old-region-bounds)
(when bounds
(when (funcall (cond
((> (point) (car bounds)) #'<)
((= (point) (car bounds)) #'=)
(t #'>))
(point) (cdr bounds))
;; We moved towards the other (old)boundary.
(goto-char (cdr bounds))))))


Of course, this is guaranteed 100% untested.

Edited by AhLeung: I tested it, and it works for most motion functions.

I found a solution, feel free to comment / improve.

(advice-add 'handle-shift-selection :before
(lambda ()
(setq-local was-active (region-active-p))))
(bind-key* "M-l" (lambda (arg)
(interactive "^p")
(if (and was-active (not (region-active-p)))
(goto-char (region-end))
(syntax-subword-forward arg)
)))
(bind-key* "M-h" (lambda (arg)
(interactive "^p")
(if (and was-active (not (region-active-p)))
(goto-char (region-beginning))
(syntax-subword-backward arg)
)))