From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Thomas Lord Newsgroups: gmane.emacs.devel Subject: Re: Shift selection using interactive spec Date: Sat, 15 Mar 2008 13:59:25 -0700 Message-ID: <47DC38AD.5010400@emf.net> References: <87k5k69p92.fsf@stupidchicken.com> <200803140408.m2E47hPU014494@sallyv1.ics.uci.edu> <87prtxpekk.fsf@kfs-lx.rd.rdm> <87abl11ilo.fsf@stupidchicken.com> <874pb9koyw.fsf@stupidchicken.com> <87od9gzqv9.fsf@stupidchicken.com> <87bq5gytbi.fsf@stupidchicken.com> <8763vndi0r.fsf@kfs-lx.rd.rdm> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Trace: ger.gmane.org 1205612475 28916 80.91.229.12 (15 Mar 2008 20:21:15 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sat, 15 Mar 2008 20:21:15 +0000 (UTC) Cc: Chong Yidong , Dan Nicolaescu , Stefan Monnier , emacs-devel@gnu.org To: "Kim F. Storm" Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Mar 15 21:21:41 2008 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1Jacsn-0007fP-QU for ged-emacs-devel@m.gmane.org; Sat, 15 Mar 2008 21:21:34 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JacsE-0003c1-Bm for ged-emacs-devel@m.gmane.org; Sat, 15 Mar 2008 16:20:58 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Jacs9-0003bu-MV for emacs-devel@gnu.org; Sat, 15 Mar 2008 16:20:53 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Jacs8-0003bf-Td for emacs-devel@gnu.org; Sat, 15 Mar 2008 16:20:53 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Jacs8-0003bc-P6 for emacs-devel@gnu.org; Sat, 15 Mar 2008 16:20:52 -0400 Original-Received: from mail.42inc.com ([205.149.0.25]) by monty-python.gnu.org with esmtps (SSL 3.0:RSA_3DES_EDE_CBC_SHA1:24) (Exim 4.60) (envelope-from ) id 1Jacs8-0005sC-Db for emacs-devel@gnu.org; Sat, 15 Mar 2008 16:20:52 -0400 X-TFF-CGPSA-Version: 1.5 X-TFF-CGPSA-Filter-42inc: Scanned X-42-Virus-Scanned: by 42 Antivirus -- Found to be clean. Original-Received: from [69.236.65.4] (account lord@emf.net HELO [192.168.1.64]) by mail.42inc.com (CommuniGate Pro SMTP 5.0.13) with ESMTPA id 25578734; Sat, 15 Mar 2008 13:20:37 -0700 User-Agent: Thunderbird 1.5.0.5 (X11/20060808) In-Reply-To: <8763vndi0r.fsf@kfs-lx.rd.rdm> X-detected-kernel: by monty-python.gnu.org: Linux 2.6, seldom 2.4 (older, 4) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:92693 Archived-At: Kim F. Storm wrote: > Now, before you settle on a solution, maybe you should also consider > how to handle the delete-selection-mode in a sensible way without > using the current pre-command-hook + command property approach. > Tentative marks simplify that too: Suppose there is a global variable, tenative-mark, which is always either nil or a mark. The ordinary mark stack also exists. The region between tenative-mark and point is called the tentative-region. save-excursion should save and restore the value of tentative-mark, setting it to nil when running its body. Low level functions (in C) that insert text into a buffer should unconditionally delete the tentative region first, if there is one, and set tentative-mark to nil. Conceptually, this is a generalization of the notion of a "point". A point is an index naming a theoretical "space between" two adjacent characters in a buffer, or the space at the beginning or end of buffer. A "tentative region" is like having a pseudo-point which indicates a conceptual "space between" in a hypothetical buffer that results from deleting the contents of the tentative region. That is the essential functionality that delete-selection-mode is aiming for but, by adding the concept of a tentative-mark, that essential functionality is simplified enough that it can reasonably be built-in as unconditional behavior of a few insertion commands. There should be a a second and third variable: maybe-preserved-tentative-mark and preserved-tentative-mark. These are, again, either nil or a mark. These are used to control which commands preserve the tentative mark vs. which set it back to nil (the default behavior): When a command returns to a command loop, the value of preserved-tentative-mark should be copied to tentative-mark, unconditionally. Both maybe-preserved-... and preserved-... should be set to nil. So, by default, commands implicitly "clear" the tentative mark. Before a command loop invokes a command, it should first copy tenative-mark to maybe-preserved-... That way, if a command wants to preserve the tentative mark if it is already present (the default interpretation of "shifted keysequences") then it can simply copy maybe-preserved-... to preserved-tentative-mark. When the command returns, that saved mark will be copied back to tentative-mark. The function ensure-shifted-mode does this: if tentative-mark is nil, create a marker at the point set tentative-mark and maybe-preserved-... to that marker return The function (call-interactively-preserving-transient 'X) does: ensure-shifted-mode copy maybe-preserved-... to preserved-... call 'X interactively return The command treat-as-shifted-sequence does this: unshift the invoking sequence push the new sequence back to input read a complete key sequence, selecting a command X call-interactively-preserving-transient X return So, treat-as-shifted-sequence is a reasonable default binding for shifted control and meta-keys or common sequences of those, at least for users who want shift-select to happen. The function returned by (treated-as-shifted-function 'X) does this: call-interactively-preserving-transient 'X and can be used to create bindings for key-sequences that should enter "shift select mode" but that aren't handled by default bindings to treat-as-shifted-sequence I guess that the command yank would need to be modified. I think that the modified version is simply copy maybe-preserved-... to preserved-... yank as before Probably there are a small number of similar commands. Another category of commands that will initially behave oddly until modified are commands that modify the buffer mainly elsewhere from the current point. replace-string is a decent example. Those can be fixed-on-demand to be: set transient-mark, maybe-preserved-..., and preserved-... all to nil behave as before The display code can (or should unconditionally?) highlight the transient region. So, for example... S-M-C-f, presumably invokes treat-as-shfited-sequence and so selects the following word as part of the transient region. Repeating that extends the region. Right-arrow, not invoking treat-as-shifted-.... implicitly cancels the transient region. On the other hand, typing 'x' ultimately calls a low-level insert function with no save-excursion between the command loop and that call. That insertion automatically deletes the transient region before inserting the x. So, those basic things work right. Similarly, instead of typing 'x', I can invoke the modified yank. If no transient-mark was set yank behaves as it does today. If a transient-mark is set, and so maybe-... was set when the command was invoked, then yank both (implicitly) deletes the transient region *and* preserves the transient mark (so the pasted content is the new content of the transient region). What about something tricky like replace-string? Using only the above rules, with all of their unconditional properties, they'll do something kind of dumb: at their first "insert" that happens to be outside of any save-excursion they'll delete everything from the transient-mark (if present) to the point. A small core of those has to be fixed from the start. Obscure cases can be fixed on demand with a one-line fix. Either: (nilify-transient) ; sets all three variables to nil (old-code) or (ignoring-transient . old-code) ; save-excursion and nilify transient for body My *guess* is that the second choice is nicer most times but that both are handy to have. So: three new variables one new display feature (clone of an existing feature) a couple unconditional variable copies in the command loop a few new functions unconditionally delete the transient region in some C code modify some core functions like yank and replace-string fix obscure commands that work similarly to yank or replace-string on-demand lots and lots of code that doesn't have to be modified at all a very simple "state machine" model of the behavior a behavior that highly agrees with "all those other GUIs" For extra special featurefulness, you could build on that by adding a "transient region ring" -- a circular buffer that remembers the last N transient regions whenever some command nillifies the transient region at the top level. A "remembered" transient region is a pair of marks: the transient-mark and a marker at what was then the point. N should probably be small but the idea is that recent transient regions are cached so that if the region is accidentally cleared by some command then a user can likely restore it, easily. So, in terms of "pronouns" again -- "addressing modes" for users -- the mark stack gives you a set of pronouns for recursing while the transient region ring gives you augmented short-term memory about "fat cursors". I'm really surprised, as I've been led to think about these features by the recent discussion, just exactly how complementary "GUI-style shift-select" and Emacs' user model and command interaction loop turn out to be. They fit together like hand and glove, if only Emacs will actually implement it that way. I'm one of those users who is both an Emacs power user *and* make pretty heavy use of GUI-style apps. I constantly have the low-level frustration of how selection, cut, paste, etc. work differently between these environments: often typing or mousing into some app as if it were Emacs or into Emacs as if it were some other app. So, I feel pretty viscerally the pain that work on shift selection is trying to address. I'm pretty convinced the little state machine model I've been developing here is a really good model for the desired functionality. So, I'm skeptical that all the hair of trying to use transient-mark-mode for this stuff is a good idea. -t