1

By using shift-select-mode, I can select some region via holding down Shift + arrow keys. When I then stop pushing Shift and press other keys the region get deselected. But this is not the case when using push-mark function from Elisp code - the region stays selected when I move the cursor.

Here's an example of my function to select current symbol under cursor:

(defun sandric/select-symbol-under-cursor ()
  "Select symbol under cursor."
  (interactive)
  (when (not (region-active-p))
    (let (bounds pos1 pos2 mything)
      (setq bounds (bounds-of-thing-at-point 'symbol))
      (setq beginning (car bounds))
      (setq ending (cdr bounds))
      (goto-char beginning)
      (push-mark beginning t t)
      (goto-char ending))))

It works as expected (leaving aside little redundance with setq and not using let bounds for now), and if I place cursor on a symbol and call the function it selects the symbol at point as the region.

The problem occurs when I press the right arrow key afterwards. The region is not deselected - instead it expands.

How can I make cursor movements after using my command not expand/decrease the region unless the Shift key is pressed, like the usual shift-select-mode behavior.

1 Answer 1

1

You need to set variable transient-mark-mode to a special value: a cons with only as its car:

(defun sandric/select-symbol-under-cursor ()
  "Select symbol under cursor."
  (interactive)
  (unless (region-active-p)
    (let* ((bounds     (bounds-of-thing-at-point 'symbol))
           (beginning  (car bounds))
           (ending     (cdr bounds)))
      (goto-char beginning)
      (push-mark beginning t t)
      (goto-char ending)
      (setq transient-mark-mode  (cons 'only transient-mark-mode)))))

C-h v transient-mark-mode tells you:

transient-mark-mode is a variable defined in C source code.

Its value is t

Permanently local in buffer simple.el; global value is the same.

Automatically becomes permanently buffer-local when set.

Documentation:

Non-nil if Transient Mark mode is enabled.

See the command transient-mark-mode for a description of this minor mode.

Non-nil also enables highlighting of the region whenever the mark is active. The region is highlighted with the region face. The variable highlight-nonselected-windows controls whether to highlight all windows or just the selected window.

Lisp programs may give this variable certain special values:

  • A value of lambda enables Transient Mark mode temporarily. It is disabled again after any subsequent action that would normally deactivate the mark (e.g. buffer modification).

  • A value of (only . OLDVAL) enables Transient Mark mode temporarily. After any subsequent point motion command that is not shift-translated, or any other action that would normally deactivate the mark (e.g. buffer modification), the value of transient-mark-mode is set to OLDVAL.

You can customize this variable.

2
  • Thanks a lot. Worked like a charm. There's always smth to learn in emacs).
    – sandric
    Nov 8, 2017 at 23:54
  • @Stefan proposed an edit to change (setq t-m-m (cons 'only t-m-m)) to (push 'only t-m-m). I prefer the form I show, as it indicates more clearly that the new value is, as the doc-string, says, (only . OLD-TRANSIENT-MARK-MODE-VALUE). Yes, the two are equivalent, and yes, the push sexp is more concise. But in the context of this Q&A, especially, I think the explicit setq sexp is a bit clearer.
    – Drew
    Nov 9, 2017 at 4:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.