emacs-devel
[Top][All Lists]
Advanced

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

Variable behavior for `mouse-3' second click at same spot


From: Drew Adams
Subject: Variable behavior for `mouse-3' second click at same spot
Date: Tue, 30 Nov 2010 22:53:44 -0800

In Emacs, `mouse-3' does (1) or (2), by default:

1. On the mode line (are there other contexts also?): Pop up a menu.


2. Otherwise (`mouse-3' is bound to `mouse-save-then-kill'):

2a. Following any event except another `mouse-3' click at the same
    spot:

    Activate the region (if inactive) from point to the click
    position, or (if active) extend/restrict it according to the click
    position.  See `(emacs) Mouse Commands' for a complete description
    of the behavior (reminder), which is quite rich.

2b. Following a `mouse-3' click at the same location:

    Delete or kill the region text, depending on the value of option
    `mouse-drag-copy-region'.

(2b) is handy, but it is an arbitrary action.  Other actions could be
performed instead: candidate actions are any that make use of the
active region.  Unfortunately, the (2b) behavior is hard-coded.

It is trivial to let the (2b) action be variable, but that has been
resisted by Emacs Dev so far.  Below is an argument to support doing
this.


3. Consider the (2b) context in Dired.  The default behavior just
raises an error, because Dired is read-only.  Why not let a second
`mouse-3' click at the same spot in Dired do something wrt the
selected file and dir names?  Two obvious possibilities come to mind:
toggle whether each file/dir is marked, or pop up a menu that lets you
act in various ways on each of the selected files and dirs.

A menu here could either (i) include specific actions such as `Byte
Compile' and `Copy' or (ii) just have a few, general marking actions:
let you mark or unmark all of the selected files and dirs, or flag
them for deletion.

Another example: Picture mode.  Here, possible actions on the region
might better be actions on the rectangle it defines.  Pop up a menu
with picture-mode actions such as `Draw Rectangle' and `Clear
Rectangle'.

Using the attached file you can try example (prototype) behaviors for
Dired and Picture mode.  For Dired, you can use commands
`mouse3-dired-use-menu' and `mouse3-dired-use-toggle-marks' to switch
between the two possibilities mentioned above (menu or immediate
action), to experiment with them.  Just remember that these commands
affect only new Dired buffers, not existing ones, since they use
`dired-mode-hook'.

Another example: in Icicles, a second `mouse-3' at the same spot in
buffer *Completions* marks the selected completions (saves them for
later reuse).  Note that this, like Dired, is an example where the
text is a set of entries in tabular format (columns).  Each
*Completions* entry (candidate) is defined by its mouse-face, not its
text.  E.g., it is not delimited by whitespace (entries can contain
spaces and newlines).  A mode-specific function does what's needed
here: picks up the set of selected completions as a list.

Similar opportunities can exist for other tabular or line-list data:
*Buffer List*, compile/grep output, Info breadcrumbs,...  The Dired
example is typical here: the region sweeps out text linearly, but the
only thing we're interested in are the file names that are inside the
region.  The attached prototype only defines special behavior for
Dired, Picture mode, and Org mode.  It should get the idea across.


4. To implement all such behavior, this is all that's needed:

* In `mouse-save-then-kill', use a function-valued variable instead of
  hard-coding the second `mouse-3' click behavior.

* In the mode hooks, define a local value for that variable.

The change to `mouse-save-then-kill' is a trivial one-liner.  The
attached prototype just uses this:

  (funcall (mouse3-second-click-command) click prefix)

in place of this hard-wired deletion code:

  (if mouse-drag-copy-region
      (delete-region (mark t) (point))
    (kill-region (mark t) (point)))

The rest of the `mouse-save-then-kill' code remains the same.


5. But, you might ask, why not instead do as we do for the mode line
popup menus, that is, just bind a different command to `mouse-3' in
the local map (e.g. `dired-mode-map')?  First, because being able to
bind a variable (not just set it locally using a mode hook) provides
additional flexibility and more control over the context for a given
behavior.

And more importantly because the code that uses `mouse-1' and
`mouse-3' to define the region, extending and restricting it, is
ready-made in `mouse-save-then-kill'.  That is, the
`mouse-save-then-kill' code does useful region-defining stuff, in
addition to performing the final 2nd-click-same-spot deletion.

