4

Setting the mark and moving point activates the region, which appears highlighted (assuming transient-mark-mode is enabled). Once the mark is set it's location is sent to the mark ring, thus changing it.

Is it possible to activate the region without altering the mark ring? I.e. making a selection as in other programs, such as your browser, to leave the region active and call other commands on it (kill, etc.).

The idea is to create a function to be implemented in new commands (something such as my-set-mark), not to change the default Emacs behavior for existing commands/functions.

undostres
  • 1,793
  • 12
  • 15

2 Answers2

5

It's possible, and in fact it's dead simple, as long as you're okay with where mark already is. There's no pre-existing command for it, but you could use this:

(defun my/activate-region-only ()
  "Activate the region without changing the mark ring."
  (interactive)
  (setq mark-active t))

If you want to set the mark without adding it to the mark ring, you start running into problems. The naive implementation would be something like this:

(defun my/set-mark-no-push ()
  "Set mark at point; activate region.  Do not change mark ring."
  (interactive)
  (set-mark (point)))

But this probably won't behave as you expect. It won't change the mark ring, but the current mark isn't on the mark ring. It only gets sent to the mark ring when a new mark gets set. Most commands that interact with the mark ring (e.g., C-u C-SPC) behave as if the current mark were on top of the mark ring, but this is sort of an illusion.

The upshot of all this is that my/set-mark-no-push, above, will prevent the previous mark from getting put onto the mark ring, but the new mark will still get into the mark ring when some subsequent command sets the mark again. If you want to set the mark without letting the new value go to the mark ring, there doesn't seem to be a clean or easy way to do it, and you're probably better off learning to live with Emacs's eccentricity in this respect.


EDIT: Okay, this turned out to be easier than I thought. Here's what I've got:

(defun my/dont-push-mark (&optional location nomsg activate)
  "As `push-mark', but don't push old mark to mark ring."
  (setq location (or location (point)))
  (if (or activate (not transient-mark-mode))
      (set-mark location)
    (set-marker (mark-marker) location))
  (or nomsg executing-kbd-macro (> (minibuffer-depth) 0)
      (message "Mark set"))
  nil)

(advice-add #'push-mark :override #'my/dont-push-mark)

Most of the code here dealing with NOMSG and ACTIVATE I lifted directly from push-mark. Three caveats:

  1. This will only modify the behavior of functions that use push-mark. That should be most of them, but there may be functions that, for whatever reason, use some other method to add a mark to the mark ring.

  2. Naturally, functions that are expecting to change the mark ring may behave unpredictably with this in effect.

  3. Most importantly, this change will be global. If you want to use the mark ring at all, you may want to write an interface that will add and remove the advice temporarily.

Aaron Harris
  • 2,664
  • 17
  • 22
  • Yes, I follow you. Setting the mark or pushing it to the mark ring (with `push-mark`) is straightforward. The point of the question is to leave the mark ring *untouched*. `set-mark` also alters the mark-ring. There must be some esoteric way of doing this (or many)! – undostres Jan 18 '16 at 18:29
  • I think my point is that leaving the mark ring untouched isn't enough, since `set-mark` *doesn't* change the mark ring. You'd need to somehow alter the behavior of every function that changes the mark to prevent it from adding the old mark to the mark ring. Though most of those probably go through `push-mark`, so the problem may be tractable. – Aaron Harris Jan 18 '16 at 18:56
  • @undostres After Aron's comment the closest approximation would be: `(defadvice push-mark (around dont-touch-mark-ring activate) "Don't do that!" (set-mark (or location (point))) (unless nomsg (message "Mark set")) (when activate (activate-mark)))` – Tobias Jan 18 '16 at 19:29
  • I'm sorry, forgot to add that this is intended for new commands, not to change the behavior of existing Emacs commands/functions. – undostres Jan 18 '16 at 19:37
  • @AaronHarris On another note, `set-mark` *does* change the mark ring since it deletes the previous mark position. – undostres Jan 18 '16 at 19:43
  • @undostres Look at the value of the variable `mark-ring`. The current mark isn't in that list. The thing you're thinking of as "the mark ring" is essentially `(cons (mark) mark-ring)`. – Aaron Harris Jan 18 '16 at 20:11
  • @AaronHarris OK I'm confused. I've been using `pop-to-mark-command` to move through `mark-ring` but it seems `global-mark-ring` is also included so... Anyway, `(set-marker (mark-marker) location)` doesn't *activate* the mark but I can definitely go back to `location` using `pop-to-mark-command`, and this position *is* in `mark-ring` (which is a buffer local variable). – undostres Jan 18 '16 at 23:11
  • @undostres For me, the docs for `pop-to-mark-command` specifically say that it doesn't affect the global mark ring. Do you maybe have some configuration that might be interfering? Or maybe this is a version issue (I'm on 24.5.1). – Aaron Harris Jan 19 '16 at 19:51
  • @undostres Note that `pop-to-mark-command` will always hit the current mark first. Aside from that, though, are you sure that `location` wasn't already in the mark ring before your call to `set-marker`? – Aaron Harris Jan 19 '16 at 19:56
  • @undostres Your mention of `pop-to-mark-command` gives me an idea: Maybe what you really want to do is define a command that works like `pop-to-mark-command` but skips the current mark? So, jump to the top of the mark ring, then dig down in the same way as `pop-to-mark-command`. – Aaron Harris Jan 19 '16 at 19:57
  • @AaronHarris I'm using a pretty much vanilla GNU Emacs 25.0.50.1 (from emacs25 branch); there shouldn't be compatibility issues. OK I get it! You're right, `set-mark` doesn't modify `mark-ring`, but Emacs cannot live without knowing where the last mark was set so `C-u C-SPC` moves point there anyway. That's why I thought `mark-ring` was being changed. You're pointing to the right direction with a customized `C-u C-SPC`-`C-x C-SPC`-`pop-to-mark-command`, and therefore this question is nonsense ;) Thank you for your comments! – undostres Jan 19 '16 at 20:51
  • @undostres Glad I could help. – Aaron Harris Jan 19 '16 at 21:24
-1

No. Mark and point form a region.

You can have temporary highlight just like other program. The region disappears upon actions. But still mark must exist.

The temporary highlight is controlled by two variables, transient-mark-mode and deactivate-mark. If transient-mark-mode and deactivate-mark are at the state (only . t) and nil respectively, the region between the point and mark is temporarily highlighted.

tom
  • 365
  • 1
  • 7
  • Yes, you're right. But I'm asking for a way to **not** alter the mark ring. It seems all mark-related functions change the mark ring one way or another. – undostres Jan 18 '16 at 18:30