emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Shift selection using interactive spec


From: Lennart Borgman (gmail)
Subject: Re: Shift selection using interactive spec
Date: Mon, 17 Mar 2008 00:04:58 +0100
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071031 Thunderbird/2.0.0.9 Mnenhy/0.7.5.666

Thomas Lord wrote:
Stefan Monnier wrote:
I do not follow you, Tom: how would the right arrow magically forget
your tentative mark?


There are three, per-buffer variables:

    tentative-mark:
        the "other side" (besides the point) of the current,
        shift-selected region, as far as primitive operations
        on buffers are concerned.    The tenative-mark, if not
        nil, combines with the point to create a "fat cursor" --
        e.g., primitive insertion operations delete the contents
        of the fat cursor before inserting.

    maybe-preserved-tentative-mark:
        The value of tentative-mark as last observed by the
        user.  That is, before every interactive command
        invocation, the value of tentative-mark is unconditionally
        copied to become the value of maybe-preserved-....

    preserved-tentative-mark:
         The value that, in the opinion of the currently running
         command, should become the value of transient-mark
         after the command completes.   By default, this is nil.
         Command loops, when interactively invoked commands
         return, unconditionally copy the value of perserved-tentative-mark
         to tentative-mark.

So, suppose I type S-right-arrow, invoking shift-select mode.
That invokes a generic function -- let's dub it treat-as-shifted-sequence.
That function creates a marker at the point and sets preserved-tentative-mark to that new marker. Then it looks up what the unshifted sequence right-arrow
is bound to and runs that command.   That command (forward-char) is
ignorant of the three variables so it doesn't change them at all.   When
control returns to the command loop, the value of preserved-tentative-mark
is copied to tentative-mark -- so now there is a tentative-mark (start of a
shift-mark region) set.

Typing S-right-arrow again has almost the same effect.   Instead of
creating a new marker, the generic function treat-as-shifted-sequence
notices that, this time, maybe-preserved-tentative-mark is non-nil.
Rather than create a new mark, it just copies that value to preserved-....
So, the tentative mark (start of shift region) is preserved.

But then you type just right-arrow, with no shift.   When invoked,
tentative-mark and maybe-preserved-.... are still both set to that
original mark, but preserved-tentative-mark has its default value of
nil.   The right arrow binding (forward char) is still ignorant of those
three variables.   It changes nothing.   When control returns to the
command loop, preserved-... (which is bound to nil) is copied to
tentative-mark

I translate it to something like this in elisp code:

;;;; pre-pre
;;   treat-as-shifted:
(setq maybe-preserved-tm tm)
(if shifted
    (setq preserved-tm
          (if tm tm (make-marker)))
  (setq preserved-tm nil))

;;;; run unshifted command + hooks
;; Neither maybe-preserved-tm or preserved-tm
;; are touched here (maybe not even known)

;;;; post-post
;;
(if buffer-was-changed
    (setq preserved-tm nil)
  (unless preserved-tm
    (when user-wants-it
      (setq preserved-tm maybe-preserved-tm))))
(setq tm preserved-tm)


 In what way is that different from setting
mark-active to nil?

There are two aspects to the answer:  cleanliness and
semantics.

Cleanliness: the three variable proposal needs a *tiny bit*
of new code in the C part of Emacs.   In exchange, it
doesn't need transitive-mark or delete-mark... elisp code
at all (because the default behaviors are better).

Cleanliness again:  In the three variable system, most
commands DTRT by default, even if they remain ignorant
of the three variables.

Semantics:  the three variable model is sensitive to
"cycle phases" in user interaction.   maybe-perserved-...
is a reliable source of the value of the tentative mark as
of the time the user last saw it.    preserved-.... is
how function control what the value of the tentative
mark will be when the user next sees it.   tentative-mark
itself is the value honored by primitives.    Making
those distinctions has a side effect: the default behaviors
comes out correctly, for free, and the non-default
behaviors are trivial to implement in generic ways.
In contrast, just having a binary distinction between
an active and inactive mark means having to make those
other distinctions harder to implement -- lots of functions
have to be modified because that's the only way left
to make those distinctions.   It's *why* you're ending up
thinking about distinguishing "motion commands" and
the like. Maybe the simple form is just: "I dunno. The three-variable implementation is just cleaner.
It happens to hit a sweet spot that way.   It just *is*."





reply via email to

[Prev in Thread] Current Thread [Next in Thread]