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.

Drew
  • 75,699
  • 9
  • 109
  • 225
sandric
  • 1,221
  • 9
  • 19

1 Answers1

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.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • Thanks a lot. Worked like a charm. There's always smth to learn in emacs). – sandric Nov 08 '17 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 09 '17 at 04:38