That region-defining behavior is completely independent of the
behavior that acts on the defined region (e.g. deleting it).  Though
independent, the two are coupled together within the same command and
bound to the same key, `mouse-3'.  There's no reason not to be able to
use those region-defining features together with different region
actions.

The mode-line popup menus on the other hand are not related to the
active region, so they don't offer a good model here.  This is about
actions that involve the region.  If we were to rely only on binding a
new command for each mode-specific set of region actions, then each
such command would need to duplicate the region-defining part of the
`mouse-save-then-kill' code (or else define the region in some other
way using the mouse).  It's much simpler to change
`mouse-save-then-kill' so that it becomes more general.


6. What about letting users also have a region menu at the global
level, that is, not just for certain modes?  There are lots of general
commands that act on the region.

But the current region-deletion behavior is admittedly very quick and
handy.  If we did provide a global `mouse-3' second-click menu then we
would want some alternative way to quickly delete the region using the
mouse, if possible.  (See #7.)

At least we can give users a choice, with a user option.  One value
can provide the same behavior we have now (kill/delete).  (That could
be the default.)  Another value can cause a general (not
mode-specific) region menu to pop up.  And we could let users
substitute some other command to get an alternative immediate action
if they want (no menu).

We can also let Lisp code override the user's global (default)
preference when appropriate (e.g. using a buffer-local variable, as
mentioned above).


7. When a user customizes the option so that a second `mouse-3' pops
up the menu, we can still offer a quick way to kill/delete the region,
by binding `mouse3-kill/delete-region' to a `mouse-3' double-click:

 (global-set-key [double-mouse-3] 'mouse3-kill/delete-region)

(And we can do that automatically, using defcustom :set.)

IOW, we can make `mouse-3' do double duty: kill/delete the region or
pop up a menu, depending on how quickly you click it twice at the same
spot.

When you try this using the attached file I think you'll find that
double-clicking is nearly the same as what you are already doing.
That is, when you use `mouse-3' to delete the selection, you typically
click it twice quickly at the same spot anyway.

I've been trying this out for a few days, and I now appreciate having
both a quick way to delete the selection (as before) and access to a
menu of region actions.  Yes, it takes a little getting used to - but
only a little.  I double-click most of the time and click twice
(slower) whenever I want to do something to the region other than
delete it.

The important thing is not this or that behavior (e.g. menu), but
giving users an option to change the behavior.


8. There are many possibilities for a global region menu.  It's best
to give users an easy way to customize it.  The attached prototype
shows one way to do this.


9. Please give it a try, and see what you think.


Note:

 * The active region can even be empty when you use the menu to act on
   it.  You can thus use a "replacement" action to just insert, and so
   on.

 * Because of what seems to be buggy backquote evaluation (I filed bug
   #7524 for it), the newlines in strings within the option's default
   value get converted to "\n".  So the Customize buffer is far wider
   than it should be.



----

Below are the submenus of the prototype popup menu, to give you some
idea in case you don't want to take a moment to try it.  The menu
itself is just this set of submenus:

,----
| Remove/Replace
| Copy
| To Register
| Rectangle
| Change Text
| Check, Correct, Convert
| Highlight     (only if you load library highlight.el, on Emacs Wiki)
| Print
| Count
| Misc
`----

,----
| Remove/Replace
| --------------
|  Kill
|  Delete
|  Yank (Replace)
|  _______________________________
|  Kill Rectangle
|  Delete Rectangle
|  Clear Rectangle (Replace)
|  String Rectangle (Replace)
|  Replace Rectangle from Register
`----

,----
| Copy
| ----
|  Copy as Kill
|  Copy to Register
|  __________________________
|  Copy Rectangle to Register
`----

,----
| To Register
| -----------
|  Copy
|  Delete
|  Append
|  Prepend
|  ______________
|  Copy Rectangle
|  Delete Rectangle
`----

,----
| Rectangle
| ---------
|  Kill
|  Delete
|  Open
|  Clear (Replace)
|  String (Replace)
|  Delimit Columns
|  _____________________
|  Delete to Register
|  Replace from Register
|  Copy to Register
`----

,----
| Change Text
| -----------
|  Boxquote                     (only if you load library boxquote.el)
|  Unboxquote                                       (" ")
|  Delimit Columns
|  Comment/Uncomment
|  __________________
|  Fill
|  Fill as Paragraph
|  Canonically Space
|  Indent
|  __________________
|  Capitalize
|  Upcase
|  Downcase
|  Remove Accents  (only if you load library unaccent.el, on the wiki)
|  __________________
|  Center
|  Reverse Line Order
`----

,----
| Check, Correct, Convert
| -----------------------
|  Ispell
|  Flyspell
|  Check Whitespace
|  Clean Up Whitespace
|  Printify
|  PR Printify
|  Compose Characters
|  Decompose Characters
|  __________________________
|  Encode using Coding System
|  Decode using Coding System
|  Encode using Format
|  Decode using Format
|  Decode Yenc
|  __________________________
|  EPA Encrypt
|  EPA Decrypt
|  PGG Encrypt
|  PGG Decrypt
`----

,----
| Highlight     (only if you load library highlight.el, on Emacs Wiki)
| ---------
|  Highlight
|  Highlight Regexp
|  Unhighlight
|  Unhighlight for Face
`----

,----
| Print
| -----
|  PostScript Print
|  PostScript Print with Faces
|  PostScript Preview
|  PostScript Number of Pages
|  _____________________________
|  Print to Text Printer
|  Print to Text Printer (`lpr')
|  Print with Paging (`pr')
|  _____________________________
|  BNF PostScript Analyze   (only if you load ebnf2ps.el, on the wiki)
|  BNF PostScript Print                             (" ")
|  BNF PostScript Save                              (" ")
`----

,----
| Count
| -----
|  Characters     (only if you load library misc-cmds.el, on the wiki)
|  Words
|  Lines
`----

,----
| Misc
| ----
|  Narrow
|  Eval
|  Key-Macro on Region Lines       (only if there is a keyboard macro)
|  Shell Command
|  Write to File
|  Create Bookmarks Matching (only if you load Bookmark+, on the wiki)
|  Highlight Bookmarks                              (" ")
|  Open in Browser
`----

Attachment: mouse3.el
Description: Binary data


reply via email to

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