unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Context menus and mouse-3       [was: Changes for emacs 28]
@ 2020-09-14  3:06 Drew Adams
  2020-09-14  6:11 ` Ergus
  2020-09-14  8:15 ` Göktuğ Kayaalp
  0 siblings, 2 replies; 112+ messages in thread
From: Drew Adams @ 2020-09-14  3:06 UTC (permalink / raw)
  To: Ergus
  Cc: philipk, Richard Stallman, emacs-devel, Arthur Miller,
	Dmitry Gutov, Gregory Heytings

Ergus> The real problem is that now the right click
Ergus> is bind to mouse-save-then-kill which I have
Ergus> never ever used, but probably others have.

and earlier:

Ergus> Sadly we have <mouse-3> bind to mouse-save-then-kill
Ergus> which I don't find useful at all, but maybe
Ergus> somebody will complain if we change it to
Ergus> C-<mouse-3> and move the panel to <mouse-3>.

I suspect that people who use a mouse but feel
that `mouse-save-then-kill' isn't useful have
never really understood what it offers.

Part of the lack of understanding may come from
not having read the manual about it.  Node `Mouse
Commands' of the Emacs manual makes the behavior
clear, and thus how useful it can be.

`mouse-3' lets you select text, delete or kill
text, and extend or reduce the selection.
That's a lot, and the actions to do those things
fit well together.

The extend-or-reduce bit works in a special way
if you've selected text by multiple clicking:
double-clicking or triple-clicking `mouse-1'.
I invite you to read the full text, if you
haven't already.  And then play with it a bit.
___

What happens if you just read the doc string?
You don't get a great idea of the richness of
`mouse-3' behavior, IMO.  It's OK, as far as a
doc string goes.  But it's unlikely to teach
someone what they can do with it.

Here's a suggestion for that doc string, and
also for the doc strings for other `mouse-*'
bindings (keys and commands): Provide a link
to that `Mouse Commands' node in the manual.
___

To me, the behavior of `mouse-save-then-kill'
is super useful.  So much so that my library
`mouse3.el' has, as a big part of its design,
to keep that behavior, while supplementing it
with `mouse-3' context menus.

You can of course optionally just get the menus.
But that's not where it's at - not the default
behavior.  The idea is to let you use the normal
behavior as many times as you like - extend,
reduce, kill, whatever - and then, if you like,
click `mouse-3' at the same place again, to pop
up a context menu.

The first part is optional, and so is the menu
popping.  Click in the same spot for the menu.
Click anywhere else for the vanilla behavior.

The other big part of the design is context
menu definition and behavior.  Those two parts
are logically independent, but it makes sense
for them to be in the same library.

There are alternative ways to define the menus,
and alternative ways to present them.  Menus can
be mode-dependent or not, dynamic (programmed)
or static.

Menus can, and generally do, differ, depending
on whether or not the region is active.  When
active, a context menu provides actions on the
region or things in it.  When inactive, it
provides actions on thing(s) located where you
click.

(There are always multiple things located at the
spot where you click.  It's up to a particular
menu to decide which things to act on.)
___

Should a context menu include _only_ items that
pertain to the region or the location clicked?
In general, no.  But you can certainly have
menus that do provide only that, if you want.

Should a context menu include global menus as
submenus, i.e., major-mode menus or menu-bar
menus?  That's up to you - an option controls
this.  If non-nil then yes: if the menu-bar is
visible then include the major-mode menus; else
include the menu-bar menus.
___

There are two alternative ways to define the
menus: (1) use keymaps and extended menu items
or (2) use the `x-poup-menu' form.  The former
is the default method.  It gives you more
control: keywords such as :visible and :enable,
for instance.  The latter is a bit simpler for
defining, perhaps.

Simple example code of using each method is
provided in `mouse3.el', with explanation.
An example of method #1 is provided for use
with Dired mode.  An example of #2 is provided
for use with Picture mode.
___

`mouse3.el' is completely compatible with the
traditional Emacs `mouse-3' behavior.  The
only place where they overlap is if you click
`mouse-3' twice at the same spot.

If you do that to delete the selected text,
then to get that effect with `mouse3.el' you
double-click instead.  Vanilla Emacs doesn't
distinguish a double-click from two clicks
separated by more than the double-click time.

(You can swap those two behaviors: slow 2-click
to delete instead of to show menu.)



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  3:06 Context menus and mouse-3 [was: Changes for emacs 28] Drew Adams
@ 2020-09-14  6:11 ` Ergus
  2020-09-14  6:28   ` Stefan Monnier
  2020-09-14 15:10   ` Context menus and mouse-3 [was: Changes for emacs 28] Eli Zaretskii
  2020-09-14  8:15 ` Göktuğ Kayaalp
  1 sibling, 2 replies; 112+ messages in thread
From: Ergus @ 2020-09-14  6:11 UTC (permalink / raw)
  To: Drew Adams
  Cc: philipk, Richard Stallman, emacs-devel, Arthur Miller,
	Dmitry Gutov, Gregory Heytings

Hi Drew:

I have been trying to find the usefulness for the command
'mouse-save-then-kill' and so far I understand what it does but I still
don't think it is more important/useful/intuitive than a good context
panel. When I said that I have never used it I mean because of a need
not because I don't know what it does.

Actually part of it's function (the kill) could be considered as a
problem more than a feature for less expert users or accidental double
right click (ex: looking for the panel).

Usually I prefer simpler solutions rather than complex and if I have to
do a proposal respecting to this, it will be:

1- Move mouse-save-then-kill to C-mouse-3

2- Move The panel in C-mouse-3 to mouse-3

3- Improve the panel just bit as has been mentioned before: promoting
copy, paste and cut to the main panel, adding spell and flymake
corrections (maybe group those) and so on... like in a normal editor.

Indeed the options I consider the most important/useful ones are already
there BUT only when the menu-bar is disabled (which gives me the only
good reason to disable it :p ).

I already tried your package and it still feels unnatural to me; but
also the hand installation is beyond the new users capabilities and
reserved only to part of the public.

That's my opinion and I think they are very sensible; but I don't want
to come into 1000 emails again arguing about this kind of details.

Best
Ergus

On Mon, Sep 14, 2020 at 03:06:43AM +0000, Drew Adams wrote:
>Ergus> The real problem is that now the right click
>Ergus> is bind to mouse-save-then-kill which I have
>Ergus> never ever used, but probably others have.
>
>and earlier:
>
>Ergus> Sadly we have <mouse-3> bind to mouse-save-then-kill
>Ergus> which I don't find useful at all, but maybe
>Ergus> somebody will complain if we change it to
>Ergus> C-<mouse-3> and move the panel to <mouse-3>.
>
>I suspect that people who use a mouse but feel
>that `mouse-save-then-kill' isn't useful have
>never really understood what it offers.
>
>Part of the lack of understanding may come from
>not having read the manual about it.  Node `Mouse
>Commands' of the Emacs manual makes the behavior
>clear, and thus how useful it can be.
>
>`mouse-3' lets you select text, delete or kill
>text, and extend or reduce the selection.
>That's a lot, and the actions to do those things
>fit well together.
>
>The extend-or-reduce bit works in a special way
>if you've selected text by multiple clicking:
>double-clicking or triple-clicking `mouse-1'.
>I invite you to read the full text, if you
>haven't already.  And then play with it a bit.
>___
>
>What happens if you just read the doc string?
>You don't get a great idea of the richness of
>`mouse-3' behavior, IMO.  It's OK, as far as a
>doc string goes.  But it's unlikely to teach
>someone what they can do with it.
>
>Here's a suggestion for that doc string, and
>also for the doc strings for other `mouse-*'
>bindings (keys and commands): Provide a link
>to that `Mouse Commands' node in the manual.
>___
>
>To me, the behavior of `mouse-save-then-kill'
>is super useful.  So much so that my library
>`mouse3.el' has, as a big part of its design,
>to keep that behavior, while supplementing it
>with `mouse-3' context menus.
>
>You can of course optionally just get the menus.
>But that's not where it's at - not the default
>behavior.  The idea is to let you use the normal
>behavior as many times as you like - extend,
>reduce, kill, whatever - and then, if you like,
>click `mouse-3' at the same place again, to pop
>up a context menu.
>
>The first part is optional, and so is the menu
>popping.  Click in the same spot for the menu.
>Click anywhere else for the vanilla behavior.
>
>The other big part of the design is context
>menu definition and behavior.  Those two parts
>are logically independent, but it makes sense
>for them to be in the same library.
>
>There are alternative ways to define the menus,
>and alternative ways to present them.  Menus can
>be mode-dependent or not, dynamic (programmed)
>or static.
>
>Menus can, and generally do, differ, depending
>on whether or not the region is active.  When
>active, a context menu provides actions on the
>region or things in it.  When inactive, it
>provides actions on thing(s) located where you
>click.
>
>(There are always multiple things located at the
>spot where you click.  It's up to a particular
>menu to decide which things to act on.)
>___
>
>Should a context menu include _only_ items that
>pertain to the region or the location clicked?
>In general, no.  But you can certainly have
>menus that do provide only that, if you want.
>
>Should a context menu include global menus as
>submenus, i.e., major-mode menus or menu-bar
>menus?  That's up to you - an option controls
>this.  If non-nil then yes: if the menu-bar is
>visible then include the major-mode menus; else
>include the menu-bar menus.
>___
>
>There are two alternative ways to define the
>menus: (1) use keymaps and extended menu items
>or (2) use the `x-poup-menu' form.  The former
>is the default method.  It gives you more
>control: keywords such as :visible and :enable,
>for instance.  The latter is a bit simpler for
>defining, perhaps.
>
>Simple example code of using each method is
>provided in `mouse3.el', with explanation.
>An example of method #1 is provided for use
>with Dired mode.  An example of #2 is provided
>for use with Picture mode.
>___
>
>`mouse3.el' is completely compatible with the
>traditional Emacs `mouse-3' behavior.  The
>only place where they overlap is if you click
>`mouse-3' twice at the same spot.
>
>If you do that to delete the selected text,
>then to get that effect with `mouse3.el' you
>double-click instead.  Vanilla Emacs doesn't
>distinguish a double-click from two clicks
>separated by more than the double-click time.
>
>(You can swap those two behaviors: slow 2-click
>to delete instead of to show menu.)
>



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  6:11 ` Ergus
@ 2020-09-14  6:28   ` Stefan Monnier
  2020-09-14  6:48     ` Ergus
  2020-09-15  4:35     ` Richard Stallman
  2020-09-14 15:10   ` Context menus and mouse-3 [was: Changes for emacs 28] Eli Zaretskii
  1 sibling, 2 replies; 112+ messages in thread
From: Stefan Monnier @ 2020-09-14  6:28 UTC (permalink / raw)
  To: Ergus
  Cc: philipk, Richard Stallman, emacs-devel, Arthur Miller,
	Dmitry Gutov, Gregory Heytings, Drew Adams

> I have been trying to find the usefulness for the command
> 'mouse-save-then-kill' and so far I understand what it does but I still
> don't think it is more important/useful/intuitive than a good context
> panel.

We don't need to choose, since we can get a context menu on
`down-mouse-3` and 'mouse-save-then-kill' on `mouse-3`.


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  6:28   ` Stefan Monnier
@ 2020-09-14  6:48     ` Ergus
  2020-09-14  7:49       ` tomas
  2020-09-15  4:35     ` Richard Stallman
  1 sibling, 1 reply; 112+ messages in thread
From: Ergus @ 2020-09-14  6:48 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Drew Adams, philipk, Richard Stallman, emacs-devel, Arthur Miller,
	Dmitry Gutov, Gregory Heytings

On Mon, Sep 14, 2020 at 02:28:14AM -0400, Stefan Monnier wrote:
>> I have been trying to find the usefulness for the command
>> 'mouse-save-then-kill' and so far I understand what it does but I still
>> don't think it is more important/useful/intuitive than a good context
>> panel.
>
>We don't need to choose, since we can get a context menu on
>`down-mouse-3` and 'mouse-save-then-kill' on `mouse-3`.
>
>
>        Stefan
>
down-mouse-3 means that it will need to keep the button pressed to keep
the panel visible/accessible?

If so, then that's not what the user expects in general. I have not
strong feelings about this (actually no feelings at all).

My main concern is that having a "kill" on double right click the
behavior is very error prone when trying to access the panel and could
produce accidental and unexpected behaviors very frequently.

That's why I think that protecting from an accidental kill requiring a
control presses is better while we remove the need of having "another
panel more" and we bring a more familiar/natural behavior.




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  6:48     ` Ergus
@ 2020-09-14  7:49       ` tomas
  2020-09-14  7:58         ` Thibaut Verron
                           ` (2 more replies)
  0 siblings, 3 replies; 112+ messages in thread
From: tomas @ 2020-09-14  7:49 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 693 bytes --]

On Mon, Sep 14, 2020 at 08:48:25AM +0200, Ergus wrote:
> On Mon, Sep 14, 2020 at 02:28:14AM -0400, Stefan Monnier wrote:
> >>I have been trying to find the usefulness for the command
> >>'mouse-save-then-kill' and so far I understand what it does but I still
> >>don't think it is more important/useful/intuitive than a good context
> >>panel.
> >
> >We don't need to choose, since we can get a context menu on
> >`down-mouse-3` and 'mouse-save-then-kill' on `mouse-3`.
> >
> >
> >       Stefan
> >
> down-mouse-3 means that it will need to keep the button pressed to keep
> the panel visible/accessible?

FWIW, it's what I'd expect. Click, slide up/down along the menu,
release.

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-14  7:49       ` tomas
@ 2020-09-14  7:58         ` Thibaut Verron
  2020-09-14  8:29           ` tomas
  2020-09-14 15:12         ` Eli Zaretskii
  2020-09-14 15:47         ` Drew Adams
  2 siblings, 1 reply; 112+ messages in thread
From: Thibaut Verron @ 2020-09-14  7:58 UTC (permalink / raw)
  To: tomas; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 992 bytes --]

Le lun. 14 sept. 2020 à 09:49, <tomas@tuxteam.de> a écrit :

> On Mon, Sep 14, 2020 at 08:48:25AM +0200, Ergus wrote:
> > On Mon, Sep 14, 2020 at 02:28:14AM -0400, Stefan Monnier wrote:
> > >>I have been trying to find the usefulness for the command
> > >>'mouse-save-then-kill' and so far I understand what it does but I still
> > >>don't think it is more important/useful/intuitive than a good context
> > >>panel.
> > >
> > >We don't need to choose, since we can get a context menu on
> > >`down-mouse-3` and 'mouse-save-then-kill' on `mouse-3`.
> > >
> > >
> > >       Stefan
> > >
> > down-mouse-3 means that it will need to keep the button pressed to keep
> > the panel visible/accessible?
>
> FWIW, it's what I'd expect. Click, slide up/down along the menu,
> release.
>

I never realized that most applications also support this way of using the
context menu.

I find that hold-and-slide moves are annoying to do reliably with a laptop
touch-pad, though.

[-- Attachment #2: Type: text/html, Size: 1445 bytes --]

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  3:06 Context menus and mouse-3 [was: Changes for emacs 28] Drew Adams
  2020-09-14  6:11 ` Ergus
@ 2020-09-14  8:15 ` Göktuğ Kayaalp
  2020-09-14  8:33   ` tomas
  2020-09-14 15:57   ` Drew Adams
  1 sibling, 2 replies; 112+ messages in thread
From: Göktuğ Kayaalp @ 2020-09-14  8:15 UTC (permalink / raw)
  To: emacs-devel
  Cc: Ergus, Richard Stallman, philipk, Arthur Miller, Dmitry Gutov,
	Gregory Heytings

On 2020-09-14 06:06 +03, Drew Adams <drew.adams@oracle.com> wrote:
> I suspect that people who use a mouse but feel
> that `mouse-save-then-kill' isn't useful have
> never really understood what it offers.

I’d say a major contributing factor is that with most touchpads this is
a very unergonomic binding.  Pressing and holding mouse-1 and making
precise selections is a PITA with these smushy plasticy cringy things
already.

--
İ. Göktuğ Kayaalp / @cadadr / <https://www.gkayaalp.com/>
pgp:   024C 30DD 597D 142B 49AC 40EB 465C D949 B101 2427



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-14  7:58         ` Thibaut Verron
@ 2020-09-14  8:29           ` tomas
  2020-09-14  9:03             ` Thibaut Verron
  2020-09-14 15:59             ` Drew Adams
  0 siblings, 2 replies; 112+ messages in thread
From: tomas @ 2020-09-14  8:29 UTC (permalink / raw)
  To: Thibaut Verron; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1529 bytes --]

On Mon, Sep 14, 2020 at 09:58:12AM +0200, Thibaut Verron wrote:
> Le lun. 14 sept. 2020 à 09:49, <tomas@tuxteam.de> a écrit :

[...]

> > FWIW, it's what I'd expect. Click, slide up/down along the menu,
> > release.
> >
> 
> I never realized that most applications also support this way of using the
> context menu.

UI is like a labyrinth full of differently trained rats inside ;-)

> I find that hold-and-slide moves are annoying to do reliably with a laptop
> touch-pad, though.

I haven't a touchpad currently (wrong: there is one, but I vastly
prefer to use the trackpoint). Some years ago I /had/ to use a
touchpad (bigcorps: the bosses know what you need better than
yourself!), but somehow I managed: click+hold was (one quick tap+
release, tap+stay and then move). This was pretty reliable.

Of course those things are so extremely variable (all the possible
combos of personal motoric predispositions, touchpad hardware and
firm/software, etc.) that you can't make a general rule.

This is why I added another point of view.

People are extremely different [1]. Hardwares are, too, but
somewhat less. Same for firmwares. Same for softwares. The
latter two are extremely buggy, at that.

When asserting things about UI "this-and-this is better", take
into account that you are biased by your prior experience. Give
other people a way to opt out of your utopia, which might well
be their distopia :-)

Cheers

[1] Bigcorps, data harvesters and economists notwithstanding
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  8:15 ` Göktuğ Kayaalp
@ 2020-09-14  8:33   ` tomas
  2020-09-14 15:57   ` Drew Adams
  1 sibling, 0 replies; 112+ messages in thread
From: tomas @ 2020-09-14  8:33 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 705 bytes --]

On Mon, Sep 14, 2020 at 11:15:27AM +0300, Göktuğ Kayaalp wrote:
> On 2020-09-14 06:06 +03, Drew Adams <drew.adams@oracle.com> wrote:
> > I suspect that people who use a mouse but feel
> > that `mouse-save-then-kill' isn't useful have
> > never really understood what it offers.
> 
> I’d say a major contributing factor is that with most touchpads this is
> a very unergonomic binding.  Pressing and holding mouse-1 and making
> precise selections is a PITA with these smushy plasticy cringy things
> already.

See my other response: you can teach a touchpad (gee, alliteration)
to behave for those cases. By now, I just only buy (second hand!)
notebooks with a trackpad.

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-14  8:29           ` tomas
@ 2020-09-14  9:03             ` Thibaut Verron
  2020-09-14  9:12               ` Göktuğ Kayaalp
  2020-09-14 11:37               ` tomas
  2020-09-14 15:59             ` Drew Adams
  1 sibling, 2 replies; 112+ messages in thread
From: Thibaut Verron @ 2020-09-14  9:03 UTC (permalink / raw)
  To: tomas; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2277 bytes --]

Le lun. 14 sept. 2020 à 10:29, <tomas@tuxteam.de> a écrit :

> On Mon, Sep 14, 2020 at 09:58:12AM +0200, Thibaut Verron wrote:
> > Le lun. 14 sept. 2020 à 09:49, <tomas@tuxteam.de> a écrit :
>
> [...]
>
> > > FWIW, it's what I'd expect. Click, slide up/down along the menu,
> > > release.
> > >
> >
> > I never realized that most applications also support this way of using
> the
> > context menu.
>
> UI is like a labyrinth full of differently trained rats inside ;-)
>

Agreed.

That might be why most GUI applications transparently support both ways of
operating the context menu. Given that their labyrinth/UI designers had
more time, means and motivation to investigate mouse behaviors than we do,
taking the same direction could be a good first step.


>
> > I find that hold-and-slide moves are annoying to do reliably with a
> laptop
> > touch-pad, though.
>
> I haven't a touchpad currently (wrong: there is one, but I vastly
> prefer to use the trackpoint). Some years ago I /had/ to use a
> touchpad (bigcorps: the bosses know what you need better than
> yourself!), but somehow I managed: click+hold was (one quick tap+
> release, tap+stay and then move). This was pretty reliable.
>

I might have had bad luck or small palms, but I could never get complex tap
combos to work reliably with palm detection.

At least I'm thankful that I never had to use one of those touchpads
without click buttons...


> Of course those things are so extremely variable (all the possible
> combos of personal motoric predispositions, touchpad hardware and
> firm/software, etc.) that you can't make a general rule.
>

Agreed. Again, I believe that it supports the idea of supporting both
usages.


> When asserting things about UI "this-and-this is better", take
> into account that you are biased by your prior experience. Give
> other people a way to opt out of your utopia, which might well
> be their distopia :-)
>

Is that meant for me personally? Sorry if I came across as assertive, it
was really the opposite of my intention.

I try to make it clear when my statements represent only my opinion and my
experience. Sorry if I failed to convey that meaning at times, I will try
harder.

Best,
Thibaut

[-- Attachment #2: Type: text/html, Size: 3315 bytes --]

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-14  9:03             ` Thibaut Verron
@ 2020-09-14  9:12               ` Göktuğ Kayaalp
  2020-09-14 11:37               ` tomas
  1 sibling, 0 replies; 112+ messages in thread
From: Göktuğ Kayaalp @ 2020-09-14  9:12 UTC (permalink / raw)
  To: thibaut.verron; +Cc: tomas, emacs-devel

On 2020-09-14 12:03 +03, Thibaut Verron <thibaut.verron@gmail.com> wrote:
> That might be why most GUI applications transparently support both ways of
> operating the context menu. Given that their labyrinth/UI designers had
> more time, means and motivation to investigate mouse behaviors than we do,
> taking the same direction could be a good first step.

That happens at the toolkit level, i.e. with any modern toolkit you
wouldn’t need to go out of your way to support that kind of interaction.
Same goes with e.g. pressing a button but then moving your mouse outside
of it and release in order to cancel the button press.

--
İ. Göktuğ Kayaalp / @cadadr / <https://www.gkayaalp.com/>
pgp:   024C 30DD 597D 142B 49AC 40EB 465C D949 B101 2427



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-14  9:03             ` Thibaut Verron
  2020-09-14  9:12               ` Göktuğ Kayaalp
@ 2020-09-14 11:37               ` tomas
  2020-09-14 12:36                 ` Thibaut Verron
  1 sibling, 1 reply; 112+ messages in thread
From: tomas @ 2020-09-14 11:37 UTC (permalink / raw)
  To: Thibaut Verron; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1733 bytes --]

On Mon, Sep 14, 2020 at 11:03:19AM +0200, Thibaut Verron wrote:
> Le lun. 14 sept. 2020 à 10:29, <tomas@tuxteam.de> a écrit :

[...]

> > [click-and-drag]

[...]

> I might have had bad luck or small palms, but I could never get complex tap
> combos to work reliably with palm detection.

All was an one-finger operation. No palms involved (I know my limitations
when challenging the Gods ;-)

[...]

> Agreed. Again, I believe that it supports the idea of supporting both
> usages.

Yes. Not always easy, but...

> > When asserting things about UI "this-and-this is better", take
> > into account that you are biased by your prior experience. Give
> > other people a way to opt out of your utopia, which might well
> > be their distopia :-)
> >
> 
> Is that meant for me personally? Sorry if I came across as assertive, it
> was really the opposite of my intention.

Oh, sorry. No, this was a "generic you". And...

> I try to make it clear when my statements represent only my opinion and my
> experience. Sorry if I failed to convey that meaning at times, I will try
> harder.

...by the way, not criticising your tone or something. You come across
as an extremely polite person.

Rather trying to raise awareness that many of the patterns we take for
granted are just the result of some training, which might be totally
different for someone else.

Of course, one might argue that we all should be trained the same way
(it happens with other things too, like language (verbal and non-verbal),
so why not with computers?). Opinions on that might differ. For me this
is dystopia, especially in the current context, where roughly ten big
corps dominate that space.

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-14 11:37               ` tomas
@ 2020-09-14 12:36                 ` Thibaut Verron
  0 siblings, 0 replies; 112+ messages in thread
From: Thibaut Verron @ 2020-09-14 12:36 UTC (permalink / raw)
  To: tomas; +Cc: emacs-devel

Le lun. 14 sept. 2020 à 13:37, <tomas@tuxteam.de> a écrit :
>
> On Mon, Sep 14, 2020 at 11:03:19AM +0200, Thibaut Verron wrote:
> > Le lun. 14 sept. 2020 à 10:29, <tomas@tuxteam.de> a écrit :
>
> [...]
>
> > > [click-and-drag]
>
> [...]
>
> > I might have had bad luck or small palms, but I could never get complex tap
> > combos to work reliably with palm detection.
>
> All was an one-finger operation. No palms involved (I know my limitations
> when challenging the Gods ;-)

Yes, sorry, I was unclear. My trouble is usually to get the palm detection to
correctly detect my palm, and not incorrectly detect my finger(s) -- right-click
is usually emulated by a two-finger tap, to make things more difficult.


> Oh, sorry. No, this was a "generic you". And...

Okay, no problem, I just wanted to be sure. :)

> Rather trying to raise awareness that many of the patterns we take for
> granted are just the result of some training, which might be totally
> different for someone else.
>
> Of course, one might argue that we all should be trained the same way
> (it happens with other things too, like language (verbal and non-verbal),
> so why not with computers?). Opinions on that might differ. For me this
> is dystopia, especially in the current context, where roughly ten big
> corps dominate that space.

I agree.

There is probably a fair middle to strike there, and a lot has happened already
in that direction. I don't know if it is something which can (let
alone should) be
forced by us or the head-of-UI at big-tech, or rather something which happens
naturally -- very much like a language, as you point out.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  6:11 ` Ergus
  2020-09-14  6:28   ` Stefan Monnier
@ 2020-09-14 15:10   ` Eli Zaretskii
  2020-09-14 16:42     ` Göktuğ Kayaalp
  1 sibling, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2020-09-14 15:10 UTC (permalink / raw)
  To: Ergus; +Cc: philipk, rms, emacs-devel, arthur.miller, dgutov, ghe, drew.adams

> Date: Mon, 14 Sep 2020 08:11:11 +0200
> From: Ergus <spacibba@aol.com>
> Cc: philipk@posteo.net, Richard Stallman <rms@gnu.org>, emacs-devel@gnu.org,
>  Arthur Miller <arthur.miller@live.com>,
>  Dmitry Gutov <dgutov@yandex.ru>, Gregory Heytings <ghe@sdf.org>
> 
> Hi Drew:

I'm not Drew.  Still...

> I have been trying to find the usefulness for the command
> 'mouse-save-then-kill' and so far I understand what it does but I still
> don't think it is more important/useful/intuitive than a good context
> panel. When I said that I have never used it I mean because of a need
> not because I don't know what it does.
> 
> Actually part of it's function (the kill) could be considered as a
> problem more than a feature for less expert users or accidental double
> right click (ex: looking for the panel).
> 
> Usually I prefer simpler solutions rather than complex and if I have to
> do a proposal respecting to this, it will be:
> 
> 1- Move mouse-save-then-kill to C-mouse-3
> 
> 2- Move The panel in C-mouse-3 to mouse-3

AFAIK, what Emacs does with mouse-3 is similar to what other X-aware
applications do.  If we change that by default, it might cause
annoyance to those who use these X-related features.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  7:49       ` tomas
  2020-09-14  7:58         ` Thibaut Verron
@ 2020-09-14 15:12         ` Eli Zaretskii
  2020-09-14 15:47         ` Drew Adams
  2 siblings, 0 replies; 112+ messages in thread
From: Eli Zaretskii @ 2020-09-14 15:12 UTC (permalink / raw)
  To: tomas; +Cc: emacs-devel

> Date: Mon, 14 Sep 2020 09:49:02 +0200
> From: <tomas@tuxteam.de>
> 
> > down-mouse-3 means that it will need to keep the button pressed to keep
> > the panel visible/accessible?
> 
> FWIW, it's what I'd expect. Click, slide up/down along the menu,
> release.

I wouldn't expect that, FWIW.  I'm used to context menus that stay
open after you release the right mouse button.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  7:49       ` tomas
  2020-09-14  7:58         ` Thibaut Verron
  2020-09-14 15:12         ` Eli Zaretskii
@ 2020-09-14 15:47         ` Drew Adams
  2020-09-14 20:54           ` tomas
  2 siblings, 1 reply; 112+ messages in thread
From: Drew Adams @ 2020-09-14 15:47 UTC (permalink / raw)
  To: tomas, emacs-devel

> > down-mouse-3 means that it will need to keep the button pressed to keep
> > the panel visible/accessible?
> 
> FWIW, it's what I'd expect. Click, slide up/down along the menu,
> release.

("Click" generally (at least in Emacs) means press and
release, not press and hold pressed.  I'm guessing you
meant that you expect to press and hold while sliding
along the menu?)



^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  8:15 ` Göktuğ Kayaalp
  2020-09-14  8:33   ` tomas
@ 2020-09-14 15:57   ` Drew Adams
  2020-09-15 19:17     ` Juri Linkov
  1 sibling, 1 reply; 112+ messages in thread
From: Drew Adams @ 2020-09-14 15:57 UTC (permalink / raw)
  To: Göktuğ Kayaalp, emacs-devel
  Cc: philipk, Richard Stallman, Ergus, Arthur Miller, Dmitry Gutov,
	Gregory Heytings

> > I suspect that people who use a mouse but feel
> > that `mouse-save-then-kill' isn't useful have
> > never really understood what it offers.
> 
> I’d say a major contributing factor is that with most touchpads this is
> a very unergonomic binding.  Pressing and holding mouse-1 and making
> precise selections is a PITA with these smushy plasticy cringy things
> already.

(I hate touch pads.)

But you don't have to press-and-hold `mouse-1' (or
touch-pad equivalent), and drag it to select text.

Seriously, read `Mouse Commands' if you haven't
already, and give it a try.

Double-click (`mouse-1') on a word, then click
`mouse-3' on another word. The selection picks up
whole words, from the first through the last you
clicked.

Triple-click a line, then click `mouse-3' on
another line.  The selection picks up whole lines.

[I'd like to see the double-clicking extended, so
that if you double-click a paren in Lisp it picks
up the full sexp, and if you then `mouse-3' another
sexp it picks up full sexps in the interval.  But
this is a bit trickier.]



^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-14  8:29           ` tomas
  2020-09-14  9:03             ` Thibaut Verron
@ 2020-09-14 15:59             ` Drew Adams
  1 sibling, 0 replies; 112+ messages in thread
From: Drew Adams @ 2020-09-14 15:59 UTC (permalink / raw)
  To: tomas, Thibaut Verron; +Cc: emacs-devel

> Give other people a way to opt out of your utopia,
> which might well be their d[y]stopia :-)

+1.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14 15:10   ` Context menus and mouse-3 [was: Changes for emacs 28] Eli Zaretskii
@ 2020-09-14 16:42     ` Göktuğ Kayaalp
  0 siblings, 0 replies; 112+ messages in thread
From: Göktuğ Kayaalp @ 2020-09-14 16:42 UTC (permalink / raw)
  To: emacs-devel; +Cc: Ergus, rms, philipk, arthur.miller, dgutov, ghe, drew.adams

On 2020-09-14 18:10 +03, Eli Zaretskii <eliz@gnu.org> wrote:
> AFAIK, what Emacs does with mouse-3 is similar to what other X-aware
> applications do.  If we change that by default, it might cause
> annoyance to those who use these X-related features.

[ I should’ve replied to your reply to my relevant email on another
  thread so that the flow of the treads aren’t broken, but I’ll be a bit
  lazy with this one.  Hope I don’t annoy anybody... ]

I never noticed that behaviour.  But while that’s a nice feature I doubt
it’s what people expect when they hear ‘context menu’.  It’s more like
the thing I gave a broken example of on the other thread.  I’d say it’s
less powerful than this C-mouse-3 context menu, but if we’re trying to
provide people with something they’d _expect_ to see when right
clicking, that’s not it.

FWIW my example was a combination of VS Code menu and Linux Mint’s
generic text editor Xed’s menu, plus a couple emacsy additions.



@Drew: Just checked out mouse3.el, read the comments.  Seems to be a
powerful extension, but IDK how fit it is for this particular task of
making some cosmetic adjustments to make some basic features have more
contemporary frontends (tho it’s quite probable that I’m missing
something here, because I barely if ever use any of the mouse, toolbar
or the menu bar).

--
İ. Göktuğ Kayaalp / @cadadr / <https://www.gkayaalp.com/>
pgp:   024C 30DD 597D 142B 49AC 40EB 465C D949 B101 2427



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14 15:47         ` Drew Adams
@ 2020-09-14 20:54           ` tomas
  0 siblings, 0 replies; 112+ messages in thread
From: tomas @ 2020-09-14 20:54 UTC (permalink / raw)
  To: Drew Adams; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 515 bytes --]

On Mon, Sep 14, 2020 at 03:47:35PM +0000, Drew Adams wrote:
> > > down-mouse-3 means that it will need to keep the button pressed to keep
> > > the panel visible/accessible?
> > 
> > FWIW, it's what I'd expect. Click, slide up/down along the menu,
> > release.
> 
> ("Click" generally (at least in Emacs) means press and
> release, not press and hold pressed.  I'm guessing you
> meant that you expect to press and hold while sliding
> along the menu?)

Spot on. I was somewhat sloppy.

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14  6:28   ` Stefan Monnier
  2020-09-14  6:48     ` Ergus
@ 2020-09-15  4:35     ` Richard Stallman
  2020-09-15 13:11       ` Stefan Monnier
  1 sibling, 1 reply; 112+ messages in thread
From: Richard Stallman @ 2020-09-15  4:35 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: spacibba, philipk, emacs-devel, arthur.miller, dgutov, ghe,
	drew.adams

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > We don't need to choose, since we can get a context menu on
  > `down-mouse-3` and 'mouse-save-then-kill' on `mouse-3`.

Have you tried doing that?  How does it work in practice?

-- 
Dr Richard Stallman
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-15  4:35     ` Richard Stallman
@ 2020-09-15 13:11       ` Stefan Monnier
  2020-09-19  7:47         ` Tak Kunihiro
                           ` (2 more replies)
  0 siblings, 3 replies; 112+ messages in thread
From: Stefan Monnier @ 2020-09-15 13:11 UTC (permalink / raw)
  To: Richard Stallman
  Cc: spacibba, philipk, emacs-devel, arthur.miller, dgutov, ghe,
	drew.adams

Richard Stallman [2020-09-15 00:35:58] wrote:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
>   > We don't need to choose, since we can get a context menu on
>   > `down-mouse-3` and 'mouse-save-then-kill' on `mouse-3`.
>
> Have you tried doing that?  How does it work in practice?

Here's the code I'm using:

    (let ((default-context-menu
            `(menu-item ,(purecopy "Menu Bar") ignore
              :filter (lambda (_)
                        (if (zerop (or (frame-parameter nil 'menu-bar-lines) 0))
                            (mouse-menu-bar-map)
                          (mouse-menu-major-mode-map))))))
      (global-set-key [C-down-mouse-3] default-context-menu)
      (global-set-key [context-menu] default-context-menu))
    
    (global-set-key [down-mouse-3] #'mouse-maybe-context-menu)
    (defun mouse-maybe-context-menu (event)
      "Bring up a context menu for a long click.
    See `mouse-long-click-time' and `mouse-context-menu-function'."
      (interactive "@e")
      (if (let ((track-mouse t)) (sit-for (/ mouse-long-click-time 1000.0)))
          (push (cons 'context-menu (cdr event)) unread-command-events)))

It's not good enough for `master` (IIRC the sit-for tends to return nil
immediately in some circumstances), but I didn't pursue this any further
given the lack of interest at the time.  I can't think of any reason why
it should be hard to fix.


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-14 15:57   ` Drew Adams
@ 2020-09-15 19:17     ` Juri Linkov
  2020-09-15 20:33       ` Drew Adams
  2020-09-16  2:24       ` Eli Zaretskii
  0 siblings, 2 replies; 112+ messages in thread
From: Juri Linkov @ 2020-09-15 19:17 UTC (permalink / raw)
  To: Drew Adams
  Cc: philipk, Richard Stallman, Ergus, emacs-devel, Gregory Heytings,
	Arthur Miller, Dmitry Gutov, Göktuğ Kayaalp

> Seriously, read `Mouse Commands' if you haven't
> already, and give it a try.

Mouse support is poor in Emacs, this is the reason
why I don't use the mouse in Emacs.  More below:

> Double-click (`mouse-1') on a word, then click
> `mouse-3' on another word. The selection picks up
> whole words, from the first through the last you
> clicked.

In other apps, the same is achieved by double-click
(`mouse-1') on a word, then double-click the same
(`mouse-1') on another word while holding down the Shift key.

> Triple-click a line, then click `mouse-3' on
> another line.  The selection picks up whole lines.

In other apps, triple-click a line, then again triple-click
on another line while holding down the Shift key.

But what if you need first to select a line, then extend
the selection to a word?  In other apps, triple-click a line,
then double-click `mouse-1' on a word while holding down the Shift key.
In Emacs, this is impossible.

Also in other apps Shift+F10 opens the context menu,
but why not in Emacs?

> [I'd like to see the double-clicking extended, so
> that if you double-click a paren in Lisp it picks
> up the full sexp, and if you then `mouse-3' another
> sexp it picks up full sexps in the interval.  But
> this is a bit trickier.]

It would be easier to use this as: double-click a paren to select
a sexp, then double-click another paren to select another sexp
while holding down the Shift key.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-15 19:17     ` Juri Linkov
@ 2020-09-15 20:33       ` Drew Adams
  2020-09-15 22:47         ` Ergus via Emacs development discussions.
  2020-09-16 19:41         ` Juri Linkov
  2020-09-16  2:24       ` Eli Zaretskii
  1 sibling, 2 replies; 112+ messages in thread
From: Drew Adams @ 2020-09-15 20:33 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, Richard Stallman, Ergus, emacs-devel,
	Göktuğ Kayaalp, Arthur Miller, Dmitry Gutov,
	Gregory Heytings

> > read `Mouse Commands' if you haven't
> > already, and give it a try.
> 
> Mouse support is poor in Emacs, this is the reason
> why I don't use the mouse in Emacs.

I disagree that mouse support is poor in Emacs.

I use a mouse in several other applications much
of the workday, and Emacs mouse support is superior
in every respect I'm aware of.  But I'm no expert
on the use of mice.  And perhaps the mouse support
in the apps I use is not a reference.

> > Double-click (`mouse-1') on a word, then click
> > `mouse-3' on another word. The selection picks up
> > whole words, from the first through the last you
> > clicked.
> 
> In other apps, the same is achieved by double-click
> (`mouse-1') on a word, then double-click the same
> (`mouse-1') on another word while holding down the Shift key.

And that's better why?  Having to use both the
keyboard and the mouse?

(One of the arguments made by a few people in
this discussion was that `C-mouse-3' makes you
do that to get a right-click menu.)

> > Triple-click a line, then click `mouse-3' on
> > another line.  The selection picks up whole lines.
> 
> In other apps, triple-click a line, then again triple-click
> on another line while holding down the Shift key.

Both keyboard and mouse again.  Better?  Not IMO.
 
> But what if you need first to select a line, then extend
> the selection to a word?  In other apps, triple-click a line,
> then double-click `mouse-1' on a word while holding down the Shift key.
> In Emacs, this is impossible.

Granted.  But again, both keyboard and mouse.

We could provide a keyboard + mouse combination
for such use cases if that were a common need.

> Also in other apps Shift+F10 opens the context menu,
> but why not in Emacs?

That's orthogonal.  Nothing prevents also having
a keyboard key sequence to open a context menu.
(Presumably the "location" it refers to would
be point.)

The impetus for this discussion was expectations
of new users to get a context menu on `mouse-3'.
(But newbies are not the only reason for such a
feature.)

> > [I'd like to see the double-clicking extended, so
> > that if you double-click a paren in Lisp it picks
> > up the full sexp, and if you then `mouse-3' another
> > sexp it picks up full sexps in the interval.  But
> > this is a bit trickier.]
> 
> It would be easier to use this as: double-click a paren to select
> a sexp, then double-click another paren to select another sexp
> while holding down the Shift key.

Another keyboard + mouse mix.

[What I described already works for simple cases, BTW.
E.g. double-click a paren in Lisp (open or close),
then `mouse-3' another paren, to select up the lists
and intervening sexps.]



^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-15 20:33       ` Drew Adams
@ 2020-09-15 22:47         ` Ergus via Emacs development discussions.
  2020-09-16  0:29           ` Corwin Brust
                             ` (2 more replies)
  2020-09-16 19:41         ` Juri Linkov
  1 sibling, 3 replies; 112+ messages in thread
From: Ergus via Emacs development discussions. @ 2020-09-15 22:47 UTC (permalink / raw)
  To: emacs-devel, Drew Adams, Juri Linkov
  Cc: philipk, Richard Stallman, Göktuğ Kayaalp,
	Arthur Miller, Dmitry Gutov, Gregory Heytings



On September 15, 2020 10:33:51 PM GMT+02:00, Drew Adams <drew.adams@oracle.com> wrote:
>> > read `Mouse Commands' if you haven't
>> > already, and give it a try.
>> 
>> Mouse support is poor in Emacs, this is the reason
>> why I don't use the mouse in Emacs.
>
>I disagree that mouse support is poor in Emacs.
>
So you are the only one I know so far with that opinion.

>I use a mouse in several other applications much
>of the workday, and Emacs mouse support is superior
>in every respect I'm aware of.  But I'm no expert
>on the use of mice.  And perhaps the mouse support
>in the apps I use is not a reference.
>
This is the same problem than undo-redo. Maybe the features are actually better technically speaking or to whom knows all the tricks and trains himself for years; but it worth nothing if the users feel uncomfortable or don't values some of the details that justify complexity in others. (Like hiding the context panel with a control or not having a redo button or not deleting the selection) Or just don't need them.

There are some "standards" in mouse interaction determined/imposed by most of the gui programing interfaces from visual studio or java to qt5 and gtk. The developers of all the aplications have been following them for years and most of the user are used to them.

So this is the "dilema". Or we change a bit (1 binding) to ease the user experience and learning curve OR we expect that all the potential users change their expectations, trainings and don't go to any other editor but use emacs because we pretend we offer a better functionality that they are not aware of and most probably don't need or never learn/use because is complex to remember.

>> > Double-click (`mouse-1') on a word, then click
>> > `mouse-3' on another word. The selection picks up
>> > whole words, from the first through the last you
>> > clicked.
>> 
>> In other apps, the same is achieved by double-click
>> (`mouse-1') on a word, then double-click the same
>> (`mouse-1') on another word while holding down the Shift key.
>
>And that's better why?  Having to use both the
>keyboard and the mouse?
>
Usually the other hand is already in the keyboard and close to a shift. Comparing, our approach of moving the mouse to the toolbar to copy after the selection is probably less efficient than anything else or the fact that M-w and C-y dont share any key like C-c/C-v or that we need the two hand to undo instead of C-z. All these are less efficient too but we are used to them.

So the argument of holding a shift seems a bit weak for any old emacs user right?

>(One of the arguments made by a few people in
>this discussion was that `C-mouse-3' makes you
>do that to get a right-click menu.)
>
No, the argument is also that many applications intercept that C-mouse action, in terminal doesn't work AND the user don't expect it to be there because probably we are one of the few (or the only) hiding the panel there after a control.


>> > Triple-click a line, then click `mouse-3' on
>> > another line.  The selection picks up whole lines.
>> 
>> In other apps, triple-click a line, then again triple-click
>> on another line while holding down the Shift key.
>
>Both keyboard and mouse again.  Better?  Not IMO.
> 
But just the same button-1 so yes, probably simpler to remember and intuitive for any office (or other modern editor) user.

>> But what if you need first to select a line, then extend
>> the selection to a word?  In other apps, triple-click a line,
>> then double-click `mouse-1' on a word while holding down the Shift
>key.
>> In Emacs, this is impossible.
>
>Granted.  But again, both keyboard and mouse.
>
And again, they are the same, mouse-1 and shift, so exactly the sames... This is a pattern. Select with mouse-1 actions in panel in mouse-3 move with the wheel.

Simple is better than complex.
Complex is better than complicated.

The emacs approach with mouse is indeed complicated.

>We could provide a keyboard + mouse combination
>for such use cases if that were a common need.
>
>> Also in other apps Shift+F10 opens the context menu,
>> but why not in Emacs?
>
>That's orthogonal.  Nothing prevents also having
>a keyboard key sequence to open a context menu.
>(Presumably the "location" it refers to would
>be point.)
>
There is the <print> key which many applications use to show the panel from keyboard too.

>The impetus for this discussion was expectations
>of new users to get a context menu on `mouse-3'.
>(But newbies are not the only reason for such a
>feature.)
>
>> > [I'd like to see the double-clicking extended, so
>> > that if you double-click a paren in Lisp it picks
>> > up the full sexp, and if you then `mouse-3' another
>> > sexp it picks up full sexps in the interval.  But
>> > this is a bit trickier.]
>> 
>> It would be easier to use this as: double-click a paren to select
>> a sexp, then double-click another paren to select another sexp
>> while holding down the Shift key.
>
>Another keyboard + mouse mix.
>
>[What I described already works for simple cases, BTW.
>E.g. double-click a paren in Lisp (open or close),
>then `mouse-3' another paren, to select up the lists
>and intervening sexps.]

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-15 22:47         ` Ergus via Emacs development discussions.
@ 2020-09-16  0:29           ` Corwin Brust
  2020-09-16  1:47             ` Drew Adams
  2020-09-16  1:25           ` Drew Adams
  2020-09-16 14:13           ` Eli Zaretskii
  2 siblings, 1 reply; 112+ messages in thread
From: Corwin Brust @ 2020-09-16  0:29 UTC (permalink / raw)
  To: Ergus
  Cc: philipk, Richard Stallman, Juri Linkov, Gregory Heytings,
	Arthur Miller, Dmitry Gutov, Göktuğ Kayaalp,
	Emacs developers, Drew Adams

Hi.

On Tue, Sep 15, 2020 at 6:06 PM Ergus via Emacs development
discussions. <emacs-devel@gnu.org> wrote:
> On September 15, 2020 10:33:51 PM GMT+02:00, Drew Adams <drew.adams@oracle.com> wrote:
> >> > read `Mouse Commands' if you haven't
> >> > already, and give it a try.
> >>
> >> Mouse support is poor in Emacs, this is the reason
> >> why I don't use the mouse in Emacs.
> >
> >I disagree that mouse support is poor in Emacs.
> >
> So you are the only one I know so far with that opinion.
>
> >I use a mouse in several other applications much
> >of the workday, and Emacs mouse support is superior
> >in every respect I'm aware of.  But I'm no expert
> >on the use of mice.  And perhaps the mouse support
> >in the apps I use is not a reference.
> >
> This is the same problem than undo-redo. Maybe the features are actually better technically speaking or to whom knows all the tricks and trains himself for years; but it worth nothing if the users feel uncomfortable or don't values some of the details that justify complexity in others. (Like hiding the context panel with a control or not having a redo button or not deleting the selection) Or just don't need them.

Technically better is a pretty big deal.  Especially when the specific
technical advancement is massive-overkill levels of user-facing
configuration and even more when the subject at hand is how best to
get said technology to users.  (And, to wit, those users' needs are
varied so as to drive us to this type of sophistication/complexity.)

> There are some "standards" in mouse interaction determined/imposed by most of the gui programing interfaces from visual studio or java to qt5 and gtk. The developers of all the aplications have been following them for years and most of the user are used to them.

This isn't really different from veteran coders who have troubled to
become familiar with lots of Emacs bindings, or really any system
expert.  I acknowledge the utility of having Emacs' default bindings
be simple and obvious to new users.   I think that should be weighed
carefully when pitted directly thoughtful existing
practice/behaviours/defaults.  Echoing what Drew said, above: What we
already have may be superior to other more common practices.

> So this is the "dilema". Or we change a bit (1 binding) to ease the user experience and learning curve OR we expect that all the potential users change their expectations, trainings and don't go to any other editor but use emacs because we pretend we offer a better functionality that they are not aware of and most probably don't need or never learn/use because is complex to remember.

I think the "learning curve" is core to the value proposition of
Emacs:  if we invest the time, we are told, Emacs will overall reduce
the efforts associated to our labors.  There is a balance to be struck
here: new users need to under enough of the machine to begin
configuring it.  Meanwhile, complexities hidden for ease of newcomers
need to remain accessible to users who may be Emacs veterans but not
elisp coders.

Neither new nor old Emacs users will thank us for saving them a
learning curve that costs efficiencies in our work-flows and I think
most of us will learn (and relearn) as needed when the carrot is
general efficiencies when writing, etc.   I think it's the "trainings"
you mention that are the biggest opportunity.

> >> > Double-click (`mouse-1') on a word, then click
> >> > `mouse-3' on another word. The selection picks up
> >> > whole words, from the first through the last you
> >> > clicked.
> >>
> >> In other apps, the same is achieved by double-click
> >> (`mouse-1') on a word, then double-click the same
> >> (`mouse-1') on another word while holding down the Shift key.
> >
> >And that's better why?  Having to use both the
> >keyboard and the mouse?
> >
> Usually the other hand is already in the keyboard and close to a shift. Comparing, our approach of moving the mouse to the toolbar to copy after the selection is probably less efficient than anything else or the fact that M-w and C-y dont share any key like C-c/C-v or that we need the two hand to undo instead of C-z. All these are less efficient too but we are used to them.

I've been thinking about this.  Those who play lots of computer games
may know of an alternate position for the left hand   (Ring finger
slides left onto "A", pinky slides down over the "modern" location of
Control, etc.)  For those who know this position, our left-hands are
pretty comfortable sliding around while we're mousing.  It's almost
another sort of touch-typing - I can stretch over and without looking
hit the Eight key on the number-row with my left index finger pretty
consistently.    In any case, my point is that the diversity of
use-cases continues to multiply however the value proposition Emacs is
only strengthened:  An editor I can configure, based on my own ever
more unique behaviors, to access functionality representing decades of
programers' workflows.

> >> > Triple-click a line, then click `mouse-3' on
> >> > another line.  The selection picks up whole lines.
> >>
> >> In other apps, triple-click a line, then again triple-click
> >> on another line while holding down the Shift key.
> >
> >Both keyboard and mouse again.  Better?  Not IMO.
> >
> But just the same button-1 so yes, probably simpler to remember and intuitive for any office (or other modern editor) user.

> Simple is better than complex.
> Complex is better than complicated.

I think I don't understand: I would say a simple solution I can
remember beats a better solution I've forgotten because it is too
unfamiliar or complex.  But only until I understand how to get "on the
fly help".  The better solution is better for me given only that I
understand and actually do use it.

> The emacs approach with mouse is indeed complicated.

Then it needs better training!  A seperate tutorial?  RMS mentioned a
key-binding memorization game awhile back- maybe a "mouse-trainer"
something like?

In any case, thank you (all) for the work you are doing to help make
Emacs more accessible to new users.  I turn a lot of people on to
Emacs and I'm looking forward to the help I expect this will be for
them.

> >We could provide a keyboard + mouse combination
> >for such use cases if that were a common need.
> >
> >> Also in other apps Shift+F10 opens the context menu,
> >> but why not in Emacs?
> >
> >That's orthogonal.  Nothing prevents also having
> >a keyboard key sequence to open a context menu.
> >(Presumably the "location" it refers to would
> >be point.)
> >
> There is the <print> key which many applications use to show the panel from keyboard too.

There is also <apps> (right of the "right-Flag" key, for me).   In OS
context this opens a context window considering the active selection
if any.

According to ~~C-h k~~ it is unbound:

 | user-error: No command is bound to <apps>

I think people come to Emacs expecting (bracing themselves) to learn.
 We need to do a better job of capitalizing on that by welcoming
people with accessible bite-sized introductory material at least as
much as we need to make the "factory defaults" for Emacs sufficient
for people to make it though such materials.  (I'm referencing
on-going topics such as the first-run configuration wizard,
minor-mode/theme, etc. discussed on other threads.  Apart from the
"mouse trainer" I not sure what else to suggest, specifically.)

> >The impetus for this discussion was expectations
> >of new users to get a context menu on `mouse-3'.
> >(But newbies are not the only reason for such a
> >feature.)
> >
> >> > [I'd like to see the double-clicking extended, so
> >> > that if you double-click a paren in Lisp it picks
> >> > up the full sexp, and if you then `mouse-3' another
> >> > sexp it picks up full sexps in the interval.  But
> >> > this is a bit trickier.]
> >>
> >> It would be easier to use this as: double-click a paren to select
> >> a sexp, then double-click another paren to select another sexp
> >> while holding down the Shift key.
> >
> >Another keyboard + mouse mix.
> >
> >[What I described already works for simple cases, BTW.
> >E.g. double-click a paren in Lisp (open or close),
> >then `mouse-3' another paren, to select up the lists
> >and intervening sexps.]

The first message in this thread (Mouse Commands, plugging the manual,
etc.) has meaningfully changed my workflow.  In fact, I was playing
with the feature described above last night.   Double click the
closing paren of a defun.  Now Mouse-3 after the following defun.
Finally, mouse-3 a second time in the same place (that is, right after
the second defun).

*Yoink*

This seems great for refactoring, ie. making little ones out of big
ones.  Took me very little getting used to.

> --
> Sent from my Android device with K-9 Mail. Please excuse my brevity.
>

PS, can we rename "yank" to "yoink"?  No?  Okay.

Regards,
Corwin



^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-15 22:47         ` Ergus via Emacs development discussions.
  2020-09-16  0:29           ` Corwin Brust
@ 2020-09-16  1:25           ` Drew Adams
  2020-09-16  8:10             ` Ergus
  2020-09-17  3:51             ` Richard Stallman
  2020-09-16 14:13           ` Eli Zaretskii
  2 siblings, 2 replies; 112+ messages in thread
From: Drew Adams @ 2020-09-16  1:25 UTC (permalink / raw)
  To: Ergus, emacs-devel, Juri Linkov
  Cc: philipk, Richard Stallman, Gregory Heytings, Arthur Miller,
	Dmitry Gutov, Göktuğ Kayaalp

You're all over the map, Ergus, arguing abstractly, not
to the point - bringing in undo-redo; newbie-vs-better
behavior; hiding the context menu behind C-mouse-3,
which also doesn't work in a terminal (mouse3.el uses
mouse-3); "moving the mouse to the toolbar to copy after
the selection" (huh? what's that about?); "M-w and C-y
dont share any key like C-c/C-v"; "we need the two hand
to undo instead of C-z" (two hands to undo?);...

Again:

>> The impetus for this discussion was expectations
>> of new users to get a context menu on `mouse-3'.
>> (But newbies are not the only reason for such a
>> feature.)

A context menu is useful for discoverability, including
by seasoned Emacs users (we are all discovering some
parts of Emacs).  It should be easily configurable by
program and by users, adaptable for any mode or other
context.  `mouse-3' is a good place for it, and not
only because that's where newbies expect it.

Emacs mouse selection, including extension & deletion,
are also useful.  Both this and a `mouse-3' menu are
possible, with no sacrifice.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-16  0:29           ` Corwin Brust
@ 2020-09-16  1:47             ` Drew Adams
  0 siblings, 0 replies; 112+ messages in thread
From: Drew Adams @ 2020-09-16  1:47 UTC (permalink / raw)
  To: Corwin Brust, Ergus
  Cc: philipk, Richard Stallman, Juri Linkov, Gregory Heytings,
	Arthur Miller, Dmitry Gutov, Göktuğ Kayaalp,
	Emacs developers

> The first message in this thread (Mouse Commands, plugging the manual,
> etc.) has meaningfully changed my workflow.  In fact, I was playing
> with the feature described above last night.   Double click the
> closing paren of a defun.  Now Mouse-3 after the following defun.
> Finally, mouse-3 a second time in the same place (that is, right after
> the second defun).
> 
> *Yoink*

<selection is killed>

And with mouse3.el, by default you'd double-click there,
instead of a slower-than-double-click second click there.

Or the reverse (not the default), if that's what you prefer.

Either way, the other (slow-2nd by default, or double by
option) shows you a context menu.  (And the menu includes
`Kill' and `Delete', if your double-vs-second fu misses.)

> This seems great for refactoring, ie. making little ones out of big
> ones.  Took me very little getting used to.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-15 19:17     ` Juri Linkov
  2020-09-15 20:33       ` Drew Adams
@ 2020-09-16  2:24       ` Eli Zaretskii
  2020-09-16 19:35         ` Juri Linkov
  1 sibling, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2020-09-16  2:24 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, rms, spacibba, emacs-devel, self, arthur.miller, dgutov,
	ghe, drew.adams

> From: Juri Linkov <juri@linkov.net>
> Date: Tue, 15 Sep 2020 22:17:24 +0300
> Cc: philipk@posteo.net, Richard Stallman <rms@gnu.org>,
>  Ergus <spacibba@aol.com>, emacs-devel@gnu.org, Gregory Heytings <ghe@sdf.org>,
>  Arthur Miller <arthur.miller@live.com>, Dmitry Gutov <dgutov@yandex.ru>,
>  Göktuğ Kayaalp <self@gkayaalp.com>
> 
> Mouse support is poor in Emacs, this is the reason
> why I don't use the mouse in Emacs.  More below:

"Poor"? the below just says that other applications (which ones?) do
it slightly differently, that's all.  I don't see how what you say
justifies the "poor" part.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
@ 2020-09-16  6:28 Tak Kunihiro
  2020-09-16 14:18 ` Eli Zaretskii
  2020-09-16 19:45 ` Juri Linkov
  0 siblings, 2 replies; 112+ messages in thread
From: Tak Kunihiro @ 2020-09-16  6:28 UTC (permalink / raw)
  To: emacs-devel; +Cc: Juri Linkov

[-- Attachment #1: Type: text/plain, Size: 686 bytes --]

> Mouse support is poor in Emacs, this is the reason
> why I don't use the mouse in Emacs.

I have an impression that relative to Emacs's capability, mouse support
is not as good as expected.

- Horizontal scroll by wheel is supported.
- Moving text using mouse is supported.
* Contextual menu is not supported yet.

I think that depending on a thing at mouse event (file, dir, or URL),
choice of operation should be popped up.  When there is no suggestion,
`Edit' menu should be popped up.  Also, by click on mode-line, buffer
list should be popped up.

I am using a global minor mode `poplife-mode' that puts commands on
mouse-3.  I attach a file with poplife-mode to show the idea.


[-- Attachment #2: poplife.el --]
[-- Type: application/octet-stream, Size: 62640 bytes --]

;;; poplife.el --- Pop choices up on mouse click

;; Copyright (C) 2017-2020 Tak Kunihiro

;; Author: Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>
;; Package-Requires: ((emacs "24.4"))
;; Keywords: mouse
;; Version: 1.0
;; Package-Version: 20200916.1451

;; This file is NOT part of GNU Emacs.

;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;; Usage:
;;
;; To interactively toggle the mode:
;;
;;   M-x poplife-mode RET
;;
;; To make the mode permanent, put these in your init file:
;;
;;   (require 'poplife)
;;   (poplife-mode 1)

;;; Commentary:
;;
;; This package pops context menu triggered by right click.  On a
;; click, depending on a thing under the mouse event, (1) FILE menu
;; (2) DIR menu, (3) WORD menu, (4) URL menu, (5) INFO menu, (6) HELP
;; menu, or (7) EDIT menu will be popped.  The EDIT menu lets you copy
;; and paste only using mouse.  As an option, the EDIT menu lets you
;; visit buffers, frames, bookmarks, and files.  The seven menus
;; are detailed as below.
;;
;; (1) FILE menu -- Pop how-to-open-a-file menu.
;; (2) DIR menu  -- Pop files in default-directory.
;; (3) WORD menu -- Pop word candidates when word under a mouse event is not correct.
;; (4) URL menu  -- Pop how-to-open-an-url menu.
;; (5) INFO menu -- Pop how-to-open-Info menu.
;; (6) HELP menu -- Pop how-to-open-Help menu.
;; (7) EDIT menu -- Pop basic edition-commands, optional edition-commands,
;;                  and visiting menus.  Details are shown below.
;;
;;  Basic edition-commands are defined by `poplife-mouse-edit-cmd-0'.
;;  Optional edition-commands are defined by
;;  `poplife-mouse-edit-cmd-1'.  with format similar to
;;  `recentf-menu-items-for-commands'.
;;
;;  DIR menu to visit files in default-directory is included by
;;  default.  To include a series of visiting menus, set each item of
;;  `poplife-mouse-edit-cottager' to non-nil, as listed below.
;;
;;   :buffer     List buffers by `global-buffers-menu-map'.
;;   :imenu      List table of contents of current buffer by iMenu.
;;   :frame      List frames by `global-buffers-menu-map'.
;;   :bookmark   List bookmarks by `bookmark-all-names'.
;;   :recentf    List recent files by `recentf-menu-elements'.
;;
;;  To reduce overhead, FILE menu is not shown when file-remote-p is
;;  non-nil.  To reduce overhead by a remote file that was once opened
;;  by Tramp and stored in the list for recentf, configure a variable
;;  `recentf-exclude'.

;;; References:

;; * Paste text with erasing active region.
;;
;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2017-07/msg00086.html
;; http://lists.gnu.org/archive/html/emacs-devel/2017-07/msg00796.html
;;
;; * Pop menu up by long-click
;;
;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00267.html
;;
;; * Following codes from Emacs core are useful for development.
;;
;; (define-key global-map [mouse-3] menu-bar-edit-menu)
;; (popup-menu menu-bar-edit-menu)
;; (popup-menu (mouse-menu-bar-map))
;; (popup-menu (mouse-menu-major-mode-map)) ; C-mouse-3
;; (popup-menu menu-bar-bookmark-map)
;; (popup-menu global-buffers-menu-map)
;; (define-key global-map [mouse-3] 'mouse-buffer-menu)
;; (buffer-menu-open)

;;; Templates of keymap:
;;
;; This package integrates keymaps from imenu, menu-bar, bookmark, and
;; recentf.  They are converted to easymenu from standard keymap.
;; Typical easymenu and standard keymap are shown below for
;; convenience.
;;
;; (label
;;  [label callback]
;;  (label
;;   [label callback]
;;   ["--"  ignore]
;;   [label callback])
;;  [label callback])
;;
;; (keymap
;;  label
;;  (symbol menu-item label callback)
;;  [(label lambda nil (interactive) commands)
;;   (label keymap
;;          (symbol menu-item label callback)
;;          (symbol menu-item label callback))
;;   (label lambda nil (interactive) commands)]
;;  (symbol "--")
;;  (symbol menu-item label
;;          (keymap label
;;                  (symbol menu-item label callback)
;;                  (symbol menu-item label callback)))
;;  (symbol menu-item label callback))

;;; Code:
(defvar poplife-context-candidates
  '(poplife-mouse-help-menu             ; HELP menu
    poplife-mouse-info-menu             ; INFO menu
    poplife-mouse-file-menu             ; FILE menu
    poplife-mouse-dir-menu              ; DIR menu
    poplife-mouse-word-menu             ; WORD menu
    poplife-mouse-url-menu              ; URL menu
    ;; menu-bar-edit-menu    ; EDIT menu (default)
    poplife-mouse-edit-menu)            ; EDIT menu
  "List of candidates for context menu.
Candidates are function or keymap.  They will be evaluated in the
order of the list.  A function should accept mouse EVENT, and
return keymap or nil.  The last candidate should return valid
keymap.")

(defvar poplife-mouse-edit-cmd-0 '(cut copy paste select-paste paste-from-menu clear mark-whole-buffer)
  "Basic edition-commands in edit menu.
Items must be one listed in `menu-bar-edit-menu'.")

(defvar poplife-mouse-edit-cmd-1
  (list
   ["Close"
    (lambda () (interactive)
      (if (one-window-p)
          (if (> (length (visible-frame-list)) 1)
              (call-interactively 'delete-frame)
            (kill-buffer (window-buffer))) ; (quit-window)
        (delete-window)))
    :help "Remove this window or this frame, or kill this buffer"
    :visible (not (region-active-p))
    :active t]
   ;; ["Spell-Check"
   ;;  flyspell-correct-word-before-point
   ;;  :help "Spell check word at point"
   ;;  :visible (and (fboundp 'flyspell-correct-word-before-point)
   ;;                (not (region-active-p)))
   ;;  :active t]
   ["Spell-Check"
    ispell-region
    :help "Spell check selected text"
    :visible (region-active-p)
    :active t]
   ;; ["Search Web"
   ;;  (lambda () (interactive)
   ;;    (let ((keyword (buffer-substring-no-properties (region-beginning) (region-end))))
   ;;      (switch-to-buffer-other-window (generate-new-buffer "*eww*"))
   ;;      (eww-mode)
   ;;      (eww keyword)))
   ;;  :help "Search selected text by online service"
   ;;  :visible (region-active-p)
   ;;  :active t]
   ["--"
    ignore
    :visible (region-active-p)
    :active t])
  "List of optional commands in edit map.") ; recentf-menu-items-for-commands

(defvar poplife-mouse-edit-cottager
  '(:imenu t :buffer t :frame t :bookmark t :recentf t)
  "Extra menus to be included in edit menu besides file.")
\f
(defvar poplife-file-max-menu-items 20
  "Maximum number of items in DIR menu.
See also `recentf-max-menu-items', `buffers-menu-max-size', and
`imenu-max-items'.")

(defvar poplife-file-recursive 1
  "Depth of directory scan on DIR menu.")

(defvar poplife-dir-do-not-scan-regexp "inbox"
  "Contents of directory matching this regexp will not be shown in DIR menu.
Instead contents of home directory are displayed.")

(defvar poplife-file-do-not-show-regexp
  "\\`\\.\\.?$\\|\\`#\\|\\.elc\\'\\|\\.exe\\'\\|\\`\\.[^e]\\|\\.lnk\\'\\|\\~\\'\\|\\`desktop\\.ini\\'\\|\\`\\.DS_store\\'\\|\\`\\.dropbox\\'\\|\\`auto\\'\\|\\`ntuser\\|\\`_master_\\|\\`_region_\\|\\.aux\\'\\|\\.bbl\\'\\|\\.blg\\'\\|\\.fdb_latexmk\\'\\|\\.fls\\'\\|\\.lof\\'\\|\\.lot\\'\\|\\.out\\'\\|\\.toc\\'\\|\\.synctex\\'\\|\\.ico\\'\\|\\`Thumbs\\.db\\'\\|\\`Icon"
  "Filenames matching this regexp will not be displayed in DIR menu.") ; dired-trivial-filenames, dired-omit-files

(defvar poplife-file-do-not-open-regexp
  "\\.pdf\\'\\|\\.doc\\'\\|\\.docx\\'\\|\\.xls\\'\\|\\.xlsx\\'\\|\\.ppt\\'\\|\\.pptx\\'\\|\\.jpg\\'\\|\\.png\\'\\|\\.tif\\'\\|\\.tiff\\'\\|\\.bmp\\'\\|\\.aif\\'\\|\\.wav\\'\\|\\.7z\\'\\|\\.tar\\'\\|\\.dll\\'\\|\\.zip\\'\\|\\.info\\'\\|\\.igpi\\'\\|\\.ttf\\'\\|\\.otf\\'\\|\\.pkg\\'\\|\\.exe\\'"
  "Filenames matching this regexp will be displayed in DIR menu and open by `poplife-func-find-file-by-default-app'.")

(defvar poplife-func-find-file 'find-file
  "Function to visit a file, and a Recentf element.
Depending on context, this is internally overwritten by
`find-file', `find-file-other-window', and
`find-file-other-frame'.  This is referred to visit a buffer, an
imenu element, and a bookmark element via
`poplife-func-switch-to-buffer'.  A buffer is visited by
`menu-bar-select-buffer-function' on `global-buffers-menu-map'.
An imenu element is always visited on current buffer.  A bookmark
element is visited by `display-func' on `bookmark-jump'.")

(defvar poplife-func-find-file-by-default-app 'poplife-find-file-by-default-app
  "Function to visit file by default application.")
\f
(require 'ffap)
(require 'easymenu)

;;;###autoload
(define-minor-mode poplife-mode
  "A global minor-mode to show context menu by right click."
  :init-value nil
  :group 'mouse
  :global t
  :keymap (let ((map (make-sparse-keymap))
                (context-menu
                 `(menu-item "Context menu" poplife-context-menu
                             :filter ,(lambda (_) (poplife-context-menu (aref (this-command-keys) 0))))))
            ;; bug#27569 (gnus-read-ephemeral-emacs-bug-group 27569)
            ;; https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-07/msg00086.html
            ;; https://lists.gnu.org/archive/html/emacs-devel/2017-07/msg00757.html
            ;; https://lists.gnu.org/archive/html/emacs-devel/2017-07/msg00796.html
            ;; https://lists.gnu.org/archive/html/emacs-devel/2017-07/msg00840.html
            (define-key map [mouse-3] context-menu)
            (define-key map [drag-mouse-3] context-menu)
            (define-key map [C-down-mouse-1] #'ignore)
            (define-key map [C-mouse-1] context-menu)
            (define-key map [C-double-mouse-1] context-menu)
            (define-key map [C-triple-mouse-1] context-menu)
            (define-key map [C-drag-mouse-1] context-menu)
            (define-key map [remap buffer-menu-open] #'poplife-menu-open)
            ;; (define-key map [C-S-down-mouse-1] 'mouse-buffer-menu)
            ;; (define-key map [C-M-mouse-1] 'poplife-what-mouse-position)
            ;; (define-key mode-line-buffer-identification-keymap [mode-line mouse-3] #'poplife-pwd-menu-open)
            ;; (define-key mode-line-buffer-identification-keymap [mode-line mouse-1] #'poplife-buffer-menu-open)
            (define-key map [remap mode-line-previous-buffer] #'poplife-buffer-menu-open) ; mouse-1
            ;; (define-key map [remap mode-line-previous-buffer] #'poplife-global-mark-ring-menu-open) ; mouse-1
            (define-key map [remap mode-line-next-buffer] #'poplife-pwd-menu-open) ; mouse-3
            (define-key map [mode-line C-mouse-1] #'poplife-pwd-menu-open)
            (define-key map [mode-line M-mouse-1] #'poplife-pwd-menu-open) ; as if Mac
            map))

;; * How to implement into core
;;
;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00416.html

;; (defvar mouse-context-menu-function #'mouse-default-context-menu
;;   "Function that builds the context-menu.
;; Takes one argument (the EVENT that requests the menu) and should return
;; a list of menu items.")

;; (defun mouse-default-context-menu (event)
;;   "Return default context menu."
;;   (interactive "e")
;;   menu-bar-edit-menu)

;; (defun mouse-context-menu (event)
;;   "Open up the context menu."
;;   (interactive "@e")
;;   (let* ((menu-items (funcall mouse-context-menu-function event))
;;          (keymap `(keymap ,(apply #'vector menu-items))))
;;     (popup-menu keymap event)))

;; (define-key global-map [mouse-3] 'mouse-context-menu)

(defun poplife-menu-open ()
  "Start key navigation of the poplife menu.
This is the keyboard interface to \\[poplife-context-menu].  This is
fork of `buffer-menu-open'."
  (interactive)
  (popup-menu (poplife-context-menu last-nonmenu-event)
              (posn-at-x-y 0 0 nil t)))

(defun poplife-context-menu (event)
  "Return key's definition depending on thing at mouse click EVENT.
Items in `poplife-context-candidates' are examined sequentially.
See `define-key' for the key's definition"
  ;; ~/.emacs.d/init.el ~/.emacs.d/ https://www.gnu.org/software/emacs/
  (when (fboundp 'secondary-selection-to-region) ; 26.1
    (secondary-selection-to-region)) ; When there is only secondary, turn it to region.
  (let ((candidates poplife-context-candidates)
        context-menu)
    (while (not context-menu)
      (let ((item (car candidates)))
        (setq candidates (cdr candidates))
        ;; See how dired-guess-shell-alist-user is used in dired-guess-default.
        (setq context-menu (cond ((fboundp item)
                                  (funcall item event))
                                 ((and (symbolp item)
                                       (keymapp (symbol-value item)))
                                  (symbol-value item))
                                 (t     ; else
                                  nil)))))
    context-menu))
;; (let ((foo (poplife-context-menu last-nonmenu-event))) (describe-variable 'foo))

(defun poplife-what-mouse-position (event)
  "Evaluate text properties under mouse click."
  (interactive "e")
  (with-output-to-temp-buffer "*Result*"
    (princ (format "Event was %S\n" event))
    (princ (format "Click was on face <%S>.\n"
                   (mouse-posn-property (event-start event) 'face)))
    (princ (format "Click was on dired-filename <%S>.\n"
                   (mouse-posn-property (event-start event) 'dired-filename)))))

(with-eval-after-load "help-mode"
  (button-type-put 'help-function-def 'help-function 'poplife-help-find-function))

(defvar poplife-help-switch-buffer-function 'pop-to-buffer
  "Function to display buffer in help-mode.
This can be `switch-to-buffer', `switch-to-buffer-other-window',
or `switch-to-buffer-other-frame'.")

(defun poplife-help-find-function (fun &optional file type)
  "Find object shown in help-mode."
  ;; This is fork of lambda function of 'help-function, that is
  ;; defined for a button type 'help-function-def in `help-mode.el'.
  (or file
      (setq file (find-lisp-object-file-name fun type)))
  (if (not file)
      (message "Unable to find defining file")
    (require 'find-func)
    (when (eq file 'C-source)
      (setq file
            (help-C-file-name (indirect-function fun) 'fun)))
    ;; Don't use find-function-noselect because it follows
    ;; aliases (which fails for built-in functions).
    (let ((location
           (find-function-search-for-symbol fun type file)))
      ;; (pop-to-buffer (car location))
      (funcall poplife-help-switch-buffer-function (car location)) ; Revised for poplife
      (run-hooks 'find-function-after-hook)
      (if (cdr location)
          (goto-char (cdr location))
        (message "Unable to find location in file")))))

(defun poplife-mouse-help-menu (event)
  "Return help-menu when thing at mouse click EVENT is button
with button type of 'help-function-def."
  (and
   (not (region-active-p))
   (let ((help-easymap
          (save-excursion
            (mouse-set-point event)
            ;; (text-properties-at (point))
            ;; '(push-button "/Applications/MacPorts/Emacs.app/Contents/Resources/lisp/button.el")
            ;; (push-button (point))
            ;; (help-button-action (button-at (point)))
            ;; (help-do-xref nil
            ;;   	(button-get (button-at (point)) 'help-function)
            ;;   	(button-get (button-at (point)) 'help-args))
            ;; (button-type (button-at (point)))
            (let ((button (button-at (point))))
              (when (and button
                         (eq (button-type button) 'help-function-def))
                (let* ((button-func (button-get button 'help-function))
                       (button-arg  (button-get button 'help-args))
                       (message (replace-regexp-in-string "[()\"]" "" (format "%S" button-arg) t t)))
                  (list
                   message
                   (vector "Open Function"
                           `(let* ((poplife-func-find-file 'find-file) ; switch-to-buffer
                                   (poplife-help-switch-buffer-function (poplife-func-switch-to-buffer)))
                              (help-button-action ,button))
                           :visible t :active t :help message)
                   ["--" ignore]
                   (vector "Open Function in Other Window"
                           `(let* ((poplife-func-find-file 'find-file-other-window) ; switch-to-buffer-other-window
                                   (poplife-help-switch-buffer-function (poplife-func-switch-to-buffer)))
                              (help-button-action ,button))
                           :visible t :active t :help message)
                   (vector "Open Function in Frame"
                           `(let* ((poplife-func-find-file 'find-file-other-frame) ; switch-to-buffer-other-frame
                                   (poplife-help-switch-buffer-function (poplife-func-switch-to-buffer)))
                              (help-button-action ,button))
                           :visible t :active t :help message))))))))
     (when help-easymap
       (easy-menu-create-menu (car help-easymap) (cdr help-easymap))))))
;; (poplife-mouse-help-menu last-nonmenu-event)

(defun poplife-info-node-at-point ()
  "Return a node reference at point.
Return non-nil if successful.  This is fork of
`Info-try-follow-nearest-node'."
  (let (file-or-node)
    (cond
     ((setq file-or-node (Info-get-token (point) "[hf]t?tps?://"
				                 "\\([hf]t?tps?://[^ \t\n\"`‘({<>})’']+\\)"))
      ;; (browse-url file-or-node)
      (setq file-or-node nil))
     ((setq file-or-node (Info-get-token (point) "\\*note[ \n\t]+"
				                 "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?"))) ; (system)Data format IONML
     ;; footnote
     ((setq file-or-node (Info-get-token (point) "(" "\\(([0-9]+)\\)"))
      (setq file-or-node nil))
     ;; menu item: node name
     ((setq file-or-node (Info-get-token (point) "\\* +" "\\* +\\([^:]*\\)::"))) ; What is DREAM?
     ;; menu item: node name or index entry
     ((Info-get-token (point) "\\* +" "\\* +\\(.*\\): ") ; FAQ
      (save-excursion
        (beginning-of-line)
        (forward-char 2)
        (setq file-or-node (Info-extract-menu-node-name nil (Info-index-node))))) ; (pmlfaq)
     ((setq file-or-node (Info-get-token (point) "File: " "File: \\([^,\n\t]*\\)")) ; pmlfaq.info
      (when (string-match "\\.info\\'" file-or-node)
        (string-match "\\`\\(.+\\)\\.info\\'" file-or-node) ; pmlfaq
        (setq file-or-node (format "(%s) Top" (match-string 1 file-or-node)))))) ; (pmlfaq) Top
    (when (and file-or-node
               (stringp Info-current-file)
               (not (string-match "\\`(.*)" file-or-node)))
      (setq file-or-node
            (format "(%s) %s"
                    (file-name-sans-extension
                     (file-name-nondirectory Info-current-file))
                    file-or-node))) ; see Info-copy-current-node-name
    file-or-node))

(defun poplife-mouse-info-menu (event)
  "Return info-menu when thing at mouse click EVENT is link."
  ;; see Info-try-follow-nearest-node
  (and
   (not (region-active-p))
   (let ((info-easymap
          (save-excursion
            (mouse-set-point event)
            (let ((file-or-node (poplife-info-node-at-point)))
              (when file-or-node
                (list
                 file-or-node
                 (vector "Open Info"
                         ;; `(info ,file-or-node)
                         `(info-setup
                           ,file-or-node
                           (switch-to-buffer (format "*info-%s*" ,file-or-node)))
                         :visible t :active t :help file-or-node)
                 ["--" ignore]
                 (vector "Copy Info"
                         `(progn (kill-new ,file-or-node) (message ,file-or-node))
                         :visible t :active t :help file-or-node)
                 (vector "Open Info in Other Window"
                         `(info-setup
                           ,file-or-node
                           (switch-to-buffer-other-window (format "*info-%s*" ,file-or-node)))
                         :visible t :active t :help file-or-node)
                 (vector "Open Info in Frame"
                         `(info-setup
                           ,file-or-node
                           (switch-to-buffer-other-frame (format "*info-%s*" ,file-or-node)))
                         :visible t :active t :help file-or-node)))))))
     (when info-easymap
       (easy-menu-create-menu (car info-easymap) (cdr info-easymap))))))
;; (let ((foo (poplife-mouse-info-menu last-nonmenu-event))) (describe-variable 'foo))
;; (popup-menu (poplife-mouse-info-menu last-nonmenu-event))

(defun poplife-mouse-file-menu (event)
  "Return file-menu when thing at mouse click EVENT is file.
The file is identified by `ffap-guesser'."
  (and
   (not (region-active-p))
   (let ((file-easymap
          (save-excursion
            (mouse-set-point event)
            (if (equal major-mode 'dired-mode)
                (and
                 (mouse-posn-property (event-start event) 'dired-filename)
                 (poplife-file-easymap (dired-get-file-for-visit) t))
              (let ((file (ffap-guesser))) ; ffap-at-mouse
                ;; ~/.emacs.d/init.el  ~/.emacs.d/  https://www.gnu.org/software/emacs/
                ;; ffap-guesser cannot guess file with asterisk such as "bookmark.html*"
                (when (and file
                           (not (ffap-file-remote-p file)))
                  (poplife-file-easymap file t)))))))
     (when file-easymap
       (easy-menu-create-menu (car file-easymap) (cdr file-easymap))))))

(defun poplife-mouse-dir-menu (event)
  "Return dir-menu when thing under mouse cursor on EVENT is directory.
The directory is identified by `ffap-guesser'."
  (and
   (not (region-active-p))
   (if (equal major-mode 'dired-mode)
       (mouse-posn-property (event-start event) 'dired-filename)
     t)
   (let ((dir-easymap (save-excursion
                        (mouse-set-point event)
                        ;; ~/.emacs.d/init.el  ~/.emacs.d/  https://www.gnu.org/software/emacs/
                        (let ((dir (ffap-guesser)))
                          (when (and dir
                                     (not (ffap-file-remote-p dir)))
                            (poplife-dir-easymap (file-name-as-directory dir) t))))))
     (when dir-easymap
       (easy-menu-create-menu (car dir-easymap) (cdr dir-easymap))))))

(defun poplife-mouse-word-menu (event)
  "Return 'flyspell-correct-word when word under mouse cursor on EVENT is incorrect."
  (and
   (not (region-active-p))
   ;; Check face by (what-cursor-position t) or C-u C-x =.
   (let ((faces-at-point (mapcar (lambda (xxx) (overlay-get xxx 'face))
                                 (overlays-at (posn-point (event-start event))))))
     (when (or (member 'flyspell-incorrect faces-at-point)
               (member 'flyspell-duplicate faces-at-point))
       #'flyspell-correct-word)))) ; flyspell-correct-word-before-point

(defun poplife-mouse-url-menu (event)
  "Return url-menu when thing under mouse cursor on EVENT is url.
The url is identified by `thing-at-point-url-at-point'."
  (and
   (not (region-active-p))
   (let ((url-easymap
          (save-excursion
            (mouse-set-point event)
            ;; ~/.emacs.d/init.el  ~/.emacs.d/  https://www.gnu.org/software/emacs/
            (let ((url (or (thing-at-point-url-at-point t) ; browse-url-at-mouse
                           (get-text-property (point) 'shr-url)
                           (get-text-property (point) 'image-url))))
              (when url
                (list (let ((url (replace-regexp-in-string "https?://" "" url))
                            (len 40)) ; Make URL short
                        (if (> (length url) len)
                            (concat (substring url 0 (1- len)) "...")
                          url))
                      (vector "Open Link"
                              `(eww ,url)
                              :visible t :active t :help url)
                      ["--" ignore]
                      (vector "Copy Link"
                              `(progn (kill-new ,url) (message "Copied %s" ,url))
                              :visible t :active t :help url)
                      (vector "Open Link in Other Window"
                              ;; eww-browse-url, eww-open-in-new-buffer
                              `(progn
                                 (switch-to-buffer-other-window (generate-new-buffer "*eww*"))
                                 (eww-mode)
                                 (eww ,url))
                              :visible t :active t :help url)
                      (vector "Open Link in Frame" ; "Open in Frame"
                              `(progn
                                 (switch-to-buffer-other-frame (generate-new-buffer "*eww*"))
                                 (eww-mode)
                                 (eww ,url))
                              :visible t :active t :help url)
                      (vector "Open Link by Default App" ; "Open Link using browse-url"
                              `(let ((browse-url-browser-function 'browse-url-default-browser))
                                 (browse-url ,url))
                              :visible t
                              :active t
                              :help url)))))))
     (when url-easymap
       (easy-menu-create-menu (car url-easymap) (cdr url-easymap))))))

(defun poplife-mouse-edit-menu (event)
  "Define edit menu on mouse click EVENT."
  ;; initialize
  (when (plist-get poplife-mouse-edit-cottager :bookmark)
    (require 'bookmark))
  (when (plist-get poplife-mouse-edit-cottager :recentf)
    (require 'recentf)
    (recentf-mode 1))
  (when (plist-get poplife-mouse-edit-cottager :imenu)
    (require 'imenu))

  (save-excursion
    (mouse-set-point event)
    (let ((map (make-sparse-keymap "Edit")))
      (unless (region-active-p)
        ;; Visit buffers with iMenu
        (when (plist-get poplife-mouse-edit-cottager :buffer)
          (easy-menu-add-item map nil (poplife-buffer-easymap)))

        ;; Visit frames
        (when (plist-get poplife-mouse-edit-cottager :frame)
          (easy-menu-add-item map nil (poplife-frame-easymap)))

        ;; Visit bookmarks
        (when (plist-get poplife-mouse-edit-cottager :bookmark)
          (easy-menu-add-item map nil (poplife-bookmark-easymap)))

        ;; Visit recent files
        (when (plist-get poplife-mouse-edit-cottager :recentf)
          (easy-menu-add-item map nil (poplife-recentf-easymap)))

        ;; Visit directory
        (unless (file-remote-p default-directory)
          (let ((dir-map (poplife-dir-easymap default-directory)))
            (setcar dir-map "File")      ; instead of ".emacs.d/"
            (easy-menu-add-item map nil dir-map)))

        ;; Separator
        (define-key map [separator-edit] menu-bar-separator))

      ;; Option -- TODO: Fix location of item with recursive structure.
      (when poplife-mouse-edit-cmd-1
        (dolist (item poplife-mouse-edit-cmd-1)
          (if (vectorp item)
              (let* ((item (append item nil)) ; Convert vector to list.
                     (nickname (car item)))
                (bindings--define-key map (vector (easy-menu-make-symbol nickname))
                  (append (list 'menu-item nickname) (cdr item))))
            (easy-menu-add-item map nil item)))) ; with recursive structure

      ;; Main
      (dolist (item (reverse (cdr menu-bar-edit-menu)))
        (when (and (listp item)
                   (member (car item) poplife-mouse-edit-cmd-0)) ; pick some
          (bindings--define-key map (vector (car item)) (cdr item))))

      map)))
;; (let ((foo (poplife-mouse-edit-menu last-nonmenu-event))) (describe-variable 'foo))
\f
;;; iMenu
(defun poplife-imenu-easymap (&optional submenu)
  "Define easymenu to list index by iMenu.
When SUBMENU is non-nil, this returns an easymenu with multiple actions."
  ;; TODO: Selection of menu does not move point when called from
  ;; click on mode-line.
  (let* ((imenu-max-items poplife-file-max-menu-items) ; 25
         (map-0 (ignore-errors
                  (imenu--split-menu
                   (delq nil (cdr (imenu--make-index-alist t))) ; remove "*Rescan*"
                   (buffer-name))))
         (map (poplife-imenu-alist-to-easymap (car map-0) (cdr map-0)
                                            'imenu--menubar-select)))
    (when (>= (length map) 2) ; Return map only when map is with useful items.
      (if submenu
          (poplife-imenu-submenufy-easymap map)
        (let ((map-rev (reverse map)))
          (push (vector "More..."
                        '(popup-menu (poplife-imenu-easymap t)
                                     (popup-menu-normalize-position last-nonmenu-event)))
                map-rev)
          (reverse map-rev))))))
;; (let ((foo (poplife-imenu-easymap))) (describe-variable 'foo))
;; (let* ((poplife-func-find-file 'find-file-other-frame) (foo (poplife-imenu-easymap))) (describe-variable 'foo))
;; (let ((foo (poplife-imenu-easymap t))) (describe-variable 'foo))
;; (popup-menu (poplife-imenu-easymap))

(defun poplife-imenu-alist-to-easymap (title alist &optional cmd)
  "Create easymenu from alist by iMenu to display index by CMD.
This is fork of `imenu--create-keymap'."
  (let (map)
    (dolist (item alist)
      (push (cond
             ((imenu--subalist-p item)
              (poplife-imenu-alist-to-easymap (car item) (cdr item) cmd))
             (t
              (if cmd
                  (vector (car item)
                          (list 'let
                                '((display-buffer--other-frame-action ; hack for switch-to-buffer-other-frame
                                   '((display-buffer-pop-up-frame)
                                     (inhibit-same-window . t))))
                                `(funcall (quote ,(poplife-func-switch-to-buffer)) ,(current-buffer))
                                `(,cmd (quote ,item))))
                (list 'quote item))))
            map))
    (setq map (reverse map))
    (push title map)
    map))

(defun poplife-imenu-submenufy-easymap (map)
  "Return easymenu of iMenu MAP with recursive structure."
  (let (map-1)
    (dolist (item map)
      (push (cond
             ((listp item) ; when an item is a list
              (poplife-imenu-submenufy-easymap item))
             ((vectorp item) ; when an item is vector
              (poplife-imenu-elt-easymap item))
             (t item)) ; else such for "poplife.el"
            map-1))
    (reverse map-1)))

(defun poplife-imenu-elt-easymap (elt)
  "Return easymenu of iMenu ELT with submenu added."
  (let ((label (aref elt 0)) ; "poplife-mouse-edit-cottager"
        (cmd (nth 3 (aref elt 1))) ; (imenu--menubar-select '("poplife-mouse-edit-cottager" . #<marker at 3207 in poplife.el>))
        (buf (current-buffer))) ; #<buffer poplife.el>
    (list label
          (vector "Open" `(progn (switch-to-buffer ,buf) ,cmd))
          ["--" ignore]
          (vector "Open in Other Window" `(progn (switch-to-buffer-other-window ,buf) ,cmd))
          (vector "Open in Frame" `(progn (pop-to-buffer ,buf '((display-buffer-pop-up-frame) (inhibit-same-window . t))) ,cmd)))))
\f
;;; Frame
(defun poplife-frame-easymap ()
  "Define easymenu to list frames."
  (let ((frame-vec (nth 2 (cadddr (assoc 'frames global-buffers-menu-map))))
        (poplife-func-find-file 'find-file-other-frame)
        map)
    (dolist (elt (append frame-vec nil)) ; Convert vector to list.
      (let* ((nickname (car elt))
             (cmd (nth 4 elt))
             (frame (cadr cmd)))
        (push (vector nickname cmd :active (not (equal frame (selected-frame)))) map)))
    (push ["New" (progn (make-frame-command) (menu-find-file-existing))] map)
    (push ["--" ignore] map)
    (when (plist-get poplife-mouse-edit-cottager :buffer)
      (push (poplife-buffer-easymap) map))
    (when (plist-get poplife-mouse-edit-cottager :bookmark)
      (push (poplife-bookmark-easymap) map))
    (when (plist-get poplife-mouse-edit-cottager :recentf)
      (push (poplife-recentf-easymap) map))
    (unless (file-remote-p default-directory)
      (let ((dir-map (poplife-dir-easymap default-directory)))
        (setcar dir-map "File")        ; "Directory"
        (push dir-map map)))
    (setq map (reverse map))
    (push "Frames" map)
    map))
;; (let ((foo (poplife-frame-easymap))) (describe-variable 'foo))
\f
;;; Buffer
(defun poplife-buffer-easymap (&optional submenu)
  "Define easymenu to list buffers.
This extracts list of buffers from `global-buffers-menu-map'.
When SUBMENU is non-nil, this returns an easymenu with multiple actions."
  (let ((buffer-list (poplife-buffer-list))
        ;; (poplife-func-find-file 'find-file) ; 20190128.1647
        (menu-bar-select-buffer-function (poplife-func-switch-to-buffer))
        map)

    ;; Add submenu on request.
    (dolist (elt buffer-list)
      (push (poplife-buffer-elt-easymap elt submenu) map))

    ;; Add option.
    (push (vector "More..."
                  '(let (buffer-full-map)
                     (let (buffers-menu-max-size)
                       (menu-bar-update-buffers t)
                       (setq buffer-full-map
                             (poplife-buffer-easymap t)))
                     (menu-bar-update-buffers t)
                     (popup-menu buffer-full-map
                                 (popup-menu-normalize-position last-nonmenu-event)))
                  :visible t
                  :active (not submenu))
          map)

    ;; Reverse map and add a key.
    (setq map (reverse map))
    (push "Buffers" map)

    map))
;; (let ((foo (poplife-buffer-easymap))) (describe-variable 'foo))
;; (let ((foo (poplife-buffer-easymap t))) (describe-variable 'foo))

(defun poplife-buffer-list-on-menu ()
  "Return a list of buffers on `global-buffers-menu-map'."
  ;; on 25.2, pick 4th out of 5 items
  ;; ("menu-bar.el.gz  " lambda nil (interactive) (funcall menu-bar-select-buffer-function #<buffer menu-bar.el.gz>))
  ;; on 24.5, pick 5th out of 6 items
  ;; ("menu-bar.el.gz  " (nil) lambda nil (interactive) (funcall menu-bar-select-buffer-function #<buffer menu-bar.el.gz>))
  (let ((len245 6)
        (nth252 4)
        (nth245 5)
        (buffers-menu (nth 2 global-buffers-menu-map))
        ;; nickname-list
        buffer-list)
    (dolist (elt (append buffers-menu nil)) ; Convert vector to list.
      ;; (push (car elt) nickname-list)
      (push (nth 2 (nth (if (equal (length elt) len245)
                            nth245
                          nth252)
                        elt)) buffer-list))
    (reverse buffer-list)))
;; (let ((foo (poplife-buffer-list-on-menu))) (describe-variable 'foo))
;; (let ((foo (buffer-list))) (describe-variable 'foo))

(defun poplife-buffer-list ()
  "Return a list of buffers."
  (delete-dups (append (list (current-buffer))
                       (poplife-buffer-list-with-marks)
                       (poplife-buffer-list-on-menu))))
;; (let ((foo (poplife-buffer-list))) (describe-variable 'foo))

(defun poplife-buffer-list-with-marks ()
  "Return a list of buffers on `global-mark-ring'."
  (let (buffer-list buf)
    (dolist (marker (reverse global-mark-ring))
      (when (setq buf (marker-buffer marker)) ; See `pop-global-mark'
        (push buf buffer-list)))
    buffer-list))
;; (let ((foo (poplife-buffer-list-with-marks))) (describe-variable 'foo))

(defun poplife-buffer-elt-easymap (buffer &optional submenu)
  "Define easymenu for a BUFFER.
When SUBMENU is non-nil, this returns an easymenu with multiple
actions."
  (let ((nickname (buffer-name buffer)))
    (if (not submenu)
        (let (imenu-map)
          (if (and (plist-get poplife-mouse-edit-cottager :imenu)
                   (equal (current-buffer) buffer)
                   (setq imenu-map (poplife-imenu-easymap)))
              imenu-map
            (vector nickname `(funcall (quote ,menu-bar-select-buffer-function) ,buffer)
                    :active `(not (equal ,(current-buffer) ,buffer)))))
      (list nickname
            (vector "Open" `(switch-to-buffer ,buffer) :active `(not (equal ,(current-buffer) ,buffer)))
            ["--" ignore]
            (vector "Open in Other Window" `(switch-to-buffer-other-window ,buffer))
            (vector "Open in Frame" `(switch-to-buffer-other-frame ,buffer))))))
\f
;;; Recentf
(defun poplife-recentf-easymap (&optional submenu)
  "Define easymenu to list recentf.
When SUBMENU is non-nil, this returns an easymenu with multiple actions."
  (let (map
        (recentf-menu-shortcuts 0)
        (elements (recentf-menu-elements recentf-max-menu-items)))
    ;; See `recentf-make-menu-items'.
    (setq map (mapcar (lambda (elt)
                        (funcall 'poplife-recentf-elt-easymap elt submenu))
                      (recentf-apply-menu-filter
                       recentf-menu-filter
                       elements)))
    (let ((map-rev (reverse map)))
      (push (vector "More..."
                    '(let ((recentf-max-menu-items recentf-max-saved-items))
                       (popup-menu (poplife-recentf-easymap t)
                                   (popup-menu-normalize-position last-nonmenu-event)))
                    :help "Show more Recentf"
                    :visible t
                    :active (not submenu))
            map-rev)
      (push ["--" ignore] map-rev)
      (push ["Edit..."
             recentf-edit-list
             :help "Manually remove files from the recent list"
             :active t]
            map-rev)
      ;; (push ["Save List Now"
      ;;        recentf-save-list
      ;;        :help "Save the list of recently opened files now"
      ;;        :active t]
      ;;       map-rev)
      (setq map (reverse map-rev)))
    (cons "Recent" map)))
;; (let ((foo (poplife-recentf-easymap))) (describe-variable 'foo))

(defun poplife-recentf-elt-easymap (elt &optional submenu)
  "Define easymenu to popup recentf item ELT.
When SUBMENU is non-nil, this returns an easymenu with multiple actions."
  ;; This is fork of `recentf-make-menu-item'.
  (let ((name (recentf-menu-element-item elt))
        (file (recentf-menu-element-value elt)))
    (if (recentf-sub-menu-element-p elt)
        (cons name (mapcar (lambda (elt) (funcall 'poplife-recentf-elt-easymap elt)) file)) ; for `recentf-arrange-by-dir'
      ;; (vector name
      ;;         `(,recentf-menu-action ,file) ; poplife-func-find-file
      ;;         :help (concat "Open " file)
      ;;         :active t)
      (let ((map
             (if (file-directory-p file)
                 (poplife-dir-easymap file submenu) ; directory
               (poplife-file-easymap file submenu)))) ; file
        (when (listp map)
          (setcar map name))
        map))))
\f
;;; Bookmark
(defun poplife-bookmark-easymap (&optional submenu)
  "Define easymenu to list bookmarks.
When SUBMENU is non-nil, this returns an easymenu with multiple actions."
  ;; TODO: On emacs-27.1 with smb, I see "tramp-error: Method ‘smb’ is
  ;; not known".
  (let ((map
         (list
          (vector "More..." '(popup-menu (poplife-bookmark-easymap t)
                                         (popup-menu-normalize-position last-nonmenu-event))
                  :visible t
                  :active (not submenu)
                  :help "Set a bookmark named inside a file.")
          ["--" ignore]
          ["Add..." bookmark-set :visible t :active (or (buffer-file-name) (eq major-mode 'dired-mode))
           :help "Set a bookmark named inside a file."]
          ["Edit..." bookmark-bmenu-list :visible t :active t
           :help "Display a list of existing bookmarks"]
          ;; ["Save List Now" bookmark-save :visible t :active t
          ;;  :help "Save currently defined bookmarks"]
          )))
    (dolist (bookmark (bookmark-all-names))
      (push (poplife-bookmark-elt-easymap bookmark submenu) map))
    (cons "Bookmark" map)))
;; (let ((foo (poplife-bookmark-easymap))) (describe-variable 'foo))
;; (let ((foo (poplife-bookmark-easymap t))) (describe-variable 'foo))

(defun poplife-bookmark-elt-easymap (bookmark &optional submenu)
  "Define easymenu to list a BOOKMARK.
When SUBMENU it non-nil, this returns an easymenu with multiple actions."
  (let (map)
    (if (not submenu)
        (let ((file (bookmark-get-filename bookmark)))
          (if (and (not (file-remote-p file)) ; when bookmark is directory
                   (file-exists-p file)
                   (file-directory-p file))
              (poplife-dir-easymap file submenu) ; offer DIR menu
            (vector bookmark
                    ;; `(bookmark-jump ,bookmark DISPLAY-FUNC)
                    `(bookmark-jump ,bookmark (quote ,(poplife-func-switch-to-buffer))) ; switch-to-buffer
                    :visible t
                    :active (not (string= ; gray the vising file out
                                  (and (buffer-file-name) (expand-file-name (buffer-file-name)))
                                  (expand-file-name (bookmark-get-filename bookmark))))
                    :help (format "Jump to %s" bookmark))))

      ;; (push (vector "Show Annotation..." `(bookmark-show-annotation ,bookmark) :visible t :active `(bookmark-get-annotation ,bookmark) :help bookmark) map)
      ;; (push (vector "Edit Annotation..." `(bookmark-edit-annotation ,bookmark) :visible t :help bookmark) map)
      (let ((annot-map (poplife-bookmark-annotation-easymap bookmark)))
        (if (vectorp annot-map) ; with no annotation and with "Add Annotation..."
            (push annot-map map)
          (dolist (annot-item (reverse (cdr annot-map)))
            (push annot-item map))
          (push ["--" ignore] map)
          (push (vector "Edit Annotation..." `(bookmark-edit-annotation ,bookmark) :visible t :help bookmark) map)))
      (push (vector "Delete..." `(and (y-or-n-p (format "Are you sure you want to delete a bookmark %s? " ,bookmark)) (bookmark-delete ,bookmark)) :visible t :help bookmark) map)
      (push (vector "Edit Location..." `(bookmark-relocate ,bookmark) :visible t :help bookmark) map)
      (push (vector "Rename..." `(bookmark-rename ,bookmark) :visible t :help bookmark) map)
      (push (vector "Insert Location" `(bookmark-locate ,bookmark) :visible t :help bookmark) map)
      (push (vector "Insert Contents" `(bookmark-insert ,bookmark) :visible t :help bookmark) map)
      (push (vector "Open by File Browser" `(poplife-find-location (expand-file-name (bookmark-get-filename ,bookmark))) :visible t :active t :help bookmark) map)
      (push (vector "Open in Frame" `(bookmark-jump ,bookmark 'switch-to-buffer-other-frame) :visible t :help bookmark) map)
      (push (vector "Open in Other Window" `(bookmark-jump-other-window ,bookmark) :visible t :help bookmark) map)
      (push ["--" ignore] map)
      (push (vector "Open" `(bookmark-jump ,bookmark) :visible t :help bookmark) map) ; switch-to-buffer
      (push (vector ".." `(let ((poplife-file-recursive ,poplife-file-recursive)
                                (poplife-func-find-file (quote ,poplife-func-find-file)))
                            (poplife-find-dir (expand-file-name "../" (bookmark-get-filename ,bookmark)) ,submenu))
                    :visible t :active t) map)
      (let ((annotation (bookmark-get-annotation bookmark)))
        (cons (format "%s%s" bookmark (if (and annotation (not (string-equal annotation ""))) "*" "")) map)))))
;; (let ((foo (poplife-bookmark-elt-easymap "poplife.el\\site-lisp"))) (describe-variable 'foo))
;; (let ((foo (poplife-bookmark-elt-easymap "poplife.el\\site-lisp" t))) (describe-variable 'foo))

(defvar poplife-bookmark-annotation-detail-flag t
  "Show full contents of annotation in popup-menu.")

(defun poplife-bookmark-annotation-easymap (bookmark)
  "Define easymenu to list annotation."
  (let ((annot (bookmark-get-annotation bookmark))
        (annot-column 36)) ; 36 is arbitrary number or (length "Open in Other Window")
    (if (and annot (not (string-equal annot "")))
        (if poplife-bookmark-annotation-detail-flag
            (let ((lines (poplife-split-string annot annot-column))
                  map)
              (dolist (line (reverse lines))
                (push (vector line `(bookmark-edit-annotation ,bookmark) :visible t :active t :help bookmark) map))
              (cons "Edit Annotation..." map))
          (let (annot-name)
            (setq annot-name (format "Edit Annotation `%s'..." (if (> (length annot) annot-column) (substring annot 0 annot-column) annot)))
            (vector annot-name `(bookmark-edit-annotation ,bookmark) :visible t :active t :help bookmark)))
      (vector "Add Annotation..." `(bookmark-edit-annotation ,bookmark) :visible t :active t :help bookmark))))

(defun poplife-split-string (string fill-length)
  "Split STRING into list of string.
Argument FILL-LENGTH determines length of each line."
  (setq string (replace-regexp-in-string
                (rx (* (any " \t\n")) eos) "" string)) ; Chomp text.
  (with-temp-buffer
    (insert string)
    (let ((fill-column fill-length) ; Replace text.
          (find-repl-list '(("\\`\\'" . " ") (" +" . " ")))) ; Avoid having "--" on menu.
      (fill-region (point-min) (point-max))
      (dolist (find-repl find-repl-list)
        (goto-char (point-min))
        (while (re-search-forward (car find-repl) nil t)
          (replace-match (cdr find-repl)))))
    (split-string (buffer-string) "\n"))) ; List of text lines.
\f
;;; File
(defun poplife-file-easymap (file &optional submenu)
  "Define easymenu to list a FILE.
When SUBMENU it non-nil, this returns an easymenu with multiple actions."
  (setq file (expand-file-name file))
  (and (not (file-directory-p file))
       (let* (map
              (file-nickname (file-name-nondirectory file))
              (file-readable-flag (and (file-regular-p file)
                                       (file-readable-p file)))
              (open-file-flag (and (not (string-match-p poplife-file-do-not-open-regexp file))
                                   file-readable-flag))
              (dir (file-name-directory file))
              (open-dir-flag (and (file-directory-p dir)
                                  (file-accessible-directory-p dir))))
         (if (not submenu)
             (vector file-nickname
                     `(funcall (if ,open-file-flag
                                   (quote ,poplife-func-find-file)
                                 (quote ,poplife-func-find-file-by-default-app)) ,file)
                     :active (and file-readable-flag ; gray the vising file out
                                  (not (string=
                                        (and (buffer-file-name) (expand-file-name (buffer-file-name)))
                                        file)))
                     :help file)
           (push (vector "Open with File Browser" `(poplife-find-location ,file)
                         :visible t
                         :active open-dir-flag
                         :help dir) map)
           (push (vector "Open with Default App" `(,poplife-func-find-file-by-default-app ,file)
                         :visible t
                         :active t
                         :help file) map)
           (push (vector "Open and Bookmark..." `(progn (find-file ,file) (bookmark-set))
                         :visible (fboundp 'bookmark-set)
                         :active open-file-flag
                         :help "Open and Bookmark this file") map)
           (push (vector "Open in Frame" `(find-file-other-frame ,file)
                         :visible t
                         :active open-file-flag
                         :help file) map)
           (push (vector "Open in Other Window" `(find-file-other-window ,file)
                         :visible t
                         :active open-file-flag
                         :help file) map)
           (push ["--" ignore] map)
           (push (vector "Open" `(find-file ,file)
                         :visible t
                         :active (and open-file-flag ; gray the vising file out
                                      (not (string=
                                            (and (buffer-file-name) (expand-file-name (buffer-file-name)))
                                            file)))
                         :help file) map)
           (push (vector ".." `(let ((poplife-file-recursive ,poplife-file-recursive)
                                     (poplife-func-find-file (quote ,poplife-func-find-file)))
                                 (poplife-find-dir ,dir, submenu))
                         :visible t :active open-dir-flag :help dir) map)
           (cons file-nickname map)))))
;; (let ((foo (poplife-file-easymap "~/.emacs.d/init.el"))) (describe-variable 'foo))
;; (let ((foo (poplife-file-easymap "~/.emacs.d/init.el" t))) (describe-variable 'foo))

(defun poplife-dir-easymap (dir &optional submenu depth)
  "Define easymenu to list files and directories in DIR.
When SUBMENU is non-nil, this returns an easymenu with multiple actions.
When DEPTH is more than 1, DIR is recursively scanned."
  (when (string-match-p poplife-dir-do-not-scan-regexp dir)
    (setq dir "~"))
  (setq dir (directory-file-name (expand-file-name dir))) ; Remove slash at the end.
  (or depth (setq depth 1))
  (let (map base-dir parent-dir rawfiles menufiles)
    (setq base-dir (file-name-as-directory (if (string= (file-name-nondirectory dir) "")
                                               dir ; In a case for "c:/"
                                             (file-name-nondirectory dir)))) ; Add slash at the end.
    (setq parent-dir (directory-file-name (file-name-directory dir)))
    ;; Obtain a file list.
    (setq rawfiles (ignore-errors (directory-files dir t)))
    ;; Filter out trivial files.
    (dolist (fullfile rawfiles)
      (let ((file-nickname (file-name-nondirectory fullfile)))
        (unless (string-match-p poplife-file-do-not-show-regexp file-nickname)
          (push fullfile menufiles))))
    ;; Limit number of menufiles
    (when (and poplife-file-max-menu-items
               (not submenu))
      (let ((nfile (length menufiles)))
        (setq menufiles (nthcdr (- nfile poplife-file-max-menu-items) menufiles))))
    ;; Add more menu.
    (push (vector "More..." ; Item to open a current directory.
                  `(let (poplife-file-max-menu-items
                         ;; (poplife-file-recursive ,(1+ poplife-file-recursive))
                         (poplife-file-recursive ,poplife-file-recursive)
                         (poplife-func-find-file (quote ,poplife-func-find-file)))
                     (poplife-find-dir ,dir t))
                  :active `(not ,submenu)
                  :visible t
                  :help dir)
          map)
    ;; Create map with files and directories.
    (dolist (fullfile menufiles)
      (let ((file-nickname (file-name-nondirectory fullfile)))
        (if (file-directory-p fullfile) ; when item is directory
            (push (if (or (>= depth poplife-file-recursive)
                          (not (file-accessible-directory-p fullfile)))
                      (vector (file-name-as-directory file-nickname)
                              `(let ((poplife-file-recursive ,poplife-file-recursive)
                                     (poplife-func-find-file (quote ,poplife-func-find-file)))
                                 (poplife-find-dir ,fullfile ,submenu))
                              :active (file-accessible-directory-p fullfile) :help fullfile)
                    (poplife-dir-easymap fullfile submenu (1+ depth))) ; recursive
                  map)
          (push ; when item is file (that is defined as `not a directory')
           (poplife-file-easymap fullfile submenu)
           map))))
    (push ["--" ignore] map)
    (push (if (not (or submenu poplife-dir-.-submenu)) ; (not submenu)
              ;; Single item
              (vector "." ; item to open current directory
                      `(,poplife-func-find-file ,dir)
                      ;; `(,poplife-func-find-file-by-default-app ,dir)
                      :visible t :active t :help dir)
            ;; Multiple items in submenu.
            (delq nil
                  (list "."
                        (vector "Open" ; item to open current directory
                                `(find-file ,dir) ; ,poplife-func-find-file
                                :visible t :active t :help dir)
                        ["--" ignore]
                        (vector "Open in Other Window"
                                `(find-file-other-window ,dir)
                                :visible t :active t :help dir)
                        (vector "Open in Frame"
                                `(find-file-other-frame ,dir)
                                :visible t :active t :help dir)
                        (vector "Open with Bookmarked..."
                                `(progn (find-file ,dir) (bookmark-set))
                                :visible (fboundp 'bookmark-set) :active t :help "Open and Add to Bookmarks")
                        (vector "Open by File Browser"
                                `(,poplife-func-find-file-by-default-app ,dir)
                                :visible t
                                :active t
                                :help dir))))
          map)
    (push (vector ".." ; Item to open parent directory.
                  `(let ((poplife-file-recursive ,poplife-file-recursive)
                         (poplife-func-find-file (quote ,poplife-func-find-file)))
                     (poplife-find-dir ,parent-dir ,submenu))
                  :active `(not (equal ,parent-dir ,dir)) :help parent-dir)
          map)
    (setq base-dir (replace-regexp-in-string "^@" "at" base-dir t t))
    (cons base-dir map)))
;; (let ((foo (poplife-dir-easymap "~/.emacs.d"))) (describe-variable 'foo))
;; (let ((foo (poplife-dir-easymap "~/.emacs.d" t))) (describe-variable 'foo))
;; (popup-menu (poplife-dir-easymap "~/.emacs.d"))
;; (popup-menu (poplife-dir-easymap "~/"))
;; (let ((foo (poplife-dir-easymap "c:/"))) (describe-variable 'foo))
;; (popup-menu (poplife-dir-easymap "c:/"))

(defvar poplife-dir-.-submenu t
  "Show always submenu for the current directory.")

(defun poplife-pwd-easymap (path &optional submenu)
  "Define easymenu to list directories that are above PATH."
  (setq path (directory-file-name (expand-file-name path))) ; remove slash
  (let* ((title (format (if (file-directory-p path)
                            "%s/"
                          "%s")
                        (file-name-nondirectory path)))
         dirpath
         map)
    (while (not (string= (file-name-nondirectory path) "" ))
      (setq dirpath (directory-file-name (file-name-directory path))) ; remove slash
      (push (vector (format "%s/" (file-name-nondirectory dirpath)) ; dirname
                    `(poplife-find-location ,path)) map)
      (setq path dirpath))
    (cons title (reverse map))))
;; (let ((foo (poplife-pwd-easymap "~/.emacs.d/site-lisp/poplife.el"))) (describe-variable 'foo))
;; (popup-menu (poplife-pwd-easymap default-directory))
;; (popup-menu (poplife-pwd-easymap "~/.emacs.d/site-lisp/"))

(defun poplife-pwd-menu-open (event)
  "Open popup-menu that opens a folder by File Browser."
  (interactive "e")
  (mouse-set-point event)
  (popup-menu
   (poplife-pwd-easymap (or buffer-file-name default-directory))))
;; (poplife-pwd-menu-open last-nonmenu-event)

(defun poplife-buffer-menu-open (event)
  "Open popup-menu that switches current buffer."
  (interactive "e")
  (mouse-set-point event)
  (popup-menu (poplife-buffer-easymap)))
;; (poplife-buffer-menu-open last-nonmenu-event)

\f
;;; Util
(defun poplife-func-switch-to-buffer ()
  "Return switch-to-buffer function that corresponds to `poplife-func-find-file'."
  (cdr (assoc poplife-func-find-file
              '((find-file . switch-to-buffer)
                (find-file-other-window . switch-to-buffer-other-window)
                (find-file-other-frame . switch-to-buffer-other-frame)))))
;; (let ((foo (poplife-func-switch-to-buffer))) (describe-variable 'foo))

(defun poplife-find-dir (dir &optional submenu)
  "Visit directory DIR using `popup-menu'.
When SUBMENU is non-nil, this offers multiple actions."
  ;; (interactive (list (read-directory-name "Find directory: ")))
  (popup-menu (poplife-dir-easymap dir submenu)
              (popup-menu-normalize-position last-nonmenu-event)))

(defun poplife-finder-directory ()
  "Return directory where Finder is visiting."
  (when (eq system-type 'darwin)
    (ns-do-applescript
     "tell application \"Finder\"
        if exists Finder window 1 then
          set currentDir to target of Finder window 1 as alias
        else
          set currentDir to desktop as alias
        end if
          set thePath to POSIX path of currentDir
      end tell")))
;; (let ((foo (poplife-finder-selection))) (describe-variable 'foo))

(defun poplife-find-location (file)
  "Visit directory that contains FILE."
  ;; org-open-file
  (cond
   ((eq system-type 'darwin)
    ;; Select file in Finder.
    (ns-do-applescript                  ; do-applescript, osascript
     (format "tell application \"Finder\"
                  set thePath to POSIX file \"%s\" as string
                  activate
                  reveal thePath
              end tell" file)))
   ((eq system-type 'windows-nt)
    ;; Select file in File Explorer.
    (w32-shell-execute "open" "explorer"
                       (concat "/e,/select,"
                               (poplife-convert-w32-filename file))))
   ((eq system-type 'gnu/linux)
    ;; Visit dir that contains file by default-app.
    ;; (start-process "select-file-by-nautilus" nil "nautilus" file)
    (start-process "open-dir-by-xdg-open" nil "xdg-open" (file-name-directory file)))
   (t
    ;; Select file in Dired
    (dired-other-frame (file-name-directory file)) ; Visit dir that contains file
    (dired-goto-file file)))) ; Move point to file

(defun poplife-convert-w32-filename (filename)
  "Mirror slash characters in FILENAME into backslashes."
  ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=24387 (bug#24387)
  ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=28883 (bug#28883)

  ;; (setq filename (convert-standard-filename filename))
  (let ((start 0))
    (while (string-match "/" filename start)
      (aset filename (match-beginning 0) ?\\)
      (setq start (match-end 0)))
    filename))
;;; (poplife-convert-w32-filename "c:/Users/dream/.emacs.d")

(defun poplife-find-file-by-default-app (file)
  "Visit FILE by default application or default file browser."
  (when (plist-get poplife-mouse-edit-cottager :recentf)
    (recentf-push file))
  (cond
   ((eq system-type 'gnu/linux)
    (start-process "find-file-by-default-app" nil "xdg-open" file)) ; Visit file by default-app.
   ((eq system-type 'darwin)
    (start-process "find-file-by-default-app" nil "open" file)) ; Visit file by default-app.
   ((eq system-type 'cygwin)
    (start-process "find-file-by-default-app" nil "cygstart" file)) ; Visit file by default-app.
   ((eq system-type 'windows-nt)
    (w32-shell-execute "open" "explorer" (poplife-convert-w32-filename file))) ; Visit file by default-app.
   (t
    (find-file-other-frame file))))

(provide 'poplife)
;;; poplife.el ends here

[-- Attachment #3: Type: text/plain, Size: 2 bytes --]




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-16  1:25           ` Drew Adams
@ 2020-09-16  8:10             ` Ergus
  2020-09-16 15:02               ` Drew Adams
  2020-09-17  3:57               ` Richard Stallman
  2020-09-17  3:51             ` Richard Stallman
  1 sibling, 2 replies; 112+ messages in thread
From: Ergus @ 2020-09-16  8:10 UTC (permalink / raw)
  To: Drew Adams
  Cc: emacs-devel, Juri Linkov, philipk, Richard Stallman,
	Göktuğ Kayaalp, Arthur Miller, Dmitry Gutov,
	Gregory Heytings

On Wed, Sep 16, 2020 at 01:25:35AM +0000, Drew Adams wrote:
>You're all over the map, Ergus, arguing abstractly, not
>to the point - bringing in undo-redo;

This was just an examples of discussions that have been for years in
this mailing list and changes that the legacy users have opposed and
vetoed with the argument of the "Emacs way is better" (like
delete-selection-mode, transient-mark-mode and so on).

>newbie-vs-better
>behavior; hiding the context menu behind C-mouse-3,
>which also doesn't work in a terminal 

This is so far the point of the discussion.

>(mouse3.el uses mouse-3);

It is not there and not easy to install for newcomers, normal users, or
toggle enabled when we open with emacs -Q, or working in another
machine.

Emacs is supposed to be an editor, not a box from IKEA to assemble your
own one by hand because people go to IKEA because they consider is
cheaper not because they think it is better. If other companies offer
the same furniture than IKEA, assembled and bring them to home at the
same price then IKEA will probably close in a couple of years.

>"moving the mouse to the toolbar to copy after
>the selection" (huh? what's that about?);

That's the only alternative we give to the mouse users for coping/paste:
select with the mouse mixing clicks go to the [tool,menu]bar and click
copy then go to the place, click, toolbar->paste instead of
select, right-click->copy, go, right-click->paste.

>"M-w and C-y
>dont share any key like C-c/C-v"; "we need the two hand
>to undo instead of C-z" ;...
>
Your previous argument was that pressing \click and shift+click\ for
selecting was worst than \3 clicks + right mouse click\. So I just showed
that there are worst inconsistencies/in-ergonomic/complicated bindings
for other common and frequent actions and nobody (including me) cares.

Here is another: do you think that killing is more frequent (to have it
ready in double right click) than copy?


>(two hands to undo?)

Yes: C-/ and M-_ requires two hands while C-x u is a bit long to repeat.

>Again:
>
>>> The impetus for this discussion was expectations
>>> of new users to get a context menu on `mouse-3'.
>>> (But newbies are not the only reason for such a
>>> feature.)
>
>A context menu is useful for discoverability, including
>by seasoned Emacs users (we are all discovering some
>parts of Emacs).  It should be easily configurable by
>program and by users, adaptable for any mode or other
>context.  `mouse-3' is a good place for it, and not
>only because that's where newbies expect it.
>
Agree

>Emacs mouse selection, including extension & deletion,
>are also useful.  Both this and a `mouse-3' menu are
>possible, with no sacrifice.

Not sure there is a consistent way for this.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-15 22:47         ` Ergus via Emacs development discussions.
  2020-09-16  0:29           ` Corwin Brust
  2020-09-16  1:25           ` Drew Adams
@ 2020-09-16 14:13           ` Eli Zaretskii
  2 siblings, 0 replies; 112+ messages in thread
From: Eli Zaretskii @ 2020-09-16 14:13 UTC (permalink / raw)
  To: Ergus
  Cc: philipk, rms, juri, ghe, arthur.miller, dgutov, self, emacs-devel,
	drew.adams

> Date: Wed, 16 Sep 2020 00:47:38 +0200
> CC: philipk@posteo.net, Richard Stallman <rms@gnu.org>,
>  Göktuğ Kayaalp <self@gkayaalp.com>,
>  Arthur Miller <arthur.miller@live.com>, Dmitry Gutov <dgutov@yandex.ru>,
>  Gregory Heytings <ghe@sdf.org>
> From: Ergus via "Emacs development discussions." <emacs-devel@gnu.org>
> 
> On September 15, 2020 10:33:51 PM GMT+02:00, Drew Adams <drew.adams@oracle.com> wrote:
> >> > read `Mouse Commands' if you haven't
> >> > already, and give it a try.
> >> 
> >> Mouse support is poor in Emacs, this is the reason
> >> why I don't use the mouse in Emacs.
> >
> >I disagree that mouse support is poor in Emacs.
> >
> So you are the only one I know so far with that opinion.

He's not the only one.

> This is the same problem than undo-redo. Maybe the features are actually better technically speaking or to whom knows all the tricks and trains himself for years; but it worth nothing if the users feel uncomfortable or don't values some of the details that justify complexity in others. (Like hiding the context panel with a control or not having a redo button or not deleting the selection) Or just don't need them.
> 
> There are some "standards" in mouse interaction determined/imposed by most of the gui programing interfaces from visual studio or java to qt5 and gtk. The developers of all the aplications have been following them for years and most of the user are used to them.

Emacs didn't invent the effect of the mouse gestures we have now, they
closely follow what X applications do, or at least did at the time.
Perhaps nowadays those applications and users who are used to those
effects are a minority (what with all the "modern" desktops so busy
copycat'ing MS-Windows' look and feel), but we still have many users
who have these gestures burnt into their muscle memories.  Wed cannot
just abandon them, even if they are a minority (which is not at all
certain).

What we _can_ do is to have 2 modes of operation, one each for every
one of these two groups of users.  This is easy to do technically, all
we need is "just" to have someone who'd sit down and design the
"other" mode of mouse gestures in some reasonable and logical way.

> So this is the "dilema". Or we change a bit (1 binding) to ease the user experience and learning curve OR we expect that all the potential users change their expectations, trainings and don't go to any other editor but use emacs because we pretend we offer a better functionality that they are not aware of and most probably don't need or never learn/use because is complex to remember.

There's no dilemma, we can have both modes.

> Simple is better than complex.
> Complex is better than complicated.

And the one you are used to is the best of them all.

> The emacs approach with mouse is indeed complicated.

I disagree that it's complicated.  But we don't have to agree, see
above.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-16  6:28 Context menus and mouse-3 Tak Kunihiro
@ 2020-09-16 14:18 ` Eli Zaretskii
  2020-09-16 14:37   ` Thibaut Verron
  2020-09-16 19:45 ` Juri Linkov
  1 sibling, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2020-09-16 14:18 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: juri, emacs-devel

> From: Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>
> Date: Wed, 16 Sep 2020 15:28:56 +0900
> Cc: Juri Linkov <juri@linkov.net>
> 
> - Horizontal scroll by wheel is supported.
> - Moving text using mouse is supported.
> * Contextual menu is not supported yet.

Yes, we do support contextual menus, just press C-mouse-3.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-16 14:18 ` Eli Zaretskii
@ 2020-09-16 14:37   ` Thibaut Verron
  2020-09-16 15:06     ` Eli Zaretskii
  2020-09-17  3:57     ` Richard Stallman
  0 siblings, 2 replies; 112+ messages in thread
From: Thibaut Verron @ 2020-09-16 14:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Tak Kunihiro, emacs-devel, juri

Le mer. 16 sept. 2020 à 16:19, Eli Zaretskii <eliz@gnu.org> a écrit :
>
> > From: Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>
> > Date: Wed, 16 Sep 2020 15:28:56 +0900
> > Cc: Juri Linkov <juri@linkov.net>
> >
> > - Horizontal scroll by wheel is supported.
> > - Moving text using mouse is supported.
> > * Contextual menu is not supported yet.
>
> Yes, we do support contextual menus, just press C-mouse-3.

It is only contextual if "context" just means "major mode".



^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-16  8:10             ` Ergus
@ 2020-09-16 15:02               ` Drew Adams
  2020-09-17  3:57               ` Richard Stallman
  1 sibling, 0 replies; 112+ messages in thread
From: Drew Adams @ 2020-09-16 15:02 UTC (permalink / raw)
  To: Ergus
  Cc: philipk, Richard Stallman, Juri Linkov, Gregory Heytings,
	Arthur Miller, Dmitry Gutov, Göktuğ Kayaalp,
	emacs-devel

> > (mouse3.el uses mouse-3);
> 
> It is not there and not easy to install for newcomers, normal users, or
> toggle enabled when we open with emacs -Q, or working in another
> machine.

I propose that it be added to Emacs, that the
behavior it offers be included, and even made
the default behavior.  It doesn't conflict with
the current behavior - it supplements it.

Which context menus are provided out of the box
can be discussed.  `mouse3.el' gives users and
libraries easy ways to get the menus they want,
but what menus Emacs should provide by default
is an open question.

> Emacs is supposed to be an editor, not a box from IKEA to assemble your
> own one by hand because people go to IKEA because they consider is
> cheaper not because they think it is better. If other companies offer
> the same furniture than IKEA, assembled and bring them to home at the
> same price then IKEA will probably close in a couple of years.

Emacs is very much a toolkit, and much more.
Emacs Lisp is its core (and some say its
raison d'etre).

Emacs is NOT just an out-of-the-box experience.
It does provide an out-of-the-box experience.
No one _need_ customize it.  But many (most?)
people do.  Openness to customization is a core
feature of Emacs.

You've missed the boat, if you don't think Emacs
is _at least_ a toolkit.

> >"moving the mouse to the toolbar to copy after
> >the selection" (huh? what's that about?);
> 
> That's the only alternative we give to the mouse users for coping/paste:
> select with the mouse mixing clicks go to the [tool,menu]bar and click
> copy then go to the place, click, toolbar->paste instead of
> select, right-click->copy, go, right-click->paste.

No.  `mouse3.el' (this thread is about context
menus and `mouse-3') offers all of that with a
right-click.

> Here is another: do you think that killing is more frequent (to have it
> ready in double right click) than copy?

`mouse-drag-copy-region'

(IMO, the default value should be t, not nil.)

> >Emacs mouse selection, including extension & deletion,
> >are also useful.  Both this and a `mouse-3' menu are
> >possible, with no sacrifice.
> 
> Not sure there is a consistent way for this.

`mouse3.el' offers exactly that.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-16 14:37   ` Thibaut Verron
@ 2020-09-16 15:06     ` Eli Zaretskii
  2020-09-16 15:39       ` Thibaut Verron
  2020-09-17  3:57     ` Richard Stallman
  1 sibling, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2020-09-16 15:06 UTC (permalink / raw)
  To: thibaut.verron; +Cc: tkk, emacs-devel, juri

> From: Thibaut Verron <thibaut.verron@gmail.com>
> Date: Wed, 16 Sep 2020 16:37:16 +0200
> Cc: Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>, juri@linkov.net, 
> 	emacs-devel <emacs-devel@gnu.org>
> 
> > > - Horizontal scroll by wheel is supported.
> > > - Moving text using mouse is supported.
> > > * Contextual menu is not supported yet.
> >
> > Yes, we do support contextual menus, just press C-mouse-3.
> 
> It is only contextual if "context" just means "major mode".

That's the "context" that we decided was relevant.  We can decide to
give it a different interpretation, but that doesn't mean we don't
support contextual menus.

Also, please don't forget that we have the most popular
context-dependent action for mouse-sensitive text on mouse-2.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-16 15:06     ` Eli Zaretskii
@ 2020-09-16 15:39       ` Thibaut Verron
  0 siblings, 0 replies; 112+ messages in thread
From: Thibaut Verron @ 2020-09-16 15:39 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Tak Kunihiro, emacs-devel, juri

Le mer. 16 sept. 2020 à 17:06, Eli Zaretskii <eliz@gnu.org> a écrit :
>
> > From: Thibaut Verron <thibaut.verron@gmail.com>
> > Date: Wed, 16 Sep 2020 16:37:16 +0200
> > Cc: Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>, juri@linkov.net,
> >       emacs-devel <emacs-devel@gnu.org>
> >
> > > > - Horizontal scroll by wheel is supported.
> > > > - Moving text using mouse is supported.
> > > > * Contextual menu is not supported yet.
> > >
> > > Yes, we do support contextual menus, just press C-mouse-3.
> >
> > It is only contextual if "context" just means "major mode".
>
> That's the "context" that we decided was relevant.  We can decide to
> give it a different interpretation, but that doesn't mean we don't
> support contextual menus.

We can go with that definition, but then we will have to accept that
it will be yet another point where the Emacs language differs from the
usual understanding. I don't suggest reforming the language to fix the
existing such points, but I believe that we should do our best to
avoid creating new ones.

It seems easy enough here, since the C-mouse-3 menu already has a
name: it is the major-mode menu.
By contrast, the suggested library mouse3.el does offer a contextual menu.


> Also, please don't forget that we have the most popular
> context-dependent action for mouse-sensitive text on mouse-2.

[And in the absence of a context, the same button does something
useful too, but with a confusing twist (the primary selection which is
neither the kill ring nor the system clipboard).]

I don't find mouse-2 easy to enter reliably, and I'd much rather see
those actions easy to reach in a mouse-3 menu.
Also, as pointed earlier in the thread, there are still mice with 2
buttons, for example laptop touchpads, and the buttons are typically
mouse-1 and mouse-3, making those actions inaccessible.
[It might be related to the fact that most applications and most users
call those buttons mouse-1 and mouse-2 respectively, mouse-3 being the
middle-click. Cf the aforementioned language divergence. :)]



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-16  2:24       ` Eli Zaretskii
@ 2020-09-16 19:35         ` Juri Linkov
  2020-09-16 23:10           ` Dmitry Gutov
  2020-09-17  3:58           ` Richard Stallman
  0 siblings, 2 replies; 112+ messages in thread
From: Juri Linkov @ 2020-09-16 19:35 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: philipk, rms, spacibba, emacs-devel, self, arthur.miller, dgutov,
	ghe, drew.adams

>> Mouse support is poor in Emacs, this is the reason
>> why I don't use the mouse in Emacs.  More below:
>
> "Poor"? the below just says that other applications (which ones?) do
> it slightly differently, that's all.  I don't see how what you say
> justifies the "poor" part.

Yes, this is subjective, but while I use the mouse in other apps,
every time I try to use the mouse in Emacs, I can't make any sense of
default mouse bindings mess, so have to resort to the keyboard (where
Emacs keybindings are far superior to other apps).



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-15 20:33       ` Drew Adams
  2020-09-15 22:47         ` Ergus via Emacs development discussions.
@ 2020-09-16 19:41         ` Juri Linkov
  1 sibling, 0 replies; 112+ messages in thread
From: Juri Linkov @ 2020-09-16 19:41 UTC (permalink / raw)
  To: Drew Adams
  Cc: philipk, Richard Stallman, Ergus, emacs-devel,
	Göktuğ Kayaalp, Arthur Miller, Dmitry Gutov,
	Gregory Heytings

>> In other apps, the same is achieved by double-click
>> (`mouse-1') on a word, then double-click the same
>> (`mouse-1') on another word while holding down the Shift key.
>
> And that's better why?  Having to use both the
> keyboard and the mouse?

So what?  There are many mouse commands in Emacs
that require pressing a modifier key.

>> But what if you need first to select a line, then extend
>> the selection to a word?  In other apps, triple-click a line,
>> then double-click `mouse-1' on a word while holding down the Shift key.
>> In Emacs, this is impossible.
>
> Granted.  But again, both keyboard and mouse.
>
> We could provide a keyboard + mouse combination
> for such use cases if that were a common need.

Isn't this already a common need?  For example,
when a user selects a word by double-clicking it,
and then needs to extend the selection to the middle
of another word.  Currently impossible in Emacs with mouse-3.

>> Also in other apps Shift+F10 opens the context menu,
>> but why not in Emacs?
>
> That's orthogonal.  Nothing prevents also having
> a keyboard key sequence to open a context menu.
> (Presumably the "location" it refers to would
> be point.)

This is still related: since there is no context menu on mouse-3,
there is a need for a keyboard equivalent compatible with other apps.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-16  6:28 Context menus and mouse-3 Tak Kunihiro
  2020-09-16 14:18 ` Eli Zaretskii
@ 2020-09-16 19:45 ` Juri Linkov
  2020-09-16 23:49   ` Tak Kunihiro
  1 sibling, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2020-09-16 19:45 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: emacs-devel

> I have an impression that relative to Emacs's capability, mouse support
> is not as good as expected.
>
> - Horizontal scroll by wheel is supported.

Please explain how horizontal scroll by wheel is supported.
I tried to use Shift-wheel like in other apps,
but it doesn't scroll horizontally.

> - Moving text using mouse is supported.

Also please explain how moving text using mouse is supported.
I tried to drag the selection with mouse-1,
but it doesn't move text.

> * Contextual menu is not supported yet.
>
> I think that depending on a thing at mouse event (file, dir, or URL),
> choice of operation should be popped up.  When there is no suggestion,
> `Edit' menu should be popped up.  Also, by click on mode-line, buffer
> list should be popped up.
>
> I am using a global minor mode `poplife-mode' that puts commands on
> mouse-3.  I attach a file with poplife-mode to show the idea.

Thanks, this is a good starting point for adding contextual menu.
I tried poplife-mode, and it pops up the menu on mouse-3,
but it seems only when there is the selection already,
i.e. it doesn't pop up the menu when nothing is selected.
Is this intended to work this way?



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-16 19:35         ` Juri Linkov
@ 2020-09-16 23:10           ` Dmitry Gutov
  2020-09-17  3:58           ` Richard Stallman
  1 sibling, 0 replies; 112+ messages in thread
From: Dmitry Gutov @ 2020-09-16 23:10 UTC (permalink / raw)
  To: Juri Linkov, Eli Zaretskii
  Cc: philipk, rms, spacibba, emacs-devel, self, arthur.miller, ghe,
	drew.adams

On 16.09.2020 22:35, Juri Linkov wrote:
>>> Mouse support is poor in Emacs, this is the reason
>>> why I don't use the mouse in Emacs.  More below:
>> "Poor"? the below just says that other applications (which ones?) do
>> it slightly differently, that's all.  I don't see how what you say
>> justifies the "poor" part.
> Yes, this is subjective, but while I use the mouse in other apps,
> every time I try to use the mouse in Emacs, I can't make any sense of
> default mouse bindings mess, so have to resort to the keyboard (where
> Emacs keybindings are far superior to other apps).

Likewise.

I wonder how much of the "we only use keyboard" echos comes from the 
mouse bindings not being useful.

Like, if you want the context menu, you have to press Ctrl on the 
keyboard anyway. Might as well invoke the command from the keyboard 
entirely.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-16 19:45 ` Juri Linkov
@ 2020-09-16 23:49   ` Tak Kunihiro
  2020-09-17  2:33     ` Tak Kunihiro
  2020-09-17  7:43     ` Juri Linkov
  0 siblings, 2 replies; 112+ messages in thread
From: Tak Kunihiro @ 2020-09-16 23:49 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 国広卓也, emacs-devel

>> - Horizontal scroll by wheel is supported.
>> - Moving text using mouse is supported.

> Please explain how horizontal scroll by wheel is supported.
> Also please explain how moving text using mouse is supported.

Try something like this.

(setq mouse-wheel-tilt-scroll t)
(setq mouse-drag-and-drop-region 'meta)

>> * Contextual menu is not supported yet.
>> 
>> I think that depending on a thing at mouse event (file, dir, or URL),
>> choice of operation should be popped up.  When there is no suggestion,
>> `Edit' menu should be popped up.  Also, by click on mode-line, buffer
>> list should be popped up.
>> 
>> I am using a global minor mode `poplife-mode' that puts commands on
>> mouse-3.  I attach a file with poplife-mode to show the idea.
> 
> Thanks, this is a good starting point for adding contextual menu.
> I tried poplife-mode, and it pops up the menu on mouse-3,
> but it seems only when there is the selection already,
> i.e. it doesn't pop up the menu when nothing is selected.
> Is this intended to work this way?

That’s not intended behavior!
I found that for unknown reason, poplife-mode does not overwrite 
[mouse-3] started with emacs -Q.  I’ll fix it and come back
soon while the topic is hot.




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-16 23:49   ` Tak Kunihiro
@ 2020-09-17  2:33     ` Tak Kunihiro
  2020-09-17  7:43     ` Juri Linkov
  1 sibling, 0 replies; 112+ messages in thread
From: Tak Kunihiro @ 2020-09-17  2:33 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 国広卓也, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 830 bytes --]

>>> * Contextual menu is not supported yet.
>>> 
>>> I think that depending on a thing at mouse event (file, dir, or URL),
>>> choice of operation should be popped up.  When there is no suggestion,
>>> `Edit' menu should be popped up.  Also, by click on mode-line, buffer
>>> list should be popped up.
>>> 
>>> I am using a global minor mode `poplife-mode' that puts commands on
>>> mouse-3.  I attach a file with poplife-mode to show the idea.
>> 
>> Thanks, this is a good starting point for adding contextual menu.
>> I tried poplife-mode, and it pops up the menu on mouse-3,
>> but it seems only when there is the selection already,
>> i.e. it doesn't pop up the menu when nothing is selected.
>> Is this intended to work this way?

I fixed it and confirm with Emacs -Q.  Can you try again to see
the approach to start with?


[-- Attachment #2: poplife.el --]
[-- Type: application/octet-stream, Size: 62823 bytes --]

;;; poplife.el --- Pop choices up on mouse click

;; Copyright (C) 2017-2020 Tak Kunihiro

;; Author: Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>
;; Package-Requires: ((emacs "24.4"))
;; Keywords: mouse
;; Version: 1.0
;; Package-Version: 20200917.1125

;; This file is NOT part of GNU Emacs.

;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;; Usage:
;;
;; To interactively toggle the mode:
;;
;;   M-x poplife-mode RET
;;
;; To make the mode permanent, put these in your init file:
;;
;;   (require 'poplife)
;;   (poplife-mode 1)

;;; Commentary:
;;
;; This package pops context menu triggered by right click.  On a
;; click, depending on a thing under the mouse event, (1) FILE menu
;; (2) DIR menu, (3) WORD menu, (4) URL menu, (5) INFO menu, (6) HELP
;; menu, or (7) EDIT menu will be popped.  The EDIT menu lets you copy
;; and paste only using mouse.  As an option, the EDIT menu lets you
;; visit buffers, frames, bookmarks, and files.  The seven menus
;; are detailed as below.
;;
;; (1) FILE menu -- Pop how-to-open-a-file menu.
;; (2) DIR menu  -- Pop files in default-directory.
;; (3) WORD menu -- Pop word candidates when word under a mouse event is not correct.
;; (4) URL menu  -- Pop how-to-open-an-url menu.
;; (5) INFO menu -- Pop how-to-open-Info menu.
;; (6) HELP menu -- Pop how-to-open-Help menu.
;; (7) EDIT menu -- Pop basic edition-commands, optional edition-commands,
;;                  and visiting menus.  Details are shown below.
;;
;;  Basic edition-commands are defined by `poplife-mouse-edit-cmd-0'.
;;  Optional edition-commands are defined by
;;  `poplife-mouse-edit-cmd-1' with format similar to
;;  `recentf-menu-items-for-commands'.
;;
;;  DIR menu to visit files in default-directory is included by
;;  default.  To include a series of visiting menus in EDIT menu, set
;;  each item of `poplife-mouse-edit-cottager' to non-nil, as listed
;;  below.
;;
;;   :buffer     List buffers by `global-buffers-menu-map'.
;;   :imenu      List table of contents of current buffer by iMenu.
;;   :frame      List frames by `global-buffers-menu-map'.
;;   :bookmark   List bookmarks by `bookmark-all-names'.
;;   :recentf    List recent files by `recentf-menu-elements'.
;;
;;  To reduce overhead, FILE menu is not shown when file-remote-p is
;;  non-nil.  To reduce overhead by a remote file that was once opened
;;  by Tramp and stored in the list for recentf, configure a variable
;;  `recentf-exclude'.

;;; References:

;; * Contextual menu
;; https://lists.gnu.org/archive/html/emacs-devel/2020-09/msg01277.html
;;
;; * Paste text with erasing active region.
;;
;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2017-07/msg00086.html
;; http://lists.gnu.org/archive/html/emacs-devel/2017-07/msg00796.html
;;
;; * Pop menu up by long-click
;;
;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00267.html
;;
;; * Following codes from Emacs core are useful for development.
;;
;; (define-key global-map [mouse-3] menu-bar-edit-menu)
;; (popup-menu menu-bar-edit-menu)
;; (popup-menu (mouse-menu-bar-map))
;; (popup-menu (mouse-menu-major-mode-map)) ; C-mouse-3
;; (popup-menu menu-bar-bookmark-map)
;; (popup-menu global-buffers-menu-map)
;; (define-key global-map [mouse-3] 'mouse-buffer-menu)
;; (buffer-menu-open)

;;; Templates of keymap:
;;
;; This package integrates keymaps from imenu, menu-bar, bookmark, and
;; recentf.  They are converted to easymenu from standard keymap.
;; Typical easymenu and standard keymap are shown below for
;; convenience.
;;
;; (label
;;  [label callback]
;;  (label
;;   [label callback]
;;   ["--"  ignore]
;;   [label callback])
;;  [label callback])
;;
;; (keymap
;;  label
;;  (symbol menu-item label callback)
;;  [(label lambda nil (interactive) commands)
;;   (label keymap
;;          (symbol menu-item label callback)
;;          (symbol menu-item label callback))
;;   (label lambda nil (interactive) commands)]
;;  (symbol "--")
;;  (symbol menu-item label
;;          (keymap label
;;                  (symbol menu-item label callback)
;;                  (symbol menu-item label callback)))
;;  (symbol menu-item label callback))

;;; Code:
(defvar poplife-context-candidates
  '(poplife-mouse-help-menu             ; HELP menu
    poplife-mouse-info-menu             ; INFO menu
    poplife-mouse-file-menu             ; FILE menu
    poplife-mouse-dir-menu              ; DIR menu
    poplife-mouse-word-menu             ; WORD menu
    poplife-mouse-url-menu              ; URL menu
    ;; menu-bar-edit-menu    ; EDIT menu (default)
    poplife-mouse-edit-menu)            ; EDIT menu
  "List of candidates for context menu.
Candidates are function or keymap.  They will be evaluated in the
order of the list.  A function should accept mouse EVENT, and
return keymap or nil.  The last candidate should return valid
keymap.")

(defvar poplife-mouse-edit-cmd-0 '(cut copy paste select-paste paste-from-menu clear mark-whole-buffer)
  "Basic edition-commands in edit menu.
Items must be one listed in `menu-bar-edit-menu'.")

(defvar poplife-mouse-edit-cmd-1
  (list
   ["Close"
    (lambda () (interactive)
      (if (one-window-p)
          (if (> (length (visible-frame-list)) 1)
              (call-interactively 'delete-frame)
            (kill-buffer (window-buffer))) ; (quit-window)
        (delete-window)))
    :help "Remove this window or this frame, or kill this buffer"
    :visible (not (region-active-p))
    :active t]
   ;; ["Spell-Check"
   ;;  flyspell-correct-word-before-point
   ;;  :help "Spell check word at point"
   ;;  :visible (and (fboundp 'flyspell-correct-word-before-point)
   ;;                (not (region-active-p)))
   ;;  :active t]
   ["Spell-Check"
    ispell-region
    :help "Spell check selected text"
    :visible (region-active-p)
    :active t]
   ;; ["Search Web"
   ;;  (lambda () (interactive)
   ;;    (let ((keyword (buffer-substring-no-properties (region-beginning) (region-end))))
   ;;      (switch-to-buffer-other-window (generate-new-buffer "*eww*"))
   ;;      (eww-mode)
   ;;      (eww keyword)))
   ;;  :help "Search selected text by online service"
   ;;  :visible (region-active-p)
   ;;  :active t]
   ["--"
    ignore
    :visible (region-active-p)
    :active t])
  "List of optional commands in edit map.") ; recentf-menu-items-for-commands

(defvar poplife-mouse-edit-cottager
  '(:imenu t :buffer t :frame t :bookmark t :recentf t)
  "Extra menus to be included in edit menu besides file.")
\f
(defvar poplife-file-max-menu-items 20
  "Maximum number of items in DIR menu.
See also `recentf-max-menu-items', `buffers-menu-max-size', and
`imenu-max-items'.")

(defvar poplife-file-recursive 1
  "Depth of directory scan on DIR menu.")

(defvar poplife-dir-do-not-scan-regexp "inbox"
  "Contents of directory matching this regexp will not be shown in DIR menu.
Instead contents of home directory are displayed.")

(defvar poplife-file-do-not-show-regexp
  "\\`\\.\\.?$\\|\\`#\\|\\.elc\\'\\|\\.exe\\'\\|\\`\\.[^e]\\|\\.lnk\\'\\|\\~\\'\\|\\`desktop\\.ini\\'\\|\\`\\.DS_store\\'\\|\\`\\.dropbox\\'\\|\\`auto\\'\\|\\`ntuser\\|\\`_master_\\|\\`_region_\\|\\.aux\\'\\|\\.bbl\\'\\|\\.blg\\'\\|\\.fdb_latexmk\\'\\|\\.fls\\'\\|\\.lof\\'\\|\\.lot\\'\\|\\.out\\'\\|\\.toc\\'\\|\\.synctex\\'\\|\\.ico\\'\\|\\`Thumbs\\.db\\'\\|\\`Icon"
  "Filenames matching this regexp will not be displayed in DIR menu.") ; dired-trivial-filenames, dired-omit-files

(defvar poplife-file-do-not-open-regexp
  "\\.pdf\\'\\|\\.doc\\'\\|\\.docx\\'\\|\\.xls\\'\\|\\.xlsx\\'\\|\\.ppt\\'\\|\\.pptx\\'\\|\\.jpg\\'\\|\\.png\\'\\|\\.tif\\'\\|\\.tiff\\'\\|\\.bmp\\'\\|\\.aif\\'\\|\\.wav\\'\\|\\.7z\\'\\|\\.tar\\'\\|\\.dll\\'\\|\\.zip\\'\\|\\.info\\'\\|\\.igpi\\'\\|\\.ttf\\'\\|\\.otf\\'\\|\\.pkg\\'\\|\\.exe\\'"
  "Filenames matching this regexp will be displayed in DIR menu and open by `poplife-func-find-file-by-default-app'.")

(defvar poplife-func-find-file 'find-file
  "Function to visit a file, and a Recentf element.
Depending on context, this is internally overwritten by
`find-file', `find-file-other-window', and
`find-file-other-frame'.  This is referred to visit a buffer, an
imenu element, and a bookmark element via
`poplife-func-switch-to-buffer'.  A buffer is visited by
`menu-bar-select-buffer-function' on `global-buffers-menu-map'.
An imenu element is always visited on current buffer.  A bookmark
element is visited by `display-func' on `bookmark-jump'.")

(defvar poplife-func-find-file-by-default-app 'poplife-find-file-by-default-app
  "Function to visit file by default application.")
\f
(require 'ffap)
(require 'easymenu)
(require 'info)

;;;###autoload
(define-minor-mode poplife-mode
  "A global minor-mode to show context menu by right click."
  :init-value nil
  :group 'mouse
  :global t
  :keymap (let ((map (make-sparse-keymap))
                (context-menu
                 `(menu-item "Context menu" poplife-context-menu
                             :filter ,(lambda (_) (poplife-context-menu (aref (this-command-keys) 0))))))
            ;; bug#27569 (gnus-read-ephemeral-emacs-bug-group 27569)
            ;; https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-07/msg00086.html
            ;; https://lists.gnu.org/archive/html/emacs-devel/2017-07/msg00757.html
            ;; https://lists.gnu.org/archive/html/emacs-devel/2017-07/msg00796.html
            ;; https://lists.gnu.org/archive/html/emacs-devel/2017-07/msg00840.html
            (define-key map [mouse-3] context-menu)
            (define-key map [drag-mouse-3] context-menu)
            (define-key map [C-down-mouse-1] #'ignore)
            (define-key map [C-mouse-1] context-menu)
            (define-key map [C-double-mouse-1] context-menu)
            (define-key map [C-triple-mouse-1] context-menu)
            (define-key map [C-drag-mouse-1] context-menu)
            (define-key map [remap buffer-menu-open] #'poplife-menu-open)
            ;; (define-key map [C-S-down-mouse-1] 'mouse-buffer-menu)
            ;; (define-key map [C-M-mouse-1] 'poplife-what-mouse-position)
            ;; (define-key mode-line-buffer-identification-keymap [mode-line mouse-3] #'poplife-pwd-menu-open)
            ;; (define-key mode-line-buffer-identification-keymap [mode-line mouse-1] #'poplife-buffer-menu-open)
            (define-key map [remap mode-line-previous-buffer] #'poplife-buffer-menu-open) ; mouse-1
            ;; (define-key map [remap mode-line-previous-buffer] #'poplife-global-mark-ring-menu-open) ; mouse-1
            (define-key map [remap mode-line-next-buffer] #'poplife-pwd-menu-open) ; mouse-3
            (define-key map [mode-line C-mouse-1] #'poplife-pwd-menu-open)
            (define-key map [mode-line M-mouse-1] #'poplife-pwd-menu-open) ; as if Mac
            map))

;; * How to implement into core
;;
;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00416.html

;; (defvar mouse-context-menu-function #'mouse-default-context-menu
;;   "Function that builds the context-menu.
;; Takes one argument (the EVENT that requests the menu) and should return
;; a list of menu items.")

;; (defun mouse-default-context-menu (event)
;;   "Return default context menu."
;;   (interactive "e")
;;   menu-bar-edit-menu)

;; (defun mouse-context-menu (event)
;;   "Open up the context menu."
;;   (interactive "@e")
;;   (let* ((menu-items (funcall mouse-context-menu-function event))
;;          (keymap `(keymap ,(apply #'vector menu-items))))
;;     (popup-menu keymap event)))

;; (define-key global-map [mouse-3] 'mouse-context-menu)

(defun poplife-menu-open ()
  "Start key navigation of the poplife menu.
This is the keyboard interface to \\[poplife-context-menu].  This is
fork of `buffer-menu-open'."
  (interactive)
  (popup-menu (poplife-context-menu last-nonmenu-event)
              (posn-at-x-y 0 0 nil t)))

(defun poplife-context-menu (event)
  "Return key's definition depending on thing at mouse click EVENT.
Items in `poplife-context-candidates' are examined sequentially.
See `define-key' for the key's definition"
  ;; ~/.emacs.d/init.el ~/.emacs.d/ https://www.gnu.org/software/emacs/
  (when (fboundp 'secondary-selection-to-region) ; 26.1
    (secondary-selection-to-region)) ; When there is only secondary, turn it to region.
  (let ((candidates poplife-context-candidates)
        context-menu)
    (while (not context-menu)
      (let ((item (car candidates)))
        (setq candidates (cdr candidates))
        ;; See how dired-guess-shell-alist-user is used in dired-guess-default.
        (setq context-menu (cond ((fboundp item)
                                  (funcall item event))
                                 ((and (symbolp item)
                                       (keymapp (symbol-value item)))
                                  (symbol-value item))
                                 (t     ; else
                                  nil)))))
    context-menu))
;; (let ((foo (poplife-context-menu last-nonmenu-event))) (describe-variable 'foo))

(defun poplife-what-mouse-position (event)
  "Evaluate text properties under mouse click."
  (interactive "e")
  (with-output-to-temp-buffer "*Result*"
    (princ (format "Event was %S\n" event))
    (princ (format "Click was on face <%S>.\n"
                   (mouse-posn-property (event-start event) 'face)))
    (princ (format "Click was on dired-filename <%S>.\n"
                   (mouse-posn-property (event-start event) 'dired-filename)))))

(with-eval-after-load "help-mode"
  (button-type-put 'help-function-def 'help-function 'poplife-help-find-function))

(defvar poplife-help-switch-buffer-function 'pop-to-buffer
  "Function to display buffer in help-mode.
This can be `switch-to-buffer', `switch-to-buffer-other-window',
or `switch-to-buffer-other-frame'.")

(defun poplife-help-find-function (fun &optional file type)
  "Find object shown in help-mode."
  ;; This is fork of lambda function of 'help-function, that is
  ;; defined for a button type 'help-function-def in `help-mode.el'.
  (or file
      (setq file (find-lisp-object-file-name fun type)))
  (if (not file)
      (message "Unable to find defining file")
    (require 'find-func)
    (when (eq file 'C-source)
      (setq file
            (help-C-file-name (indirect-function fun) 'fun)))
    ;; Don't use find-function-noselect because it follows
    ;; aliases (which fails for built-in functions).
    (let ((location
           (find-function-search-for-symbol fun type file)))
      ;; (pop-to-buffer (car location))
      (funcall poplife-help-switch-buffer-function (car location)) ; Revised for poplife
      (run-hooks 'find-function-after-hook)
      (if (cdr location)
          (goto-char (cdr location))
        (message "Unable to find location in file")))))

(defun poplife-mouse-help-menu (event)
  "Return help-menu when thing at mouse click EVENT is button
with button type of 'help-function-def."
  (and
   (not (region-active-p))
   (let ((help-easymap
          (save-excursion
            (mouse-set-point event)
            ;; (text-properties-at (point))
            ;; '(push-button "/Applications/MacPorts/Emacs.app/Contents/Resources/lisp/button.el")
            ;; (push-button (point))
            ;; (help-button-action (button-at (point)))
            ;; (help-do-xref nil
            ;;   	(button-get (button-at (point)) 'help-function)
            ;;   	(button-get (button-at (point)) 'help-args))
            ;; (button-type (button-at (point)))
            (let ((button (button-at (point))))
              (when (and button
                         (eq (button-type button) 'help-function-def))
                (let* ((button-func (button-get button 'help-function))
                       (button-arg  (button-get button 'help-args))
                       (message (replace-regexp-in-string "[()\"]" "" (format "%S" button-arg) t t)))
                  (list
                   message
                   (vector "Open Function"
                           `(let* ((poplife-func-find-file 'find-file) ; switch-to-buffer
                                   (poplife-help-switch-buffer-function (poplife-func-switch-to-buffer)))
                              (help-button-action ,button))
                           :visible t :active t :help message)
                   ["--" ignore]
                   (vector "Open Function in Other Window"
                           `(let* ((poplife-func-find-file 'find-file-other-window) ; switch-to-buffer-other-window
                                   (poplife-help-switch-buffer-function (poplife-func-switch-to-buffer)))
                              (help-button-action ,button))
                           :visible t :active t :help message)
                   (vector "Open Function in Frame"
                           `(let* ((poplife-func-find-file 'find-file-other-frame) ; switch-to-buffer-other-frame
                                   (poplife-help-switch-buffer-function (poplife-func-switch-to-buffer)))
                              (help-button-action ,button))
                           :visible t :active t :help message))))))))
     (when help-easymap
       (easy-menu-create-menu (car help-easymap) (cdr help-easymap))))))
;; (poplife-mouse-help-menu last-nonmenu-event)

(defun poplife-info-node-at-point ()
  "Return a node reference at point.
Return non-nil if successful.  This is fork of
`Info-try-follow-nearest-node'."
  (let (file-or-node)
    (cond
     ((setq file-or-node (Info-get-token (point) "[hf]t?tps?://"
				                 "\\([hf]t?tps?://[^ \t\n\"`‘({<>})’']+\\)"))
      ;; (browse-url file-or-node)
      (setq file-or-node nil))
     ((setq file-or-node (Info-get-token (point) "\\*note[ \n\t]+"
				                 "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?"))) ; (system)Data format IONML
     ;; footnote
     ((setq file-or-node (Info-get-token (point) "(" "\\(([0-9]+)\\)"))
      (setq file-or-node nil))
     ;; menu item: node name
     ((setq file-or-node (Info-get-token (point) "\\* +" "\\* +\\([^:]*\\)::"))) ; What is DREAM?
     ;; menu item: node name or index entry
     ((Info-get-token (point) "\\* +" "\\* +\\(.*\\): ") ; FAQ
      (save-excursion
        (beginning-of-line)
        (forward-char 2)
        (setq file-or-node (Info-extract-menu-node-name nil (Info-index-node))))) ; (pmlfaq)
     ((setq file-or-node (Info-get-token (point) "File: " "File: \\([^,\n\t]*\\)")) ; pmlfaq.info
      (when (string-match "\\.info\\'" file-or-node)
        (string-match "\\`\\(.+\\)\\.info\\'" file-or-node) ; pmlfaq
        (setq file-or-node (format "(%s) Top" (match-string 1 file-or-node)))))) ; (pmlfaq) Top
    (when (and file-or-node
               (stringp Info-current-file)
               (not (string-match "\\`(.*)" file-or-node)))
      (setq file-or-node
            (format "(%s) %s"
                    (file-name-sans-extension
                     (file-name-nondirectory Info-current-file))
                    file-or-node))) ; see Info-copy-current-node-name
    file-or-node))

(defun poplife-mouse-info-menu (event)
  "Return info-menu when thing at mouse click EVENT is link."
  ;; see Info-try-follow-nearest-node
  (and
   (not (region-active-p))
   (let ((info-easymap
          (save-excursion
            (mouse-set-point event)
            (let ((file-or-node (poplife-info-node-at-point)))
              (when file-or-node
                (list
                 file-or-node
                 (vector "Open Info"
                         ;; `(info ,file-or-node)
                         `(info-setup
                           ,file-or-node
                           (switch-to-buffer (format "*info-%s*" ,file-or-node)))
                         :visible t :active t :help file-or-node)
                 ["--" ignore]
                 (vector "Copy Info"
                         `(progn (kill-new ,file-or-node) (message ,file-or-node))
                         :visible t :active t :help file-or-node)
                 (vector "Open Info in Other Window"
                         `(info-setup
                           ,file-or-node
                           (switch-to-buffer-other-window (format "*info-%s*" ,file-or-node)))
                         :visible t :active t :help file-or-node)
                 (vector "Open Info in Frame"
                         `(info-setup
                           ,file-or-node
                           (switch-to-buffer-other-frame (format "*info-%s*" ,file-or-node)))
                         :visible t :active t :help file-or-node)))))))
     (when info-easymap
       (easy-menu-create-menu (car info-easymap) (cdr info-easymap))))))
;; (let ((foo (poplife-mouse-info-menu last-nonmenu-event))) (describe-variable 'foo))
;; (popup-menu (poplife-mouse-info-menu last-nonmenu-event))

(defun poplife-mouse-file-menu (event)
  "Return file-menu when thing at mouse click EVENT is file.
The file is identified by `ffap-guesser'."
  (and
   (not (region-active-p))
   (let ((file-easymap
          (save-excursion
            (mouse-set-point event)
            (if (equal major-mode 'dired-mode)
                (and
                 (mouse-posn-property (event-start event) 'dired-filename)
                 (poplife-file-easymap (dired-get-file-for-visit) t))
              (let* ((ffap-url-regexp nil) (file (ffap-guesser))) ; ffap-at-mouse
                ;; ~/.emacs.d/init.el  ~/.emacs.d/  https://www.gnu.org/software/emacs/
                ;; ffap-guesser cannot guess file with asterisk such as "bookmark.html*"
                (when (and file
                           (not (ffap-file-remote-p file)))
                  (poplife-file-easymap file t)))))))
     (when file-easymap
       (easy-menu-create-menu (car file-easymap) (cdr file-easymap))))))

(defun poplife-mouse-dir-menu (event)
  "Return dir-menu when thing under mouse cursor on EVENT is directory.
The directory is identified by `ffap-guesser'."
  (and
   (not (region-active-p))
   (if (equal major-mode 'dired-mode)
       (mouse-posn-property (event-start event) 'dired-filename)
     t)
   (let ((dir-easymap (save-excursion
                        (mouse-set-point event)
                        ;; ~/.emacs.d/init.el  ~/.emacs.d/  https://www.gnu.org/software/emacs/
                        (let* ((ffap-url-regexp nil) (dir (ffap-guesser)))
                          (when (and dir
                                     (not (ffap-file-remote-p dir)))
                            (poplife-dir-easymap (file-name-as-directory dir) t))))))
     (when dir-easymap
       (easy-menu-create-menu (car dir-easymap) (cdr dir-easymap))))))

(defun poplife-mouse-word-menu (event)
  "Return 'flyspell-correct-word when word under mouse cursor on EVENT is incorrect."
  (and
   (not (region-active-p))
   ;; Check face by (what-cursor-position t) or C-u C-x =.
   (let ((faces-at-point (mapcar (lambda (xxx) (overlay-get xxx 'face))
                                 (overlays-at (posn-point (event-start event))))))
     (when (or (member 'flyspell-incorrect faces-at-point)
               (member 'flyspell-duplicate faces-at-point))
       #'flyspell-correct-word)))) ; flyspell-correct-word-before-point

(defun poplife-mouse-url-menu (event)
  "Return url-menu when thing under mouse cursor on EVENT is url.
The url is identified by `thing-at-point-url-at-point'."
  (and
   (not (region-active-p))
   (let ((url-easymap
          (save-excursion
            (mouse-set-point event)
            ;; ~/.emacs.d/init.el  ~/.emacs.d/  https://www.gnu.org/software/emacs/
            (let ((url (or (thing-at-point-url-at-point t) ; browse-url-at-mouse
                           (get-text-property (point) 'shr-url)
                           (get-text-property (point) 'image-url))))
              (when url
                (list (let ((url (replace-regexp-in-string "https?://" "" url))
                            (len 40)) ; Make URL short
                        (if (> (length url) len)
                            (concat (substring url 0 (1- len)) "...")
                          url))
                      (vector "Open Link"
                              `(eww ,url)
                              :visible t :active t :help url)
                      ["--" ignore]
                      (vector "Copy Link"
                              `(progn (kill-new ,url) (message "Copied %s" ,url))
                              :visible t :active t :help url)
                      (vector "Open Link in Other Window"
                              ;; eww-browse-url, eww-open-in-new-buffer
                              `(progn
                                 (switch-to-buffer-other-window (generate-new-buffer "*eww*"))
                                 (eww-mode)
                                 (eww ,url))
                              :visible t :active t :help url)
                      (vector "Open Link in Frame" ; "Open in Frame"
                              `(progn
                                 (switch-to-buffer-other-frame (generate-new-buffer "*eww*"))
                                 (eww-mode)
                                 (eww ,url))
                              :visible t :active t :help url)
                      (vector "Open Link by Default App" ; "Open Link using browse-url"
                              `(let ((browse-url-browser-function 'browse-url-default-browser))
                                 (browse-url ,url))
                              :visible t
                              :active t
                              :help url)))))))
     (when url-easymap
       (easy-menu-create-menu (car url-easymap) (cdr url-easymap))))))

(defun poplife-mouse-edit-menu (event)
  "Define edit menu on mouse click EVENT."
  ;; initialize
  (when (plist-get poplife-mouse-edit-cottager :bookmark)
    (require 'bookmark))
  (when (plist-get poplife-mouse-edit-cottager :recentf)
    (require 'recentf)
    (recentf-mode 1))
  (when (plist-get poplife-mouse-edit-cottager :imenu)
    (require 'imenu))

  (save-excursion
    (mouse-set-point event)
    (let ((map (make-sparse-keymap "Edit")))
      (unless (region-active-p)
        ;; Visit buffers with iMenu
        (when (plist-get poplife-mouse-edit-cottager :buffer)
          (easy-menu-add-item map nil (poplife-buffer-easymap)))

        ;; Visit frames
        (when (plist-get poplife-mouse-edit-cottager :frame)
          (easy-menu-add-item map nil (poplife-frame-easymap)))

        ;; Visit bookmarks
        (when (plist-get poplife-mouse-edit-cottager :bookmark)
          (easy-menu-add-item map nil (poplife-bookmark-easymap)))

        ;; Visit recent files
        (when (plist-get poplife-mouse-edit-cottager :recentf)
          (easy-menu-add-item map nil (poplife-recentf-easymap)))

        ;; Visit directory
        (unless (file-remote-p default-directory)
          (let ((dir-map (poplife-dir-easymap default-directory)))
            (setcar dir-map "File")      ; instead of ".emacs.d/"
            (easy-menu-add-item map nil dir-map)))

        ;; Separator
        (define-key map [separator-edit] menu-bar-separator))

      ;; Option -- TODO: Fix location of item with recursive structure.
      (when poplife-mouse-edit-cmd-1
        (dolist (item poplife-mouse-edit-cmd-1)
          (if (vectorp item)
              (let* ((item (append item nil)) ; Convert vector to list.
                     (nickname (car item)))
                (bindings--define-key map (vector (easy-menu-make-symbol nickname))
                  (append (list 'menu-item nickname) (cdr item))))
            (easy-menu-add-item map nil item)))) ; with recursive structure

      ;; Main
      (dolist (item (reverse (cdr menu-bar-edit-menu)))
        (when (and (listp item)
                   (member (car item) poplife-mouse-edit-cmd-0)) ; pick some
          (bindings--define-key map (vector (car item)) (cdr item))))

      map)))
;; (let ((foo (poplife-mouse-edit-menu last-nonmenu-event))) (describe-variable 'foo))
\f
;;; iMenu
(defun poplife-imenu-easymap (&optional submenu)
  "Define easymenu to list index by iMenu.
When SUBMENU is non-nil, this returns an easymenu with multiple actions."
  ;; TODO: Selection of menu does not move point when called from
  ;; click on mode-line.
  (let* ((imenu-max-items poplife-file-max-menu-items) ; 25
         (map-0 (ignore-errors
                  (imenu--split-menu
                   (delq nil (cdr (imenu--make-index-alist t))) ; remove "*Rescan*"
                   (buffer-name))))
         (map (poplife-imenu-alist-to-easymap (car map-0) (cdr map-0)
                                            'imenu--menubar-select)))
    (when (>= (length map) 2) ; Return map only when map is with useful items.
      (if submenu
          (poplife-imenu-submenufy-easymap map)
        (let ((map-rev (reverse map)))
          (push (vector "More..."
                        '(popup-menu (poplife-imenu-easymap t)
                                     (popup-menu-normalize-position last-nonmenu-event)))
                map-rev)
          (reverse map-rev))))))
;; (let ((foo (poplife-imenu-easymap))) (describe-variable 'foo))
;; (let* ((poplife-func-find-file 'find-file-other-frame) (foo (poplife-imenu-easymap))) (describe-variable 'foo))
;; (let ((foo (poplife-imenu-easymap t))) (describe-variable 'foo))
;; (popup-menu (poplife-imenu-easymap))

(defun poplife-imenu-alist-to-easymap (title alist &optional cmd)
  "Create easymenu from alist by iMenu to display index by CMD.
This is fork of `imenu--create-keymap'."
  (let (map)
    (dolist (item alist)
      (push (cond
             ((imenu--subalist-p item)
              (poplife-imenu-alist-to-easymap (car item) (cdr item) cmd))
             (t
              (if cmd
                  (vector (car item)
                          (list 'let
                                '((display-buffer--other-frame-action ; hack for switch-to-buffer-other-frame
                                   '((display-buffer-pop-up-frame)
                                     (inhibit-same-window . t))))
                                `(funcall (quote ,(poplife-func-switch-to-buffer)) ,(current-buffer))
                                `(,cmd (quote ,item))))
                (list 'quote item))))
            map))
    (setq map (reverse map))
    (push title map)
    map))

(defun poplife-imenu-submenufy-easymap (map)
  "Return easymenu of iMenu MAP with recursive structure."
  (let (map-1)
    (dolist (item map)
      (push (cond
             ((listp item) ; when an item is a list
              (poplife-imenu-submenufy-easymap item))
             ((vectorp item) ; when an item is vector
              (poplife-imenu-elt-easymap item))
             (t item)) ; else such for "poplife.el"
            map-1))
    (reverse map-1)))

(defun poplife-imenu-elt-easymap (elt)
  "Return easymenu of iMenu ELT with submenu added."
  (let ((label (aref elt 0)) ; "poplife-mouse-edit-cottager"
        (cmd (nth 3 (aref elt 1))) ; (imenu--menubar-select '("poplife-mouse-edit-cottager" . #<marker at 3207 in poplife.el>))
        (buf (current-buffer))) ; #<buffer poplife.el>
    (list label
          (vector "Open" `(progn (switch-to-buffer ,buf) ,cmd))
          ["--" ignore]
          (vector "Open in Other Window" `(progn (switch-to-buffer-other-window ,buf) ,cmd))
          (vector "Open in Frame" `(progn (pop-to-buffer ,buf '((display-buffer-pop-up-frame) (inhibit-same-window . t))) ,cmd)))))
\f
;;; Frame
(defun poplife-frame-easymap ()
  "Define easymenu to list frames."
  (let ((frame-vec (nth 2 (cadddr (assoc 'frames global-buffers-menu-map))))
        (poplife-func-find-file 'find-file-other-frame)
        map)
    (dolist (elt (append frame-vec nil)) ; Convert vector to list.
      (let* ((nickname (car elt))
             (cmd (nth 4 elt))
             (frame (cadr cmd)))
        (push (vector nickname cmd :active (not (equal frame (selected-frame)))) map)))
    (push ["New" (progn (make-frame-command) (menu-find-file-existing))] map)
    (push ["--" ignore] map)
    (when (plist-get poplife-mouse-edit-cottager :buffer)
      (push (poplife-buffer-easymap) map))
    (when (plist-get poplife-mouse-edit-cottager :bookmark)
      (push (poplife-bookmark-easymap) map))
    (when (plist-get poplife-mouse-edit-cottager :recentf)
      (push (poplife-recentf-easymap) map))
    (unless (file-remote-p default-directory)
      (let ((dir-map (poplife-dir-easymap default-directory)))
        (setcar dir-map "File")        ; "Directory"
        (push dir-map map)))
    (setq map (reverse map))
    (push "Frames" map)
    map))
;; (let ((foo (poplife-frame-easymap))) (describe-variable 'foo))
\f
;;; Buffer
(defun poplife-buffer-easymap (&optional submenu)
  "Define easymenu to list buffers.
This extracts list of buffers from `global-buffers-menu-map'.
When SUBMENU is non-nil, this returns an easymenu with multiple actions."
  (let ((buffer-list (poplife-buffer-list))
        ;; (poplife-func-find-file 'find-file) ; 20190128.1647
        (menu-bar-select-buffer-function (poplife-func-switch-to-buffer))
        map)

    ;; Add submenu on request.
    (dolist (elt buffer-list)
      (push (poplife-buffer-elt-easymap elt submenu) map))

    ;; Add option.
    (push (vector "More..."
                  '(let (buffer-full-map)
                     (let (buffers-menu-max-size)
                       (menu-bar-update-buffers t)
                       (setq buffer-full-map
                             (poplife-buffer-easymap t)))
                     (menu-bar-update-buffers t)
                     (popup-menu buffer-full-map
                                 (popup-menu-normalize-position last-nonmenu-event)))
                  :visible t
                  :active (not submenu))
          map)

    ;; Reverse map and add a key.
    (setq map (reverse map))
    (push "Buffers" map)

    map))
;; (let ((foo (poplife-buffer-easymap))) (describe-variable 'foo))
;; (let ((foo (poplife-buffer-easymap t))) (describe-variable 'foo))

(defun poplife-buffer-list-on-menu ()
  "Return a list of buffers on `global-buffers-menu-map'."
  ;; on 25.2, pick 4th out of 5 items
  ;; ("menu-bar.el.gz  " lambda nil (interactive) (funcall menu-bar-select-buffer-function #<buffer menu-bar.el.gz>))
  ;; on 24.5, pick 5th out of 6 items
  ;; ("menu-bar.el.gz  " (nil) lambda nil (interactive) (funcall menu-bar-select-buffer-function #<buffer menu-bar.el.gz>))
  (let ((len245 6)
        (nth252 4)
        (nth245 5)
        (buffers-menu (nth 2 global-buffers-menu-map))
        ;; nickname-list
        buffer-list)
    (dolist (elt (append buffers-menu nil)) ; Convert vector to list.
      ;; (push (car elt) nickname-list)
      (push (nth 2 (nth (if (equal (length elt) len245)
                            nth245
                          nth252)
                        elt)) buffer-list))
    (reverse buffer-list)))
;; (let ((foo (poplife-buffer-list-on-menu))) (describe-variable 'foo))
;; (let ((foo (buffer-list))) (describe-variable 'foo))

(defun poplife-buffer-list ()
  "Return a list of buffers."
  (delete-dups (append (list (current-buffer))
                       (poplife-buffer-list-with-marks)
                       (poplife-buffer-list-on-menu))))
;; (let ((foo (poplife-buffer-list))) (describe-variable 'foo))

(defun poplife-buffer-list-with-marks ()
  "Return a list of buffers on `global-mark-ring'."
  (let (buffer-list buf)
    (dolist (marker (reverse global-mark-ring))
      (when (setq buf (marker-buffer marker)) ; See `pop-global-mark'
        (push buf buffer-list)))
    buffer-list))
;; (let ((foo (poplife-buffer-list-with-marks))) (describe-variable 'foo))

(defun poplife-buffer-elt-easymap (buffer &optional submenu)
  "Define easymenu for a BUFFER.
When SUBMENU is non-nil, this returns an easymenu with multiple
actions."
  (let ((nickname (buffer-name buffer)))
    (if (not submenu)
        (let (imenu-map)
          (if (and (plist-get poplife-mouse-edit-cottager :imenu)
                   (equal (current-buffer) buffer)
                   (setq imenu-map (poplife-imenu-easymap)))
              imenu-map
            (vector nickname `(funcall (quote ,menu-bar-select-buffer-function) ,buffer)
                    :active `(not (equal ,(current-buffer) ,buffer)))))
      (list nickname
            (vector "Open" `(switch-to-buffer ,buffer) :active `(not (equal ,(current-buffer) ,buffer)))
            ["--" ignore]
            (vector "Open in Other Window" `(switch-to-buffer-other-window ,buffer))
            (vector "Open in Frame" `(switch-to-buffer-other-frame ,buffer))))))
\f
;;; Recentf
(defun poplife-recentf-easymap (&optional submenu)
  "Define easymenu to list recentf.
When SUBMENU is non-nil, this returns an easymenu with multiple actions."
  (let (map
        (recentf-menu-shortcuts 0)
        (elements (recentf-menu-elements recentf-max-menu-items)))
    ;; See `recentf-make-menu-items'.
    (setq map (mapcar (lambda (elt)
                        (funcall 'poplife-recentf-elt-easymap elt submenu))
                      (recentf-apply-menu-filter
                       recentf-menu-filter
                       elements)))
    (let ((map-rev (reverse map)))
      (push (vector "More..."
                    '(let ((recentf-max-menu-items recentf-max-saved-items))
                       (popup-menu (poplife-recentf-easymap t)
                                   (popup-menu-normalize-position last-nonmenu-event)))
                    :help "Show more Recentf"
                    :visible t
                    :active (not submenu))
            map-rev)
      (push ["--" ignore] map-rev)
      (push ["Edit..."
             recentf-edit-list
             :help "Manually remove files from the recent list"
             :active t]
            map-rev)
      ;; (push ["Save List Now"
      ;;        recentf-save-list
      ;;        :help "Save the list of recently opened files now"
      ;;        :active t]
      ;;       map-rev)
      (setq map (reverse map-rev)))
    (cons "Recent" map)))
;; (let ((foo (poplife-recentf-easymap))) (describe-variable 'foo))

(defun poplife-recentf-elt-easymap (elt &optional submenu)
  "Define easymenu to popup recentf item ELT.
When SUBMENU is non-nil, this returns an easymenu with multiple actions."
  ;; This is fork of `recentf-make-menu-item'.
  (let ((name (recentf-menu-element-item elt))
        (file (recentf-menu-element-value elt)))
    (if (recentf-sub-menu-element-p elt)
        (cons name (mapcar (lambda (elt) (funcall 'poplife-recentf-elt-easymap elt)) file)) ; for `recentf-arrange-by-dir'
      ;; (vector name
      ;;         `(,recentf-menu-action ,file) ; poplife-func-find-file
      ;;         :help (concat "Open " file)
      ;;         :active t)
      (let ((map
             (if (file-directory-p file)
                 (poplife-dir-easymap file submenu) ; directory
               (poplife-file-easymap file submenu)))) ; file
        (when (listp map)
          (setcar map name))
        map))))
\f
;;; Bookmark
(defun poplife-bookmark-easymap (&optional submenu)
  "Define easymenu to list bookmarks.
When SUBMENU is non-nil, this returns an easymenu with multiple actions."
  ;; TODO: On emacs-27.1 with smb, I see "tramp-error: Method ‘smb’ is
  ;; not known".
  (let ((map
         (list
          (vector "More..." '(popup-menu (poplife-bookmark-easymap t)
                                         (popup-menu-normalize-position last-nonmenu-event))
                  :visible t
                  :active (not submenu)
                  :help "Set a bookmark named inside a file.")
          ["--" ignore]
          ["Add..." bookmark-set :visible t :active (or (buffer-file-name) (eq major-mode 'dired-mode))
           :help "Set a bookmark named inside a file."]
          ["Edit..." bookmark-bmenu-list :visible t :active t
           :help "Display a list of existing bookmarks"]
          ;; ["Save List Now" bookmark-save :visible t :active t
          ;;  :help "Save currently defined bookmarks"]
          )))
    (dolist (bookmark (bookmark-all-names))
      (push (poplife-bookmark-elt-easymap bookmark submenu) map))
    (cons "Bookmark" map)))
;; (let ((foo (poplife-bookmark-easymap))) (describe-variable 'foo))
;; (let ((foo (poplife-bookmark-easymap t))) (describe-variable 'foo))

(defun poplife-bookmark-elt-easymap (bookmark &optional submenu)
  "Define easymenu to list a BOOKMARK.
When SUBMENU it non-nil, this returns an easymenu with multiple actions."
  (let (map)
    (if (not submenu)
        (let ((file (bookmark-get-filename bookmark)))
          (if (and (not (file-remote-p file)) ; when bookmark is directory
                   (file-exists-p file)
                   (file-directory-p file))
              (poplife-dir-easymap file submenu) ; offer DIR menu
            (vector bookmark
                    ;; `(bookmark-jump ,bookmark DISPLAY-FUNC)
                    `(bookmark-jump ,bookmark (quote ,(poplife-func-switch-to-buffer))) ; switch-to-buffer
                    :visible t
                    :active (not (string= ; gray the vising file out
                                  (and (buffer-file-name) (expand-file-name (buffer-file-name)))
                                  (expand-file-name (bookmark-get-filename bookmark))))
                    :help (format "Jump to %s" bookmark))))

      ;; (push (vector "Show Annotation..." `(bookmark-show-annotation ,bookmark) :visible t :active `(bookmark-get-annotation ,bookmark) :help bookmark) map)
      ;; (push (vector "Edit Annotation..." `(bookmark-edit-annotation ,bookmark) :visible t :help bookmark) map)
      (let ((annot-map (poplife-bookmark-annotation-easymap bookmark)))
        (if (vectorp annot-map) ; with no annotation and with "Add Annotation..."
            (push annot-map map)
          (dolist (annot-item (reverse (cdr annot-map)))
            (push annot-item map))
          (push ["--" ignore] map)
          (push (vector "Edit Annotation..." `(bookmark-edit-annotation ,bookmark) :visible t :help bookmark) map)))
      (push (vector "Delete..." `(and (y-or-n-p (format "Are you sure you want to delete a bookmark %s? " ,bookmark)) (bookmark-delete ,bookmark)) :visible t :help bookmark) map)
      (push (vector "Edit Location..." `(bookmark-relocate ,bookmark) :visible t :help bookmark) map)
      (push (vector "Rename..." `(bookmark-rename ,bookmark) :visible t :help bookmark) map)
      (push (vector "Insert Location" `(bookmark-locate ,bookmark) :visible t :help bookmark) map)
      (push (vector "Insert Contents" `(bookmark-insert ,bookmark) :visible t :help bookmark) map)
      (push (vector "Open by File Browser" `(poplife-find-location (expand-file-name (bookmark-get-filename ,bookmark))) :visible t :active t :help bookmark) map)
      (push (vector "Open in Frame" `(bookmark-jump ,bookmark 'switch-to-buffer-other-frame) :visible t :help bookmark) map)
      (push (vector "Open in Other Window" `(bookmark-jump-other-window ,bookmark) :visible t :help bookmark) map)
      (push ["--" ignore] map)
      (push (vector "Open" `(bookmark-jump ,bookmark) :visible t :help bookmark) map) ; switch-to-buffer
      (push (vector ".." `(let ((poplife-file-recursive ,poplife-file-recursive)
                                (poplife-func-find-file (quote ,poplife-func-find-file)))
                            (poplife-find-dir (expand-file-name "../" (bookmark-get-filename ,bookmark)) ,submenu))
                    :visible t :active t) map)
      (let ((annotation (bookmark-get-annotation bookmark)))
        (cons (format "%s%s" bookmark (if (and annotation (not (string-equal annotation ""))) "*" "")) map)))))
;; (let ((foo (poplife-bookmark-elt-easymap "poplife.el\\site-lisp"))) (describe-variable 'foo))
;; (let ((foo (poplife-bookmark-elt-easymap "poplife.el\\site-lisp" t))) (describe-variable 'foo))

(defvar poplife-bookmark-annotation-detail-flag t
  "Show full contents of annotation in popup-menu.")

(defun poplife-bookmark-annotation-easymap (bookmark)
  "Define easymenu to list annotation."
  (let ((annot (bookmark-get-annotation bookmark))
        (annot-column 36)) ; 36 is arbitrary number or (length "Open in Other Window")
    (if (and annot (not (string-equal annot "")))
        (if poplife-bookmark-annotation-detail-flag
            (let ((lines (poplife-split-string annot annot-column))
                  map)
              (dolist (line (reverse lines))
                (push (vector line `(bookmark-edit-annotation ,bookmark) :visible t :active t :help bookmark) map))
              (cons "Edit Annotation..." map))
          (let (annot-name)
            (setq annot-name (format "Edit Annotation `%s'..." (if (> (length annot) annot-column) (substring annot 0 annot-column) annot)))
            (vector annot-name `(bookmark-edit-annotation ,bookmark) :visible t :active t :help bookmark)))
      (vector "Add Annotation..." `(bookmark-edit-annotation ,bookmark) :visible t :active t :help bookmark))))

(defun poplife-split-string (string fill-length)
  "Split STRING into list of string.
Argument FILL-LENGTH determines length of each line."
  (setq string (replace-regexp-in-string
                (rx (* (any " \t\n")) eos) "" string)) ; Chomp text.
  (with-temp-buffer
    (insert string)
    (let ((fill-column fill-length) ; Replace text.
          (find-repl-list '(("\\`\\'" . " ") (" +" . " ")))) ; Avoid having "--" on menu.
      (fill-region (point-min) (point-max))
      (dolist (find-repl find-repl-list)
        (goto-char (point-min))
        (while (re-search-forward (car find-repl) nil t)
          (replace-match (cdr find-repl)))))
    (split-string (buffer-string) "\n"))) ; List of text lines.
\f
;;; File
(defun poplife-file-easymap (file &optional submenu)
  "Define easymenu to list a FILE.
When SUBMENU it non-nil, this returns an easymenu with multiple actions."
  (setq file (expand-file-name file))
  (and (not (file-directory-p file))
       (let* (map
              (file-nickname (file-name-nondirectory file))
              (file-readable-flag (and (file-regular-p file)
                                       (file-readable-p file)))
              (open-file-flag (and (not (string-match-p poplife-file-do-not-open-regexp file))
                                   file-readable-flag))
              (dir (file-name-directory file))
              (open-dir-flag (and (file-directory-p dir)
                                  (file-accessible-directory-p dir))))
         (if (not submenu)
             (vector file-nickname
                     `(funcall (if ,open-file-flag
                                   (quote ,poplife-func-find-file)
                                 (quote ,poplife-func-find-file-by-default-app)) ,file)
                     :active (and file-readable-flag ; gray the vising file out
                                  (not (string=
                                        (and (buffer-file-name) (expand-file-name (buffer-file-name)))
                                        file)))
                     :help file)
           (push (vector "Open with File Browser" `(poplife-find-location ,file)
                         :visible t
                         :active open-dir-flag
                         :help dir) map)
           (push (vector "Open with Default App" `(,poplife-func-find-file-by-default-app ,file)
                         :visible t
                         :active t
                         :help file) map)
           (push (vector "Open and Bookmark..." `(progn (find-file ,file) (bookmark-set))
                         :visible (fboundp 'bookmark-set)
                         :active open-file-flag
                         :help "Open and Bookmark this file") map)
           (push (vector "Open in Frame" `(find-file-other-frame ,file)
                         :visible t
                         :active open-file-flag
                         :help file) map)
           (push (vector "Open in Other Window" `(find-file-other-window ,file)
                         :visible t
                         :active open-file-flag
                         :help file) map)
           (push ["--" ignore] map)
           (push (vector "Open" `(find-file ,file)
                         :visible t
                         :active (and open-file-flag ; gray the vising file out
                                      (not (string=
                                            (and (buffer-file-name) (expand-file-name (buffer-file-name)))
                                            file)))
                         :help file) map)
           (push (vector ".." `(let ((poplife-file-recursive ,poplife-file-recursive)
                                     (poplife-func-find-file (quote ,poplife-func-find-file)))
                                 (poplife-find-dir ,dir, submenu))
                         :visible t :active open-dir-flag :help dir) map)
           (cons file-nickname map)))))
;; (let ((foo (poplife-file-easymap "~/.emacs.d/init.el"))) (describe-variable 'foo))
;; (let ((foo (poplife-file-easymap "~/.emacs.d/init.el" t))) (describe-variable 'foo))

(defun poplife-dir-easymap (dir &optional submenu depth)
  "Define easymenu to list files and directories in DIR.
When SUBMENU is non-nil, this returns an easymenu with multiple actions.
When DEPTH is more than 1, DIR is recursively scanned."
  (when (string-match-p poplife-dir-do-not-scan-regexp dir)
    (setq dir "~"))
  (setq dir (directory-file-name (expand-file-name dir))) ; Remove slash at the end.
  (or depth (setq depth 1))
  (let (map base-dir parent-dir rawfiles menufiles)
    (setq base-dir (file-name-as-directory (if (string= (file-name-nondirectory dir) "")
                                               dir ; In a case for "c:/"
                                             (file-name-nondirectory dir)))) ; Add slash at the end.
    (setq parent-dir (directory-file-name (file-name-directory dir)))
    ;; Obtain a file list.
    (setq rawfiles (ignore-errors (directory-files dir t)))
    ;; Filter out trivial files.
    (dolist (fullfile rawfiles)
      (let ((file-nickname (file-name-nondirectory fullfile)))
        (unless (string-match-p poplife-file-do-not-show-regexp file-nickname)
          (push fullfile menufiles))))
    ;; Limit number of menufiles
    (when (and poplife-file-max-menu-items
               (not submenu))
      (let ((nfile (length menufiles)))
        (setq menufiles (nthcdr (- nfile poplife-file-max-menu-items) menufiles))))
    ;; Add more menu.
    (push (vector "More..." ; Item to open a current directory.
                  `(let (poplife-file-max-menu-items
                         ;; (poplife-file-recursive ,(1+ poplife-file-recursive))
                         (poplife-file-recursive ,poplife-file-recursive)
                         (poplife-func-find-file (quote ,poplife-func-find-file)))
                     (poplife-find-dir ,dir t))
                  :active `(not ,submenu)
                  :visible t
                  :help dir)
          map)
    ;; Create map with files and directories.
    (dolist (fullfile menufiles)
      (let ((file-nickname (file-name-nondirectory fullfile)))
        (if (file-directory-p fullfile) ; when item is directory
            (push (if (or (>= depth poplife-file-recursive)
                          (not (file-accessible-directory-p fullfile)))
                      (vector (file-name-as-directory file-nickname)
                              `(let ((poplife-file-recursive ,poplife-file-recursive)
                                     (poplife-func-find-file (quote ,poplife-func-find-file)))
                                 (poplife-find-dir ,fullfile ,submenu))
                              :active (file-accessible-directory-p fullfile) :help fullfile)
                    (poplife-dir-easymap fullfile submenu (1+ depth))) ; recursive
                  map)
          (push ; when item is file (that is defined as `not a directory')
           (poplife-file-easymap fullfile submenu)
           map))))
    (push ["--" ignore] map)
    (push (if (not (or submenu poplife-dir-.-submenu)) ; (not submenu)
              ;; Single item
              (vector "." ; item to open current directory
                      `(,poplife-func-find-file ,dir)
                      ;; `(,poplife-func-find-file-by-default-app ,dir)
                      :visible t :active t :help dir)
            ;; Multiple items in submenu.
            (delq nil
                  (list "."
                        (vector "Open" ; item to open current directory
                                `(find-file ,dir) ; ,poplife-func-find-file
                                :visible t :active t :help dir)
                        ["--" ignore]
                        (vector "Open in Other Window"
                                `(find-file-other-window ,dir)
                                :visible t :active t :help dir)
                        (vector "Open in Frame"
                                `(find-file-other-frame ,dir)
                                :visible t :active t :help dir)
                        (vector "Open with Bookmarked..."
                                `(progn (find-file ,dir) (bookmark-set))
                                :visible (fboundp 'bookmark-set) :active t :help "Open and Add to Bookmarks")
                        (vector "Open by File Browser"
                                `(,poplife-func-find-file-by-default-app ,dir)
                                :visible t
                                :active t
                                :help dir))))
          map)
    (push (vector ".." ; Item to open parent directory.
                  `(let ((poplife-file-recursive ,poplife-file-recursive)
                         (poplife-func-find-file (quote ,poplife-func-find-file)))
                     (poplife-find-dir ,parent-dir ,submenu))
                  :active `(not (equal ,parent-dir ,dir)) :help parent-dir)
          map)
    (setq base-dir (replace-regexp-in-string "^@" "at" base-dir t t))
    (cons base-dir map)))
;; (let ((foo (poplife-dir-easymap "~/.emacs.d"))) (describe-variable 'foo))
;; (let ((foo (poplife-dir-easymap "~/.emacs.d" t))) (describe-variable 'foo))
;; (popup-menu (poplife-dir-easymap "~/.emacs.d"))
;; (popup-menu (poplife-dir-easymap "~/"))
;; (let ((foo (poplife-dir-easymap "c:/"))) (describe-variable 'foo))
;; (popup-menu (poplife-dir-easymap "c:/"))

(defvar poplife-dir-.-submenu t
  "Show always submenu for the current directory.")

(defun poplife-pwd-easymap (path &optional submenu)
  "Define easymenu to list directories that are above PATH."
  (setq path (directory-file-name (expand-file-name path))) ; remove slash
  (let* ((title (format (if (file-directory-p path)
                            "%s/"
                          "%s")
                        (file-name-nondirectory path)))
         dirpath
         map)
    (while (not (string= (file-name-nondirectory path) "" ))
      (setq dirpath (directory-file-name (file-name-directory path))) ; remove slash
      (push (vector (format "%s/" (file-name-nondirectory dirpath)) ; dirname
                    `(poplife-find-location ,path)) map)
      (setq path dirpath))
    (cons title (reverse map))))
;; (let ((foo (poplife-pwd-easymap "~/.emacs.d/site-lisp/poplife.el"))) (describe-variable 'foo))
;; (popup-menu (poplife-pwd-easymap default-directory))
;; (popup-menu (poplife-pwd-easymap "~/.emacs.d/site-lisp/"))

(defun poplife-pwd-menu-open (event)
  "Open popup-menu that opens a folder by File Browser."
  (interactive "e")
  (mouse-set-point event)
  (popup-menu
   (poplife-pwd-easymap (or buffer-file-name default-directory))))
;; (poplife-pwd-menu-open last-nonmenu-event)

(defun poplife-buffer-menu-open (event)
  "Open popup-menu that switches current buffer."
  (interactive "e")
  (mouse-set-point event)
  (popup-menu (poplife-buffer-easymap)))
;; (poplife-buffer-menu-open last-nonmenu-event)

\f
;;; Util
(defun poplife-func-switch-to-buffer ()
  "Return switch-to-buffer function that corresponds to `poplife-func-find-file'."
  (cdr (assoc poplife-func-find-file
              '((find-file . switch-to-buffer)
                (find-file-other-window . switch-to-buffer-other-window)
                (find-file-other-frame . switch-to-buffer-other-frame)))))
;; (let ((foo (poplife-func-switch-to-buffer))) (describe-variable 'foo))

(defun poplife-find-dir (dir &optional submenu)
  "Visit directory DIR using `popup-menu'.
When SUBMENU is non-nil, this offers multiple actions."
  ;; (interactive (list (read-directory-name "Find directory: ")))
  (popup-menu (poplife-dir-easymap dir submenu)
              (popup-menu-normalize-position last-nonmenu-event)))

(defun poplife-finder-directory ()
  "Return directory where Finder is visiting."
  (when (eq system-type 'darwin)
    (ns-do-applescript
     "tell application \"Finder\"
        if exists Finder window 1 then
          set currentDir to target of Finder window 1 as alias
        else
          set currentDir to desktop as alias
        end if
          set thePath to POSIX path of currentDir
      end tell")))
;; (let ((foo (poplife-finder-selection))) (describe-variable 'foo))

(defun poplife-find-location (file)
  "Visit directory that contains FILE."
  ;; org-open-file
  (cond
   ((eq system-type 'darwin)
    ;; Select file in Finder.
    (ns-do-applescript                  ; do-applescript, osascript
     (format "tell application \"Finder\"
                  set thePath to POSIX file \"%s\" as string
                  activate
                  reveal thePath
              end tell" file)))
   ((eq system-type 'windows-nt)
    ;; Select file in File Explorer.
    (w32-shell-execute "open" "explorer"
                       (concat "/e,/select,"
                               (poplife-convert-w32-filename file))))
   ((eq system-type 'gnu/linux)
    ;; Visit dir that contains file by default-app.
    ;; (start-process "select-file-by-nautilus" nil "nautilus" file)
    (start-process "open-dir-by-xdg-open" nil "xdg-open" (file-name-directory file)))
   (t
    ;; Select file in Dired
    (dired-other-frame (file-name-directory file)) ; Visit dir that contains file
    (dired-goto-file file)))) ; Move point to file

(defun poplife-convert-w32-filename (filename)
  "Mirror slash characters in FILENAME into backslashes."
  ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=24387 (bug#24387)
  ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=28883 (bug#28883)

  ;; (setq filename (convert-standard-filename filename))
  (let ((start 0))
    (while (string-match "/" filename start)
      (aset filename (match-beginning 0) ?\\)
      (setq start (match-end 0)))
    filename))
;;; (poplife-convert-w32-filename "c:/Users/dream/.emacs.d")

(defun poplife-find-file-by-default-app (file)
  "Visit FILE by default application or default file browser."
  (when (plist-get poplife-mouse-edit-cottager :recentf)
    (recentf-push file))
  (cond
   ((eq system-type 'gnu/linux)
    (start-process "find-file-by-default-app" nil "xdg-open" file)) ; Visit file by default-app.
   ((eq system-type 'darwin)
    (start-process "find-file-by-default-app" nil "open" file)) ; Visit file by default-app.
   ((eq system-type 'cygwin)
    (start-process "find-file-by-default-app" nil "cygstart" file)) ; Visit file by default-app.
   ((eq system-type 'windows-nt)
    (w32-shell-execute "open" "explorer" (poplife-convert-w32-filename file))) ; Visit file by default-app.
   (t
    (find-file-other-frame file))))

(provide 'poplife)
;;; poplife.el ends here

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-16  1:25           ` Drew Adams
  2020-09-16  8:10             ` Ergus
@ 2020-09-17  3:51             ` Richard Stallman
  1 sibling, 0 replies; 112+ messages in thread
From: Richard Stallman @ 2020-09-17  3:51 UTC (permalink / raw)
  To: Drew Adams
  Cc: spacibba, philipk, juri, self, arthur.miller, dgutov, ghe,
	emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > You're all over the map, Ergus, arguing abstractly, not
  > to the point

The second part of that sentences criticizes his arguments.  That's a
reasonable way to criticize.  But the first part is unkind, because it
criticizes Ergus rather than his arguments.
-- 
Dr Richard Stallman
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-16 14:37   ` Thibaut Verron
  2020-09-16 15:06     ` Eli Zaretskii
@ 2020-09-17  3:57     ` Richard Stallman
  1 sibling, 0 replies; 112+ messages in thread
From: Richard Stallman @ 2020-09-17  3:57 UTC (permalink / raw)
  To: thibaut.verron; +Cc: juri, eliz, tkk, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > Yes, we do support contextual menus, just press C-mouse-3.

  > It is only contextual if "context" just means "major mode".

It would not be hard to make text property bindings for C-mouse-3
depending on where in the buffer the mouse is.  Or make a binding that
calculates what menu to use.  No special infrastructure is needed --
just figure out what bindings you want.

-- 
Dr Richard Stallman
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-16  8:10             ` Ergus
  2020-09-16 15:02               ` Drew Adams
@ 2020-09-17  3:57               ` Richard Stallman
  2020-09-17 20:10                 ` Ergus
  1 sibling, 1 reply; 112+ messages in thread
From: Richard Stallman @ 2020-09-17  3:57 UTC (permalink / raw)
  To: Ergus
  Cc: philipk, juri, ghe, arthur.miller, dgutov, self, emacs-devel,
	drew.adams

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > This was just an examples of discussions that have been for years in
  > this mailing list and changes that the legacy users have opposed and
  > vetoed

Please do not call us "legacy users".  That is a harsh thing to say of
anyone.  It implies that Emacs inherited us and is stuck with us.

-- 
Dr Richard Stallman
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-16 19:35         ` Juri Linkov
  2020-09-16 23:10           ` Dmitry Gutov
@ 2020-09-17  3:58           ` Richard Stallman
  2020-09-17  7:48             ` Juri Linkov
  1 sibling, 1 reply; 112+ messages in thread
From: Richard Stallman @ 2020-09-17  3:58 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, spacibba, emacs-devel, self, arthur.miller, dgutov, ghe,
	eliz, drew.adams

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > "Poor"? the below just says that other applications (which ones?) do
  > > it slightly differently, that's all.  I don't see how what you say
  > > justifies the "poor" part.

  > Yes, this is subjective,

The worst problem is, it is not concrete enough to be constructive.
If someone says your program is "poor", what could you usefully do?

Please be more specific when you criticize.

  >  but while I use the mouse in other apps,
  > every time I try to use the mouse in Emacs, I can't make any sense of
  > default mouse bindings mess,

Which bindings do you find confusing?

If you say that, we might get an idea for an improvement.

-- 
Dr Richard Stallman
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-16 23:49   ` Tak Kunihiro
  2020-09-17  2:33     ` Tak Kunihiro
@ 2020-09-17  7:43     ` Juri Linkov
  2020-09-17  9:22       ` Robert Pluim
  2020-09-17 19:41       ` chad
  1 sibling, 2 replies; 112+ messages in thread
From: Juri Linkov @ 2020-09-17  7:43 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: emacs-devel

>>> - Horizontal scroll by wheel is supported.
>>> - Moving text using mouse is supported.
>
>> Please explain how horizontal scroll by wheel is supported.
>> Also please explain how moving text using mouse is supported.
>
> Try something like this.
>
> (setq mouse-wheel-tilt-scroll t)

I tried this, but still it doesn't scroll horizontally
with the mouse wheel.  It seems this feature expects the
mouse events mouse-6 and mouse-7, but scrolling the mouse wheel
produces mouse-4 and mouse-5.

> (setq mouse-drag-and-drop-region 'meta)

I tried this with (setq mouse-drag-and-drop-region 'control)
and it moves the text without modifier, and copies the text
when the modifier key is pressed immediately before releasing
the mouse button.  In other apps, the modifier key can be pressed
before clicking the mouse button.

>> Thanks, this is a good starting point for adding contextual menu.
>> I tried poplife-mode, and it pops up the menu on mouse-3,
>> but it seems only when there is the selection already,
>> i.e. it doesn't pop up the menu when nothing is selected.
>> Is this intended to work this way?
>
> That’s not intended behavior!
> I found that for unknown reason, poplife-mode does not overwrite
> [mouse-3] started with emacs -Q.  I’ll fix it and come back
> soon while the topic is hot.
...
> I fixed it and confirm with Emacs -Q.  Can you try again to see
> the approach to start with?

Now this is much better, thanks.

There are still some minor problems.  For example, when "Paste"
is selected from the Context menu, it doesn't paste the text
where mouse-3 was clicked.  It still pastes at the current cursor
position.

Also the Context menu is not activated immediately after clicking
down-mouse-3.  It's activated only after mouse-3 is released.
In other apps, down-mouse-3 can activate the Context menu.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-17  3:58           ` Richard Stallman
@ 2020-09-17  7:48             ` Juri Linkov
  2020-09-17 20:13               ` Ergus
  2020-09-18 10:53               ` Stefan Kangas
  0 siblings, 2 replies; 112+ messages in thread
From: Juri Linkov @ 2020-09-17  7:48 UTC (permalink / raw)
  To: Richard Stallman
  Cc: philipk, spacibba, emacs-devel, self, arthur.miller, dgutov, ghe,
	eliz, drew.adams

>   > > "Poor"? the below just says that other applications (which ones?) do
>   > > it slightly differently, that's all.  I don't see how what you say
>   > > justifies the "poor" part.
>
>   > Yes, this is subjective,
>
> The worst problem is, it is not concrete enough to be constructive.
> If someone says your program is "poor", what could you usefully do?
>
> Please be more specific when you criticize.

Constructively, I propose to include in Emacs a new mode
(with a name like 'modern-mouse-mode') where

- down-mouse-3 and mouse-3 pop up the context menu
  containing at least the items "Cut", "Copy", "Paste", "Undo", "Redo"
  (and only "Copy" when the buffer is in read-only mode);
- holding down the Shift key while using mouse-1 adjusts
  the already active region;
- dragging the active region moves it to the place
  where the mouse-1 was released;
- dragging the active region copies it to another place
  while holding down the Control key;
- holding down the Shift key while scrolling with mouse wheel
  scrolls the buffer horizontally;

>   >  but while I use the mouse in other apps,
>   > every time I try to use the mouse in Emacs, I can't make any sense of
>   > default mouse bindings mess,
>
> Which bindings do you find confusing?

This is just incompatibility between the currently active old mode
that follows what X applications do, and more modern mouse bindings
used nowadays in other applications.  So two separate modes are needed.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-17  7:43     ` Juri Linkov
@ 2020-09-17  9:22       ` Robert Pluim
  2020-09-17 18:59         ` Juri Linkov
  2020-09-17 19:41       ` chad
  1 sibling, 1 reply; 112+ messages in thread
From: Robert Pluim @ 2020-09-17  9:22 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Tak Kunihiro, emacs-devel

>>>>> On Thu, 17 Sep 2020 10:43:59 +0300, Juri Linkov <juri@linkov.net> said:
    Juri> There are still some minor problems.  For example, when "Paste"
    Juri> is selected from the Context menu, it doesn't paste the text
    Juri> where mouse-3 was clicked.  It still pastes at the current cursor
    Juri> position.

What's your value of 'mouse-yank-at-point'?

Robert



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-17  9:22       ` Robert Pluim
@ 2020-09-17 18:59         ` Juri Linkov
  0 siblings, 0 replies; 112+ messages in thread
From: Juri Linkov @ 2020-09-17 18:59 UTC (permalink / raw)
  To: Robert Pluim; +Cc: Tak Kunihiro, emacs-devel

> What's your value of 'mouse-yank-at-point'?

I use the default value nil of 'mouse-yank-at-point'.
So poplife.el should take onto account mouse-yank-at-point.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-17  7:43     ` Juri Linkov
  2020-09-17  9:22       ` Robert Pluim
@ 2020-09-17 19:41       ` chad
  2020-09-18  8:23         ` Juri Linkov
  1 sibling, 1 reply; 112+ messages in thread
From: chad @ 2020-09-17 19:41 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Tak Kunihiro, EMACS development team

[-- Attachment #1: Type: text/plain, Size: 1545 bytes --]

On Thu, Sep 17, 2020 at 1:28 AM Juri Linkov <juri@linkov.net> wrote:

> >>> - Horizontal scroll by wheel is supported.
> >>> - Moving text using mouse is supported.
> >
> >> Please explain how horizontal scroll by wheel is supported.
> >> Also please explain how moving text using mouse is supported.
> >
> > Try something like this.
> >
> > (setq mouse-wheel-tilt-scroll t)
>
> I tried this, but still it doesn't scroll horizontally
> with the mouse wheel.  It seems this feature expects the
> mouse events mouse-6 and mouse-7, but scrolling the mouse wheel
> produces mouse-4 and mouse-5.
>

FWIW, emacs uses the "original" (I think they started with XFree86?)
bindings that treat up/down mouse wheel as mouse buttons 4/5, while
left/right are 6&7, so this is working as (at least at one point in the
past) intended. There might be a communication issue around "by wheel"
here: are you using a mouse with a wheel that tilts to the left/right? I
believe that's what the OP had in mind.

(There is some added complication here, in that windows and macos seem to
use mouse-up/down/left/right, whereas the x11 code uses mouse-4/5/6/7. My
current environment is a little odd, but it seems like gtk (ala emacs-pgtk)
ise still using the numbers rather than the names.)

Poking around the internet suggests that the "standard" for horizontal
roll-the-wheel-scrolling is to add shift to rolling the wheel (and this
works in the couple apps that I tried). Emacs' mwheel.el doesn't currently
do this, but it looks like it wouldn't be hard to add.

~Chad

[-- Attachment #2: Type: text/html, Size: 2078 bytes --]

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-17  3:57               ` Richard Stallman
@ 2020-09-17 20:10                 ` Ergus
  2020-09-17 21:58                   ` Philip K.
  0 siblings, 1 reply; 112+ messages in thread
From: Ergus @ 2020-09-17 20:10 UTC (permalink / raw)
  To: Richard Stallman
  Cc: philipk, juri, ghe, arthur.miller, dgutov, self, emacs-devel,
	drew.adams

On Wed, Sep 16, 2020 at 11:57:37PM -0400, Richard Stallman wrote:
>[[[ To any NSA and FBI agents reading my email: please consider    ]]]
>[[[ whether defending the US Constitution against all enemies,     ]]]
>[[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
>  > This was just an examples of discussions that have been for years in
>  > this mailing list and changes that the legacy users have opposed and
>  > vetoed
>
>Please do not call us "legacy users".  That is a harsh thing to say of
>anyone.  It implies that Emacs inherited us and is stuck with us.
>
Sorry. That was the expression I found to describe users used to emacs
as is (including me) but that oppose to many changes (so not like me).

I usually describe features and changes I see in other editors that
indeed are not beneficial for me at all because I already spent a lot of
time learning the "emacs way". So in that sense I am also a legacy
user. Most of the changes I propose are indeed very simple; just details
and bindings that for external users are important and need constantly
and are included in emacs since many years.

But after all I understood that it is very hard to convince anyone
(students, colleges, projects managers) to invest so much time and
reading to learn how to do something simple they already know how to do
everywhere else. We can't even sale the idea that it is faster,
available everywhere, or more ergonomic like vim does.

Changing some of these will probably force me to re-learn many things;
but I am fine with that if that implies that the editor becomes more
attractive for more users. Otherwise we are just dying slowly with every
time less and less people in a world with exponentially more and more
programmers (with need to use an editor; the knowledge to become
maintainers and fresh ideas).

>-- 
>Dr Richard Stallman
>Chief GNUisance of the GNU Project (https://gnu.org)
>Founder, Free Software Foundation (https://fsf.org)
>Internet Hall-of-Famer (https://internethalloffame.org)
>
>
>



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-17  7:48             ` Juri Linkov
@ 2020-09-17 20:13               ` Ergus
  2020-09-18  8:19                 ` Juri Linkov
  2020-09-18 10:53               ` Stefan Kangas
  1 sibling, 1 reply; 112+ messages in thread
From: Ergus @ 2020-09-17 20:13 UTC (permalink / raw)
  To: Juri Linkov
  Cc: Richard Stallman, eliz, drew.adams, philipk, emacs-devel, ghe,
	arthur.miller, dgutov, self

On Thu, Sep 17, 2020 at 10:48:11AM +0300, Juri Linkov wrote:
>>   > > "Poor"? the below just says that other applications (which ones?) do
>>   > > it slightly differently, that's all.  I don't see how what you say
>>   > > justifies the "poor" part.
>>
>>   > Yes, this is subjective,
>>
>> The worst problem is, it is not concrete enough to be constructive.
>> If someone says your program is "poor", what could you usefully do?
>>
>> Please be more specific when you criticize.
>
>Constructively, I propose to include in Emacs a new mode
>(with a name like 'modern-mouse-mode') where
>
>- down-mouse-3 and mouse-3 pop up the context menu
>  containing at least the items "Cut", "Copy", "Paste", "Undo", "Redo"
>  (and only "Copy" when the buffer is in read-only mode);
>- holding down the Shift key while using mouse-1 adjusts
>  the already active region;
>- dragging the active region moves it to the place
>  where the mouse-1 was released;
>- dragging the active region copies it to another place
>  while holding down the Control key;
>- holding down the Shift key while scrolling with mouse wheel
>  scrolls the buffer horizontally;
>
>>   >  but while I use the mouse in other apps,
>>   > every time I try to use the mouse in Emacs, I can't make any sense of
>>   > default mouse bindings mess,
>>
>> Which bindings do you find confusing?
>
>This is just incompatibility between the currently active old mode
>that follows what X applications do, and more modern mouse bindings
>used nowadays in other applications.  So two separate modes are needed.

I haven't follow this but it seems very interesting, do you think it
makes sense that this becomes part of CUA-mode or are you thinking to
keep it apart?




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-17 20:10                 ` Ergus
@ 2020-09-17 21:58                   ` Philip K.
  0 siblings, 0 replies; 112+ messages in thread
From: Philip K. @ 2020-09-17 21:58 UTC (permalink / raw)
  To: Ergus; +Cc: rms, juri, self, arthur.miller, dgutov, ghe, emacs-devel,
	drew.adams

Ergus <spacibba@aol.com> writes:

> But after all I understood that it is very hard to convince anyone
> (students, colleges, projects managers) to invest so much time and
> reading to learn how to do something simple they already know how to do
> everywhere else.

I sometimes feel this aspect is overstated. Yes, you might be a bit
confused at first, but learning the basics of *using* Emacs isn't a
intellectual endeavour. Arrow keys work, "Home", "End", "Delete"
too. "Copy-Pasting" is probably the first big hurdle, but that's just a
1:1 mapping at first. Buffer and window management are 3-4 keybindings
each. Working with files really only requires understating how to open
files and how to save them. With these few keybindings, you already know
the basics. I've seen people stick to vim just because it's cool knowing
less about the editor.

Sure, if someone's in a hurry to edit a file, they don't want to learn
how to use a proper Editor first, but I don't think that Emacs should be
geared towards that demographic either. If you want to open a file via
the GUI, change a few words and forget about it, Gedit/Kwrite/Mousepad
is probably a better choice (with better DE integration).

-- 
	Philip K.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-17 20:13               ` Ergus
@ 2020-09-18  8:19                 ` Juri Linkov
  0 siblings, 0 replies; 112+ messages in thread
From: Juri Linkov @ 2020-09-18  8:19 UTC (permalink / raw)
  To: Ergus
  Cc: philipk, Richard Stallman, emacs-devel, self, arthur.miller,
	dgutov, ghe, eliz, drew.adams

> I haven't follow this but it seems very interesting, do you think it
> makes sense that this becomes part of CUA-mode or are you thinking to
> keep it apart?

This is a separate mode with a name like 'modern-mouse-mode'
that also should enable another sub-mode 'context-menu-mode'.

Should this mode also be activated by CUA-mode?  Maybe.
But this is a separate question.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-17 19:41       ` chad
@ 2020-09-18  8:23         ` Juri Linkov
  2020-09-18 18:41           ` chad
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2020-09-18  8:23 UTC (permalink / raw)
  To: chad; +Cc: Tak Kunihiro, EMACS development team

>     > (setq mouse-wheel-tilt-scroll t)
>
>     I tried this, but still it doesn't scroll horizontally
>     with the mouse wheel.  It seems this feature expects the
>     mouse events mouse-6 and mouse-7, but scrolling the mouse wheel
>     produces mouse-4 and mouse-5.
>
> FWIW, emacs uses the "original" (I think they started with XFree86?)
> bindings that treat up/down mouse wheel as mouse buttons 4/5, while
> left/right are 6&7, so this is working as (at least at one point in the
> past) intended. There might be a communication issue around "by wheel"
> here: are you using a mouse with a wheel that tilts to the left/right? I
> believe that's what the OP had in mind.

Do you mean a mouse with many additional buttons?  I heard such monsters
exist, but never seen them.

> Poking around the internet suggests that the "standard" for horizontal
> roll-the-wheel-scrolling is to add shift to rolling the wheel (and this
> works in the couple apps that I tried). Emacs' mwheel.el doesn't currently
> do this, but it looks like it wouldn't be hard to add.

I recall posting a patch that implements this, maybe I should resubmit it.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-17  7:48             ` Juri Linkov
  2020-09-17 20:13               ` Ergus
@ 2020-09-18 10:53               ` Stefan Kangas
  2020-09-19  4:01                 ` Richard Stallman
  1 sibling, 1 reply; 112+ messages in thread
From: Stefan Kangas @ 2020-09-18 10:53 UTC (permalink / raw)
  To: Juri Linkov, Richard Stallman
  Cc: philipk, spacibba, emacs-devel, ghe, arthur.miller, dgutov, self,
	eliz, drew.adams

Juri Linkov <juri@linkov.net> writes:

> Constructively, I propose to include in Emacs a new mode
> (with a name like 'modern-mouse-mode') where
>
> - down-mouse-3 and mouse-3 pop up the context menu
>   containing at least the items "Cut", "Copy", "Paste", "Undo", "Redo"
>   (and only "Copy" when the buffer is in read-only mode);
> - holding down the Shift key while using mouse-1 adjusts
>   the already active region;
> - dragging the active region moves it to the place
>   where the mouse-1 was released;
> - dragging the active region copies it to another place
>   while holding down the Control key;
> - holding down the Shift key while scrolling with mouse wheel
>   scrolls the buffer horizontally;

I agree with all of this.

But why not make this the default?  It's a low hanging fruit where there
is no reason not to make Emacs like other editors (well, except for
hysterical raisins).

Presumably none of it would cause any major problems for existing power
users.  Most discussions here seem to indicate they are more inclined to
use they keyboard than the mouse.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-18  8:23         ` Juri Linkov
@ 2020-09-18 18:41           ` chad
  0 siblings, 0 replies; 112+ messages in thread
From: chad @ 2020-09-18 18:41 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Tak Kunihiro, EMACS development team

[-- Attachment #1: Type: text/plain, Size: 2182 bytes --]

On Fri, Sep 18, 2020 at 1:31 AM Juri Linkov <juri@linkov.net> wrote:

> >     > (setq mouse-wheel-tilt-scroll t)
> >
> >     I tried this, but still it doesn't scroll horizontally
> >     with the mouse wheel.  It seems this feature expects the
> >     mouse events mouse-6 and mouse-7, but scrolling the mouse wheel
> >     produces mouse-4 and mouse-5.
> >
> > FWIW, emacs uses the "original" (I think they started with XFree86?)
> > bindings that treat up/down mouse wheel as mouse buttons 4/5, while
> > left/right are 6&7, so this is working as (at least at one point in the
> > past) intended. There might be a communication issue around "by wheel"
> > here: are you using a mouse with a wheel that tilts to the left/right? I
> > believe that's what the OP had in mind.
>
> Do you mean a mouse with many additional buttons?  I heard such monsters
> exist, but never seen them.
>

On one hand, if you believe that mice should have exactly 3 buttons in a
manner perhaps similar to the Spanish Inquisition, then yes.

On the other, for mice with a physical wheel, on X11 and derivatives (but
neither windows nor mac), a physically rolling the wheel appears to the
window system (and thus to emacs) as mouse buttons numbered 4 and 5. If the
wheel also registers a tilt to the left/right, these appear as buttons 6 &
7. The former is very common; the latter seems to be uncommon these days.
Neither of these are the so-called "MMO mouse" (apparently now sometimes
"MOBA mouse") with 6-15 (yes, really) extra buttons that are *relatively*
common amongst hardcore PC gamers.  (For example:
https://www.howtogeek.com/403685/how-to-use-an-mmo-or-moba-mouse-for-productivity/)
I've
only tried one of these once, and at the time the extra buttons weren't
supported by X11, so I can't tell you if the mouse equivalent of the space
cadet keyboard is emacs nirvana, instant thumb-sprain, or just a waste of
plastic.

These days, trackpads/touchpads are very common, and most of them have a
scrolling feature that uses gestures to fake those 4 extra buttons. Emacs
master currently does the expected scrolling things for up/down but not
left/right nor shift-up/down.

Hope that helps,
~Chad

[-- Attachment #2: Type: text/html, Size: 2864 bytes --]

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3 [was: Changes for emacs 28]
  2020-09-18 10:53               ` Stefan Kangas
@ 2020-09-19  4:01                 ` Richard Stallman
  0 siblings, 0 replies; 112+ messages in thread
From: Richard Stallman @ 2020-09-19  4:01 UTC (permalink / raw)
  To: Stefan Kangas
  Cc: philipk, spacibba, emacs-devel, self, arthur.miller, dgutov, ghe,
	eliz, juri, drew.adams

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > Constructively, I propose to include in Emacs a new mode
  > > (with a name like 'modern-mouse-mode') where

Sure, why not?

  > But why not make this the default?

Changing the default is a serious matter.  It requires agreement that
the new default is better.  By contrast, introducing a new optional
mode does not require much discussion.

Once we release Emacs with this new mode, we can ask users to try it
and we can find out whether people like it.



-- 
Dr Richard Stallman
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-15 13:11       ` Stefan Monnier
@ 2020-09-19  7:47         ` Tak Kunihiro
  2020-09-19  8:02         ` Tak Kunihiro
  2021-07-11 23:38         ` Context menus and mouse-3 Juri Linkov
  2 siblings, 0 replies; 112+ messages in thread
From: Tak Kunihiro @ 2020-09-19  7:47 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, Richard Stallman, spacibba, emacs-devel, tkk,
	arthur.miller, dgutov, ghe, drew.adams

To have pop up menu after long click sounds very useful.

- https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00267.html
- https://lists.gnu.org/archive/html/emacs-devel/2020-09/msg01277.html

I want to bind context menus to down-mouse-1 instead of down-mouse-3.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3       [was: Changes for emacs 28]
  2020-09-15 13:11       ` Stefan Monnier
  2020-09-19  7:47         ` Tak Kunihiro
@ 2020-09-19  8:02         ` Tak Kunihiro
  2021-07-11 23:38         ` Context menus and mouse-3 Juri Linkov
  2 siblings, 0 replies; 112+ messages in thread
From: Tak Kunihiro @ 2020-09-19  8:02 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, Richard Stallman, spacibba, emacs-devel, tkk,
	arthur.miller, dgutov, ghe, drew.adams

I think framework of context menu should be provided by Emacs,
as suggested three years ago by Stefan.

https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00416.html

I propose a system something like below.

A list for menu candidates is defined in advance.  After first one is
evaluated, then it returns menu or nil.  When it is menu, we pop menu
up.  When it is nil, the second one is evaluated.  The last one should
always return menu.

(defvar mouse-context-menu-functions
  '(mouse-help-menu             ; HELP menu
    mouse-info-menu             ; INFO menu
    mouse-file-menu             ; FILE menu
    mouse-dir-menu              ; DIR menu
    mouse-word-menu             ; WORD menu
    mouse-url-menu              ; URL menu
    menu-bar-edit-menu          ; EDIT menu (default))
  "Function that builds the context-menu.
Takes one argument (the EVENT that requests the menu) and should return
a list of menu items or nil")



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2020-09-15 13:11       ` Stefan Monnier
  2020-09-19  7:47         ` Tak Kunihiro
  2020-09-19  8:02         ` Tak Kunihiro
@ 2021-07-11 23:38         ` Juri Linkov
  2021-07-12  1:25           ` [External] : " Drew Adams
                             ` (2 more replies)
  2 siblings, 3 replies; 112+ messages in thread
From: Juri Linkov @ 2021-07-11 23:38 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, Richard Stallman, spacibba, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

[-- Attachment #1: Type: text/plain, Size: 1777 bytes --]

>>   > We don't need to choose, since we can get a context menu on
>>   > `down-mouse-3` and 'mouse-save-then-kill' on `mouse-3`.
>
>     (defun mouse-maybe-context-menu (event)
>       "Bring up a context menu for a long click.
>     See `mouse-long-click-time' and `mouse-context-menu-function'."
>       (interactive "@e")
>       (if (let ((track-mouse t)) (sit-for (/ mouse-long-click-time 1000.0)))
>           (push (cons 'context-menu (cdr event)) unread-command-events)))
>
> It's not good enough for `master` (IIRC the sit-for tends to return nil
> immediately in some circumstances), but I didn't pursue this any further
> given the lack of interest at the time.  I can't think of any reason why
> it should be hard to fix.

This is a much needed feature and it would nice to finish it one way or another.
I tried to use timers, and the result works well in all test cases:

1. Modes that already bind down-mouse-3 continue working without problems,
   so e.g. smerge-popup-context-menu works fine.  BTW, while testing it
   by clicking down-mouse-3 in non-selected windows, I found a problem,
   so a fix for this very rare problem is also included in the patch.

   For the same reason 'popup-menu' needs to be called explicitly
   to be able to select the right window, as the patch does,
   for the case when the mouse is dragged and down-mouse-3
   is released in another window.

2. flyspell.el doesn't need to be changed.  ibuffer.el works too.

3. cua-rect.el helped to fix one problem and now is supported too.

The new user option mouse-3-down-context-menu is based on mouse-1-click-follows-link.
Currently mouse-context-menu-map shows just the Edit menu - filling the content
of the context menu with e.g. mouse-context-menu-function is a separate task.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mouse-3-down-context-menu.patch --]
[-- Type: text/x-diff, Size: 4670 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 89e5d7c48a..febda78212 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -156,6 +156,82 @@ key-translation-map
 (define-key key-translation-map [double-mouse-1]
   #'mouse--click-1-maybe-follows-link)
 
+\f
+(defcustom mouse-3-down-context-menu 450
+  "Non-nil means that holding down Mouse-3 shows context menu.
+
+With the default setting, holding down the Mouse-3 button
+for more than 450 milliseconds performs the same action as S-Down-Mouse-3
+\(which shows the menu), while an ordinary Mouse-3 click performs the
+original Mouse-3 binding (which typically sets the region where you
+click the mouse).
+
+If value is an integer, the time elapsed between pressing and
+releasing the mouse button determines whether to show the menu
+or perform the normal Mouse-3 action (typically set the region).
+The absolute numeric value specifies the maximum duration of a
+\"short click\" in milliseconds.  A positive value means that a
+short click shows the menu, and a longer click performs the
+normal action.
+
+Otherwise, a single Mouse-3 click unconditionally shows the menu."
+  :version "28.1"
+  :type '(choice (const :tag "Disabled" nil)
+                 (number :tag "Single click time limit" :value 450)
+                 (other :tag "Single click" t)))
+
+(defvar mouse--down-3-timer nil)
+
+(defun mouse-maybe-context-menu (event)
+  (interactive "@e")
+  (cond
+   ;; Delay context menu display.
+   ((numberp mouse-3-down-context-menu)
+    (when (timerp mouse--down-3-timer)
+      (cancel-timer mouse--down-3-timer))
+    (setq mouse--down-3-timer
+          (run-with-timer
+           (/ (abs mouse-3-down-context-menu) 1000.0) nil
+           (lambda ()
+             (setq mouse--down-3-timer t)
+             (unless (eq (posn-window (event-end event)) (selected-window))
+               (select-window (posn-window (event-end event))))
+             (mouse-context-menu event))))
+    nil)
+   ;; Immediately pop up context menu.
+   (mouse-3-down-context-menu
+    (unless (eq (posn-window (event-end event)) (selected-window))
+      (select-window (posn-window (event-end event))))
+    (mouse-context-menu event))))
+
+(defun mouse--click-3-maybe-context-menu (&optional _prompt)
+  (cond
+   ((numberp mouse-3-down-context-menu)
+    (cond
+     ((timerp mouse--down-3-timer)
+      ;; Don't wait for context menu and fall back to mouse-save-then-kill.
+      (cancel-timer mouse--down-3-timer)
+      (setq mouse--down-3-timer nil)
+      nil)
+     (mouse--down-3-timer
+      ;; Context menu was displayed after delay.
+      (setq mouse--down-3-timer nil)
+      [])))
+   ;; Context menu was displayed immediately.
+   (mouse-3-down-context-menu
+    [])))
+
+(define-key key-translation-map [mouse-3]
+  #'mouse--click-3-maybe-context-menu)
+
+(defun mouse-context-menu-map ()
+  (cddr (assq 'edit (lookup-key global-map [menu-bar]))))
+
+(defun mouse-context-menu (event)
+  "Show a context menu for the current buffer."
+  (interactive "@e")
+  (popup-menu (mouse-context-menu-map) event))
+
 \f
 ;; Provide a mode-specific menu on a mouse button.
 
@@ -1672,7 +1748,7 @@ mouse-save-then-kill
      ((not (numberp click-pt)) nil)
      ;; If the user clicked without moving point, kill the region.
      ;; This also resets `mouse-selection-click-count'.
-     ((and (eq last-command 'mouse-save-then-kill)
+     ((and (memq last-command '(mouse-save-then-kill mouse-maybe-context-menu))
 	   (eq click-pt mouse-save-then-kill-posn)
 	   (eq window (selected-window)))
       (if mouse-drag-copy-region
@@ -2899,6 +2975,8 @@ function-key-map
 ;; Allow yanking also when the corresponding cursor is "in the fringe".
 (define-key function-key-map [right-fringe mouse-2] 'mouse--strip-first-event)
 (define-key function-key-map [left-fringe mouse-2] 'mouse--strip-first-event)
+
+(global-set-key [down-mouse-3]	'mouse-maybe-context-menu)
 (global-set-key [mouse-3]	'mouse-save-then-kill)
 (define-key function-key-map [right-fringe mouse-3] 'mouse--strip-first-event)
 (define-key function-key-map [left-fringe mouse-3] 'mouse--strip-first-event)
diff --git a/lisp/vc/smerge-mode.el b/lisp/vc/smerge-mode.el
index 694d4529b9..3aa7399dd5 100644
--- a/lisp/vc/smerge-mode.el
+++ b/lisp/vc/smerge-mode.el
@@ -385,6 +385,8 @@ smerge-remove-props
 (defun smerge-popup-context-menu (event)
   "Pop up the Smerge mode context menu under mouse."
   (interactive "e")
+  (unless (eq (posn-window (event-end event)) (selected-window))
+    (select-window (posn-window (event-end event))))
   (if (and smerge-mode
 	   (save-excursion (posn-set-point (event-end event)) (smerge-check 1)))
       (progn

^ permalink raw reply related	[flat|nested] 112+ messages in thread

* RE: [External] : Re: Context menus and mouse-3
  2021-07-11 23:38         ` Context menus and mouse-3 Juri Linkov
@ 2021-07-12  1:25           ` Drew Adams
  2021-07-12 11:55           ` Eli Zaretskii
  2021-07-12 22:32           ` Stefan Monnier
  2 siblings, 0 replies; 112+ messages in thread
From: Drew Adams @ 2021-07-12  1:25 UTC (permalink / raw)
  To: Juri Linkov, Stefan Monnier
  Cc: philipk@posteo.net, Richard Stallman, spacibba@aol.com,
	emacs-devel@gnu.org, arthur.miller@live.com, dgutov@yandex.ru,
	ghe@sdf.org

> This is a much needed feature and it would nice to
> finish it one way or another.

I still propose that library `mouse3.el' be added
to Emacs.  From a year ago:

  I propose that it be added to Emacs, that the
  behavior it offers be included, and even made
  the default behavior.  It doesn't conflict with
  the current behavior - it supplements it.

  Which context menus are provided out of the box
  can be discussed.  `mouse3.el' gives users and
  libraries easy ways to get the menus they want,
  but what menus Emacs should provide by default
  is an open question.

Description:

https://www.emacswiki.org/emacs/Mouse3

Code:

https://www.emacswiki.org/emacs/download/mouse3.el



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-11 23:38         ` Context menus and mouse-3 Juri Linkov
  2021-07-12  1:25           ` [External] : " Drew Adams
@ 2021-07-12 11:55           ` Eli Zaretskii
  2021-07-12 20:56             ` Juri Linkov
  2021-07-12 22:32           ` Stefan Monnier
  2 siblings, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2021-07-12 11:55 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

> From: Juri Linkov <juri@linkov.net>
> Date: Mon, 12 Jul 2021 02:38:19 +0300
> Cc: philipk@posteo.net, Richard Stallman <rms@gnu.org>, spacibba@aol.com,
>  emacs-devel@gnu.org, arthur.miller@live.com, dgutov@yandex.ru, ghe@sdf.org,
>  drew.adams@oracle.com
> 
> >>   > We don't need to choose, since we can get a context menu on
> >>   > `down-mouse-3` and 'mouse-save-then-kill' on `mouse-3`.
> >
> >     (defun mouse-maybe-context-menu (event)
> >       "Bring up a context menu for a long click.
> >     See `mouse-long-click-time' and `mouse-context-menu-function'."
> >       (interactive "@e")
> >       (if (let ((track-mouse t)) (sit-for (/ mouse-long-click-time 1000.0)))
> >           (push (cons 'context-menu (cdr event)) unread-command-events)))
> >
> > It's not good enough for `master` (IIRC the sit-for tends to return nil
> > immediately in some circumstances), but I didn't pursue this any further
> > given the lack of interest at the time.  I can't think of any reason why
> > it should be hard to fix.
> 
> This is a much needed feature and it would nice to finish it one way or another.
> I tried to use timers, and the result works well in all test cases:

Could you please remind us the problem you are trying to solve here?

Thanks.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-12 11:55           ` Eli Zaretskii
@ 2021-07-12 20:56             ` Juri Linkov
  2021-07-13  0:19               ` [External] : " Drew Adams
  2021-07-13 11:32               ` Eli Zaretskii
  0 siblings, 2 replies; 112+ messages in thread
From: Juri Linkov @ 2021-07-12 20:56 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

>> >>   > We don't need to choose, since we can get a context menu on
>> >>   > `down-mouse-3` and 'mouse-save-then-kill' on `mouse-3`.
>> >
>> >     (defun mouse-maybe-context-menu (event)
>> >       "Bring up a context menu for a long click.
>> >     See `mouse-long-click-time' and `mouse-context-menu-function'."
>> >       (interactive "@e")
>> >       (if (let ((track-mouse t)) (sit-for (/ mouse-long-click-time 1000.0)))
>> >           (push (cons 'context-menu (cdr event)) unread-command-events)))
>> >
>> > It's not good enough for `master` (IIRC the sit-for tends to return nil
>> > immediately in some circumstances), but I didn't pursue this any further
>> > given the lack of interest at the time.  I can't think of any reason why
>> > it should be hard to fix.
>>
>> This is a much needed feature and it would nice to finish it one way or another.
>> I tried to use timers, and the result works well in all test cases:
>
> Could you please remind us the problem you are trying to solve here?

Nowadays every other app uses down-mouse-3 to pop up a context menu,
but in Emacs mouse-3 operates on the region.  So the solution is
similar to mouse-1-click-follows-link: to pop up a context menu
after a delay, otherwise the immediate click operates on the region.

The only thing I don't understand why couldn't the context-menu
implementation be the same as the menu-bar implementation?

The global binding of [menu-bar] is defined in menu-bar.el,
so the same way [context-menu] could be defined globally
with the standard bindings such as all other apps have:
"Cut", "Copy", "Paste", "Select All", "Undo", "Redo".
Then the users will be able to customize the global
[context-menu] applicable to all buffers.

Every mode can define own [context-menu] in their mode-maps,
then users will be able to customize mode's [context-menu]
using mode hooks.  Even text-properties could define
the [context-menu] in their local bindings that will be used
by '(current-local-map)' or better '(current-active-maps)'.

To be able to override the [context-menu], local bindings could use
text-property maps with another binding named [overriding-context-menu]
that will replace the whole composite [context-menu], so e.g.
flyspell-mode could put it on misspelled words, etc.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-11 23:38         ` Context menus and mouse-3 Juri Linkov
  2021-07-12  1:25           ` [External] : " Drew Adams
  2021-07-12 11:55           ` Eli Zaretskii
@ 2021-07-12 22:32           ` Stefan Monnier
  2021-07-12 23:56             ` Juri Linkov
  2 siblings, 1 reply; 112+ messages in thread
From: Stefan Monnier @ 2021-07-12 22:32 UTC (permalink / raw)
  To: Juri Linkov
  Cc: Richard Stallman, spacibba, philipk, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

Juri Linkov [2021-07-12 02:38:19] wrote:
> This is a much needed feature and it would nice to finish it one way or another.
> I tried to use timers, and the result works well in all test cases:
[...]
> +    (setq mouse--down-3-timer
> +          (run-with-timer
> +           (/ (abs mouse-3-down-context-menu) 1000.0) nil
> +           (lambda ()
> +             (setq mouse--down-3-timer t)
> +             (unless (eq (posn-window (event-end event)) (selected-window))
> +               (select-window (posn-window (event-end event))))
> +             (mouse-context-menu event))))
[...]
> (defun mouse-context-menu (event)
>   "Show a context menu for the current buffer."
>   (interactive "@e")
>   (popup-menu (mouse-context-menu-map) event))

I'm a bit busy with other things these days, but just looking at the
above code, one thing I see as a potential problem with this code is
that the context menu commands won't be run "the normal way": the
undo-boundary won't be applied as usual, post/pre-command-hook won't be
run as usual, etc...

> The global binding of [menu-bar] is defined in menu-bar.el,
> so the same way [context-menu] could be defined globally

Agreed, and I think it would address the above problem.
I.e. do something like

    (defun mouse-context-menu (event)
      (push `(context-menu . ,(cdr event)) unread-command-events))

BTW, the other worry with your code is that if you use an input device
which can fail to pair the down/up mouse-3 events, you might end up
failing to cancel the timer code (that can also happen when the users
set a binding for `drag-mouse-3`, I think), so maybe you should arrange
for the down event to register a `pre-command-hook` that cancels
the timer.

In terms of aesthetics, it would be good to arrange the code such that
`mouse--click-3-maybe-context-menu` doesn't need to duplicate/mimic the
tests performed in `mouse-maybe-context-menu`.  Maybe have
`mouse-maybe-context-menu` set some var telling
`mouse--click-3-maybe-context-menu` when the next `mouse-3` should
be dropped?


        Stefan


PS: FWIW, the "proof of concept" code I have in my local Emacs is:

    (global-set-key [down-mouse-3] #'mouse-maybe-context-menu)
    (defun mouse-maybe-context-menu (event)
      "Bring up a context menu for a long click."
      (interactive "@e")
      (if (let* ((track-mouse t)
                 (time (/ mouse-long-click-time 1000.0))
                 (result (sit-for time)))
            (message "Maybe-context-menu: %S %S" time result)
            result)
          (push (cons 'context-menu (cdr event)) unread-command-events)))

I think `sit-for` can be made to work OK, but my proof-of-concept
isn't good enough.  I think the main issue is that it doesn't
swallow the mouse-3 click, but I haven't really looked into it.




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-12 22:32           ` Stefan Monnier
@ 2021-07-12 23:56             ` Juri Linkov
  2021-07-13  3:01               ` Stefan Monnier
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2021-07-12 23:56 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, Richard Stallman, spacibba, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

>> The global binding of [menu-bar] is defined in menu-bar.el,
>> so the same way [context-menu] could be defined globally
>
> Agreed, and I think it would address the above problem.
> I.e. do something like
>
>     (defun mouse-context-menu (event)
>       (push `(context-menu . ,(cdr event)) unread-command-events))

OT1H, this avoids an explicit call to 'popup-menu'.  But OTOH,
this precludes constructing the context-menu with a user-defined
function mouse-context-menu-function.

I tried to override the global [context-menu] with e.g. menu-bar-custom-menu
(that later could be replaced with the value returned from mouse-context-menu-function):

    (let ((map (make-sparse-keymap)))
      (define-key map [context-menu] menu-bar-custom-menu)
      (set-transient-map map))
    (push (cons 'context-menu (cdr event)) unread-command-events)

However, it doesn't override the global [context-menu], but prepends
the transient [context-menu] before the global one.

> PS: FWIW, the "proof of concept" code I have in my local Emacs is:
[...]
> I think `sit-for` can be made to work OK, but my proof-of-concept
> isn't good enough.  I think the main issue is that it doesn't
> swallow the mouse-3 click, but I haven't really looked into it.

At least, now we have two implementations, and both could be improved
before selecting the one that works better.  Meanwhile, I'd continue
trying to combine [context-menu] with mouse-context-menu-function.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: [External] : Re: Context menus and mouse-3
  2021-07-12 20:56             ` Juri Linkov
@ 2021-07-13  0:19               ` Drew Adams
  2021-07-13 11:32               ` Eli Zaretskii
  1 sibling, 0 replies; 112+ messages in thread
From: Drew Adams @ 2021-07-13  0:19 UTC (permalink / raw)
  To: Juri Linkov, Eli Zaretskii
  Cc: philipk@posteo.net, rms@gnu.org, spacibba@aol.com,
	emacs-devel@gnu.org, monnier@iro.umontreal.ca,
	arthur.miller@live.com, dgutov@yandex.ru, ghe@sdf.org

> Nowadays every other app...

Nowadays every other app is still not Emacs.
Emacs is not just an app like every other app.

> uses down-mouse-3 to pop up a context menu,
> but in Emacs mouse-3 operates on the region.

By default, yes, Emacs does.  And that's good.
Emacs selection-extension or deletion with a
right-click is a good feature.

> So the solution is...

No.  So there are many "solutions" possible.

But solutions to what?  The "problem" that Emacs
isn't like "every other app"?

No.  Solutions (ways) to provide users with a
right-click context menu.

And the best of those solutions give users:

1. A way to get either the longstanding Emacs
   default behavior or a context menu - au choix,
   when they right-click.  That means decide at
   the moment you click.

2. A way to choose only context menus, foregoing
   Emacs selection-extension/deletion behavior.

Library `mouse3.el' offers those user choices.

Wrt #1: By default you don't get a context menu
with a single right-click - you get the Emacs
selection-extension/deletion behavior.  A second
click gives you the menu.  So you can get either,
with the menu access costing you just a second
click at the same place.

Wrt #2: A user option lets you get the menu with
a single right-click.  In that case, you lose the
usual selection-extension/deletion behavior (but
Emacs gives you other ways to extend/delete a
selection).
___

There's no use of a delay (which is the bane of
Emacs CUA fiddling) - except this: whatever delay
you've already defined for your mouse as defining
a double-click.

* If within that delay then Emacs (as always)
  gives you a double-click behavior, which by
  default is the same as the longstanding Emacs
  behavior: kill/delete the (extended) selection,
  according to `mouse-drag-copy-region'.

* If more than the double-click delay then you
  get the menu.

(If you opt for a right-click to always give you
the menu immediately, then there's no second
click behavior and no double-click behavior.)

> similar to mouse-1-click-follows-link: to pop up a context menu
> after a delay, otherwise the immediate click operates on the region.

See above.  I think the mouse3.el approach is
saner and better fits both Emacs itself and
users used to, and still preferring, only a
context menu.

> Every mode can define own [context-menu] in their mode-maps,
> then users will be able to customize mode's [context-menu]
> using mode hooks.  Even text-properties could define
> the [context-menu] in their local bindings that will be used
> by '(current-local-map)' or better '(current-active-maps)'.

With mouse3.el there's no need for any of that -
no hooks, and no need for a special [context-menu]
pseudo-function key binding.  It's simple to
define context menus for modes (or for anything).

> To be able to override the [context-menu], local bindings could use
> text-property maps with another binding named [overriding-context-menu]
> that will replace the whole composite [context-menu], so e.g.
> flyspell-mode could put it on misspelled words, etc.

And no need for any of that - overriding with
text-property maps, additional pseudo-function
bindings, etc.  Instead, just bind variable
`mouse3-save-then-kill-command' to the behavior
you want - in any context or from any bit of code.
It can do anything you like, including provide
another menu (minor mode behavior or whatever).



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-12 23:56             ` Juri Linkov
@ 2021-07-13  3:01               ` Stefan Monnier
  2021-07-13 23:32                 ` Juri Linkov
  0 siblings, 1 reply; 112+ messages in thread
From: Stefan Monnier @ 2021-07-13  3:01 UTC (permalink / raw)
  To: Juri Linkov
  Cc: Richard Stallman, spacibba, philipk, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

>>> The global binding of [menu-bar] is defined in menu-bar.el,
>>> so the same way [context-menu] could be defined globally
>> Agreed, and I think it would address the above problem.
>> I.e. do something like
>>
>>     (defun mouse-context-menu (event)
>>       (push `(context-menu . ,(cdr event)) unread-command-events))
>
> OT1H, this avoids an explicit call to 'popup-menu'.

Calling `popup-menu` is not a problem, but not doing the dance usually
done by the command loop is more problematic.

> But OTOH, this precludes constructing the context-menu with
> a user-defined function mouse-context-menu-function.

Actually it doesn't.
You can bind `context-menu` to a command that uses that function and
then passes the result to `popup-menu`, or you can bind it to something like

        `(menu-item "Context menu" ignore
          :filter (lambda (_)
                    ..call mouse-context-menu-function..))

> I tried to override the global [context-menu] with e.g. menu-bar-custom-menu
> (that later could be replaced with the value returned from mouse-context-menu-function):
>
>     (let ((map (make-sparse-keymap)))
>       (define-key map [context-menu] menu-bar-custom-menu)
>       (set-transient-map map))
>     (push (cons 'context-menu (cdr event)) unread-command-events)
>
> However, it doesn't override the global [context-menu], but prepends
> the transient [context-menu] before the global one.

Yes, if the key is bound in various keymaps and all the bindings are to
a keymap, then those keymaps get merged, as usual for prefix keymaps.

Two ways to solve that:
- use `mouse-context-menu-function` instead of adding a new local
  key binding for `context-menu`.
- don't bind `context-menu` to a keymap but to a command (that
  presumably then uses `popup-menu` internally).

>> PS: FWIW, the "proof of concept" code I have in my local Emacs is:
> [...]
>> I think `sit-for` can be made to work OK, but my proof-of-concept
>> isn't good enough.  I think the main issue is that it doesn't
>> swallow the mouse-3 click, but I haven't really looked into it.
>
> At least, now we have two implementations, and both could be improved
> before selecting the one that works better.

FWIW I think yours holds more promise, so I don't intend to try and
improve mine.


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-12 20:56             ` Juri Linkov
  2021-07-13  0:19               ` [External] : " Drew Adams
@ 2021-07-13 11:32               ` Eli Zaretskii
  2021-07-13 23:46                 ` Juri Linkov
  1 sibling, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2021-07-13 11:32 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

> From: Juri Linkov <juri@linkov.net>
> Cc: monnier@iro.umontreal.ca,  philipk@posteo.net,  rms@gnu.org,
>   spacibba@aol.com,  emacs-devel@gnu.org,  arthur.miller@live.com,
>   dgutov@yandex.ru,  ghe@sdf.org,  drew.adams@oracle.com
> Date: Mon, 12 Jul 2021 23:56:39 +0300
> 
> Nowadays every other app uses down-mouse-3 to pop up a context menu,
> but in Emacs mouse-3 operates on the region.  So the solution is
> similar to mouse-1-click-follows-link: to pop up a context menu
> after a delay, otherwise the immediate click operates on the region.

Can't we decide which effect is TRT based on where the user clicks?
Context menus are available only in special places, and it would seem
that setting the region in those places doesn't make sense, by and
large.

And if sometimes we cannot dwim there, how about making the defcustom
you introduced to allow the users to express their preferences in
these problematic cases?

If the above makes sense, I think it's a better solution than forcing
this feature on everyone.  I would be surprised if holding the mouse
button for several hundreds of milliseconds would suddenly produce an
entirely different and unrelated effect, and I'd probably be annoyed
by the need to hold the button when I _know_ I want the context menu.
So it sounds like this implementation is sub-optimal from the get-go,
and we should try looking for a better one.

We could also consider an even more radical solution: an option to
swap mouse-2 and mouse-3.  Because isn't it true that people who
expect context menus to pop up when mouse-3 is pressed generally don't
expect and don't use region-related mouse clicks at all?  (We have
such a "swap-buttons" variable specific to MS-Windows, and I've been
using it for eons, because clicking mouse-2 on a wheeled mouse is very
inconvenient.)

Thanks.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-13  3:01               ` Stefan Monnier
@ 2021-07-13 23:32                 ` Juri Linkov
  2021-07-14  2:14                   ` Stefan Monnier
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2021-07-13 23:32 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, Richard Stallman, spacibba, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

>> I tried to override the global [context-menu] with e.g. menu-bar-custom-menu
>> (that later could be replaced with the value returned from mouse-context-menu-function):
>>
>>     (let ((map (make-sparse-keymap)))
>>       (define-key map [context-menu] menu-bar-custom-menu)
>>       (set-transient-map map))
>>     (push (cons 'context-menu (cdr event)) unread-command-events)
>>
>> However, it doesn't override the global [context-menu], but prepends
>> the transient [context-menu] before the global one.
>
> Yes, if the key is bound in various keymaps and all the bindings are to
> a keymap, then those keymaps get merged, as usual for prefix keymaps.
>
> Two ways to solve that:
> - use `mouse-context-menu-function` instead of adding a new local
>   key binding for `context-menu`.
> - don't bind `context-menu` to a keymap but to a command (that
>   presumably then uses `popup-menu` internally).

`popup-menu` has the same problems: it doesn't run post/pre-command-hook, etc.
because it uses `call-interactively`.  So any code that is based on `popup-menu`
such as `org-mouse-show-context-menu` has the same problems, and any code
that uses `call-interactively` such as `tmm-prompt`.

But it's possible to replace `call-interactively` with something like:

    (let ((command (car (x-popup-menu event menu-bar-custom-menu)))
          (map (make-sparse-keymap)))
      (define-key map [next-command] command)
      (set-transient-map map t))
    (push (cons 'next-command (cdr event)) unread-command-events)

It works surprisingly well, and I really see no problems with this.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-13 11:32               ` Eli Zaretskii
@ 2021-07-13 23:46                 ` Juri Linkov
  2021-07-14  4:30                   ` Eli Zaretskii
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2021-07-13 23:46 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

> Can't we decide which effect is TRT based on where the user clicks?
> Context menus are available only in special places, and it would seem
> that setting the region in those places doesn't make sense, by and
> large.

Context menus are useful everywhere, not just in special places.
For example, selecting "Paste" from the context menu makes sense everywhere.

> And if sometimes we cannot dwim there, how about making the defcustom
> you introduced to allow the users to express their preferences in
> these problematic cases?

In the previous patch, the defcustom is named mouse-3-down-context-menu.
When it's customized to nil, then only the current behavior is available
with mouse-save-then-kill.  When customized to t, then the context menu
pops up immediately.

> If the above makes sense, I think it's a better solution than forcing
> this feature on everyone.  I would be surprised if holding the mouse
> button for several hundreds of milliseconds would suddenly produce an
> entirely different and unrelated effect, and I'd probably be annoyed
> by the need to hold the button when I _know_ I want the context menu.
> So it sounds like this implementation is sub-optimal from the get-go,
> and we should try looking for a better one.

We can add as many options as necessary to cater for all needs,
but the question is about the default behavior.  The proposed delay is
a middle ground before the user decides which behavior is more preferable.

> We could also consider an even more radical solution: an option to
> swap mouse-2 and mouse-3.  Because isn't it true that people who
> expect context menus to pop up when mouse-3 is pressed generally don't
> expect and don't use region-related mouse clicks at all?  (We have
> such a "swap-buttons" variable specific to MS-Windows, and I've been
> using it for eons, because clicking mouse-2 on a wheeled mouse is very
> inconvenient.)

This is not backward-compatibile change of the default behavior.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-13 23:32                 ` Juri Linkov
@ 2021-07-14  2:14                   ` Stefan Monnier
  2021-07-14 23:32                     ` Juri Linkov
  0 siblings, 1 reply; 112+ messages in thread
From: Stefan Monnier @ 2021-07-14  2:14 UTC (permalink / raw)
  To: Juri Linkov
  Cc: Richard Stallman, spacibba, philipk, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

>>> I tried to override the global [context-menu] with e.g. menu-bar-custom-menu
>>> (that later could be replaced with the value returned from mouse-context-menu-function):
>>>
>>>     (let ((map (make-sparse-keymap)))
>>>       (define-key map [context-menu] menu-bar-custom-menu)
>>>       (set-transient-map map))
>>>     (push (cons 'context-menu (cdr event)) unread-command-events)
>>>
>>> However, it doesn't override the global [context-menu], but prepends
>>> the transient [context-menu] before the global one.
>>
>> Yes, if the key is bound in various keymaps and all the bindings are to
>> a keymap, then those keymaps get merged, as usual for prefix keymaps.
>>
>> Two ways to solve that:
>> - use `mouse-context-menu-function` instead of adding a new local
>>   key binding for `context-menu`.
>> - don't bind `context-menu` to a keymap but to a command (that
>>   presumably then uses `popup-menu` internally).
>
> `popup-menu` has the same problems: it doesn't run post/pre-command-hook, etc.

That doesn't matter: the command loop does that for us before/after calling
the command bound to `context-menu`, so the command bound to
`context-menu` doesn't need to do it.  The problem with your original
call is not the use of `popup-menu` but the fact that it runs it from
from a timer.


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-13 23:46                 ` Juri Linkov
@ 2021-07-14  4:30                   ` Eli Zaretskii
  2021-07-14 23:37                     ` Juri Linkov
  0 siblings, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2021-07-14  4:30 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

> From: Juri Linkov <juri@linkov.net>
> Cc: monnier@iro.umontreal.ca,  philipk@posteo.net,  rms@gnu.org,
>   spacibba@aol.com,  emacs-devel@gnu.org,  arthur.miller@live.com,
>   dgutov@yandex.ru,  ghe@sdf.org,  drew.adams@oracle.com
> Date: Wed, 14 Jul 2021 02:46:27 +0300
> 
> > Can't we decide which effect is TRT based on where the user clicks?
> > Context menus are available only in special places, and it would seem
> > that setting the region in those places doesn't make sense, by and
> > large.
> 
> Context menus are useful everywhere, not just in special places.
> For example, selecting "Paste" from the context menu makes sense
> everywhere.

Where in Emacs do we have context menus which include "Paste"?  I
thought we were talking about existing menus popped by mouse-2 that
you'd like to pop up with mouse-3.  If this isn't the case, then what
menus are we talking about here?  In particular, if you want to _add_
menus which currently don't exist in contexts where we currently don't
offer menus, that could be an entirely new minor mode, and then the
conflict with current bindings of mouse-3 could be resolved as part of
that mode.

> > And if sometimes we cannot dwim there, how about making the defcustom
> > you introduced to allow the users to express their preferences in
> > these problematic cases?
> 
> In the previous patch, the defcustom is named mouse-3-down-context-menu.
> When it's customized to nil, then only the current behavior is available
> with mouse-save-then-kill.  When customized to t, then the context menu
> pops up immediately.

I was thinking about something more flexible than an all-or-nothing
setting.  A delay is not really intelligent enough, since it again is
a global value.  I was thinking about something sensitive to the
context.

> > If the above makes sense, I think it's a better solution than forcing
> > this feature on everyone.  I would be surprised if holding the mouse
> > button for several hundreds of milliseconds would suddenly produce an
> > entirely different and unrelated effect, and I'd probably be annoyed
> > by the need to hold the button when I _know_ I want the context menu.
> > So it sounds like this implementation is sub-optimal from the get-go,
> > and we should try looking for a better one.
> 
> We can add as many options as necessary to cater for all needs,
> but the question is about the default behavior.  The proposed delay is
> a middle ground before the user decides which behavior is more preferable.

The default you suggest strikes me as inappropriate.  It is definitely
backward incompatible and confusing.

> > We could also consider an even more radical solution: an option to
> > swap mouse-2 and mouse-3.  Because isn't it true that people who
> > expect context menus to pop up when mouse-3 is pressed generally don't
> > expect and don't use region-related mouse clicks at all?  (We have
> > such a "swap-buttons" variable specific to MS-Windows, and I've been
> > using it for eons, because clicking mouse-2 on a wheeled mouse is very
> > inconvenient.)
> 
> This is not backward-compatibile change of the default behavior.

An opt-in behavior is by definition always backward-compatible.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-14  2:14                   ` Stefan Monnier
@ 2021-07-14 23:32                     ` Juri Linkov
  2021-07-15  1:18                       ` Stefan Monnier
  2021-07-15  6:24                       ` Eli Zaretskii
  0 siblings, 2 replies; 112+ messages in thread
From: Juri Linkov @ 2021-07-14 23:32 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, Richard Stallman, spacibba, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

> The problem with your original call is not the use of `popup-menu`
> but the fact that it runs it from from a timer.

So when the user wants the context menu to pop up after a delay then

  (push (cons 'context-menu (cdr event)) unread-command-events)

is a less problematic way to do this.  But for another case
to pop up the context menu immediately, customizing
mouse-3-down-context-menu to nil and still using the same
translation functions like mouse--click-3-maybe-context-menu
is not the most optimal way.

To pop up it immediately, I see no better way than currently
is implemented for C-down-mouse-3 because then C-h k C-down-mouse-3
works smoothly as well as Undo selected from the menu keeps undoing
on consequent calls, etc.

This means there is a need to create a new mode that when enabled
will bind the context menu directly to the key down-mouse-3
and unbind mouse-3 from mouse-save-then-kill
when the user wants to pop up it immediately.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-14  4:30                   ` Eli Zaretskii
@ 2021-07-14 23:37                     ` Juri Linkov
  2021-07-15  6:22                       ` Eli Zaretskii
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2021-07-14 23:37 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

>> Context menus are useful everywhere, not just in special places.
>> For example, selecting "Paste" from the context menu makes sense
>> everywhere.
>
> Where in Emacs do we have context menus which include "Paste"?

When the menu-bar is disabled, then C-down-mouse-3 pops up the global
menu where "Edit" contains "Paste".  When the menu-bar is enabled,
then some modes include "Paste" (e.g. calculator-paste) in a buffer-local menu.
And some modes like org-mode, flyspell-mode, etc. already redefine
down-mouse-3 to pop up context menus.

> I thought we were talking about existing menus popped by mouse-2 that

I suppose you meant C-down-mouse-3?

> you'd like to pop up with mouse-3.  If this isn't the case, then what
> menus are we talking about here?  In particular, if you want to _add_
> menus which currently don't exist in contexts where we currently don't
> offer menus, that could be an entirely new minor mode, and then the
> conflict with current bindings of mouse-3 could be resolved as part of
> that mode.

It seems a new minor mode is unavoidable because when the user wants
down-mouse-3 to pop up the context menu immediately, then
for the best effect down-mouse-3 should be bound directly
to the context-map, instead of sending the [context-menu] event.

>> In the previous patch, the defcustom is named mouse-3-down-context-menu.
>> When it's customized to nil, then only the current behavior is available
>> with mouse-save-then-kill.  When customized to t, then the context menu
>> pops up immediately.
>
> I was thinking about something more flexible than an all-or-nothing
> setting.  A delay is not really intelligent enough, since it again is
> a global value.  I was thinking about something sensitive to the
> context.

The users who currently use mouse-3 to operate on the region
might want to continue using it even on context-sensitive regions.

For example, like in all browsers, down-mouse-3 in e.g. Info browser or eww,
will show the menu with such items as "Backward" and "Forward".
But when down-mouse-3 will be clicked on a link, it will display
the context sensitive menu with "Follow" and "Open in New Window".



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-14 23:32                     ` Juri Linkov
@ 2021-07-15  1:18                       ` Stefan Monnier
  2021-07-15 22:31                         ` Juri Linkov
  2021-07-15  6:24                       ` Eli Zaretskii
  1 sibling, 1 reply; 112+ messages in thread
From: Stefan Monnier @ 2021-07-15  1:18 UTC (permalink / raw)
  To: Juri Linkov
  Cc: Richard Stallman, spacibba, philipk, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

Juri Linkov [2021-07-15 02:32:14] wrote:
>> The problem with your original call is not the use of `popup-menu`
>> but the fact that it runs it from from a timer.
>
> So when the user wants the context menu to pop up after a delay then
>
>   (push (cons 'context-menu (cdr event)) unread-command-events)

Yup.

> To pop up it immediately, I see no better way than currently
> is implemented for C-down-mouse-3 because then C-h k C-down-mouse-3
> works smoothly as well as Undo selected from the menu keeps undoing
> on consequent calls, etc.

Indeed.  Maybe we can bring them together by (when
`mouse-3-down-context-menu` is t) using a remapping from `down-mouse-3`
to `context-menu`.  It seems pretty intrusive, tho :-(

Maybe a better option is to make it so the `context-menu` event is kept
internal (give it a less attractive name), i.e. just an implementation
detail for the case where the menu pops up after a delay.


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-14 23:37                     ` Juri Linkov
@ 2021-07-15  6:22                       ` Eli Zaretskii
  2021-07-15 22:23                         ` Juri Linkov
  0 siblings, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2021-07-15  6:22 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

> From: Juri Linkov <juri@linkov.net>
> Cc: monnier@iro.umontreal.ca,  philipk@posteo.net,  rms@gnu.org,
>   spacibba@aol.com,  emacs-devel@gnu.org,  arthur.miller@live.com,
>   dgutov@yandex.ru,  ghe@sdf.org,  drew.adams@oracle.com
> Date: Thu, 15 Jul 2021 02:37:11 +0300
> 
> >> Context menus are useful everywhere, not just in special places.
> >> For example, selecting "Paste" from the context menu makes sense
> >> everywhere.
> >
> > Where in Emacs do we have context menus which include "Paste"?
> 
> When the menu-bar is disabled, then C-down-mouse-3 pops up the global
> menu where "Edit" contains "Paste".  When the menu-bar is enabled,
> then some modes include "Paste" (e.g. calculator-paste) in a buffer-local menu.

So you want to have the same menus on mouse-3, including when the menu
bar is not disabled?

> And some modes like org-mode, flyspell-mode, etc. already redefine
> down-mouse-3 to pop up context menus.

But those modes define those context menus on special parts of
display, where pasting etc. makes less sense, no?

> > I thought we were talking about existing menus popped by mouse-2 that
> 
> I suppose you meant C-down-mouse-3?

Both, I guess.

> > you'd like to pop up with mouse-3.  If this isn't the case, then what
> > menus are we talking about here?  In particular, if you want to _add_
> > menus which currently don't exist in contexts where we currently don't
> > offer menus, that could be an entirely new minor mode, and then the
> > conflict with current bindings of mouse-3 could be resolved as part of
> > that mode.
> 
> It seems a new minor mode is unavoidable because when the user wants
> down-mouse-3 to pop up the context menu immediately, then
> for the best effect down-mouse-3 should be bound directly
> to the context-map, instead of sending the [context-menu] event.

I'm okay with adding a minor mode for this.  Based on its popularity,
we could later discuss whether it should be turned on by default.

> The users who currently use mouse-3 to operate on the region
> might want to continue using it even on context-sensitive regions.
> 
> For example, like in all browsers, down-mouse-3 in e.g. Info browser or eww,
> will show the menu with such items as "Backward" and "Forward".
> But when down-mouse-3 will be clicked on a link, it will display
> the context sensitive menu with "Follow" and "Open in New Window".

If this kind of "dwim-ish" heuristic solves the issue, we should use
it.  In situations where such heuristic doesn't give good results,
perhaps this new minor mode we are talking about can also decide which
alternative to prefer when it isn't clear-cut.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-14 23:32                     ` Juri Linkov
  2021-07-15  1:18                       ` Stefan Monnier
@ 2021-07-15  6:24                       ` Eli Zaretskii
  2021-07-15 22:28                         ` Juri Linkov
  1 sibling, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2021-07-15  6:24 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

> From: Juri Linkov <juri@linkov.net>
> Date: Thu, 15 Jul 2021 02:32:14 +0300
> Cc: philipk@posteo.net, Richard Stallman <rms@gnu.org>, spacibba@aol.com,
>  emacs-devel@gnu.org, arthur.miller@live.com, dgutov@yandex.ru, ghe@sdf.org,
>  drew.adams@oracle.com
> 
> This means there is a need to create a new mode that when enabled
> will bind the context menu directly to the key down-mouse-3
> and unbind mouse-3 from mouse-save-then-kill
> when the user wants to pop up it immediately.

Instead of unbinding mouse-save-then-kill, this new mode could rebind
it to C-down-mouse-3, so that users could still invoke the command.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-15  6:22                       ` Eli Zaretskii
@ 2021-07-15 22:23                         ` Juri Linkov
  2021-07-16  6:49                           ` Eli Zaretskii
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2021-07-15 22:23 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

>> When the menu-bar is disabled, then C-down-mouse-3 pops up the global
>> menu where "Edit" contains "Paste".  When the menu-bar is enabled,
>> then some modes include "Paste" (e.g. calculator-paste) in a buffer-local menu.
>
> So you want to have the same menus on mouse-3, including when the menu
> bar is not disabled?

Exactly.

>> And some modes like org-mode, flyspell-mode, etc. already redefine
>> down-mouse-3 to pop up context menus.
>
> But those modes define those context menus on special parts of
> display, where pasting etc. makes less sense, no?

When the buffer is not read-only, I see no reason to disallow
pasting text because e.g. in flyspell-mode it makes sense
to paste a correction to a misspelled word, etc.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-15  6:24                       ` Eli Zaretskii
@ 2021-07-15 22:28                         ` Juri Linkov
  2021-07-16  6:51                           ` Eli Zaretskii
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2021-07-15 22:28 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

>> This means there is a need to create a new mode that when enabled
>> will bind the context menu directly to the key down-mouse-3
>> and unbind mouse-3 from mouse-save-then-kill
>> when the user wants to pop up it immediately.
>
> Instead of unbinding mouse-save-then-kill, this new mode could rebind
> it to C-down-mouse-3, so that users could still invoke the command.

Swapping mouse-3 and C-down-mouse-3 would be a good thing.  Another
necessary change to emulate the behavior of modern apps is to rebind
mouse-save-then-kill to S-mouse-1.

Maybe it's possible to add a delay so that the current binding [S-down-mouse-1]
could pop up mouse-appearance-menu only after a delay, e.g. 450ms.
But on releasing S-mouse-1 immediately, it could use mouse-save-then-kill
as modern apps do.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-15  1:18                       ` Stefan Monnier
@ 2021-07-15 22:31                         ` Juri Linkov
  2021-07-16 15:46                           ` Stefan Monnier
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2021-07-15 22:31 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, Richard Stallman, spacibba, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

>> To pop up it immediately, I see no better way than currently
>> is implemented for C-down-mouse-3 because then C-h k C-down-mouse-3
>> works smoothly as well as Undo selected from the menu keeps undoing
>> on consequent calls, etc.
>
> Indeed.  Maybe we can bring them together by (when
> `mouse-3-down-context-menu` is t) using a remapping from `down-mouse-3`
> to `context-menu`.  It seems pretty intrusive, tho :-(

I don't know what I did wrong but this does nothing:

  (global-set-key [down-mouse-3] [context-menu])
  (global-set-key [context-menu]
    `(menu-item ,(purecopy "Context Menu") ignore
      :filter (lambda (_) (mouse-context-menu-map))))

whereas this works fine:

  (global-set-key [down-mouse-3]
    `(menu-item ,(purecopy "Context Menu") ignore
      :filter (lambda (_) (mouse-context-menu-map))))

> Maybe a better option is to make it so the `context-menu` event is kept
> internal (give it a less attractive name), i.e. just an implementation
> detail for the case where the menu pops up after a delay.

A minor mode will also need to remove this binding

  (define-key key-translation-map [mouse-3]
    #'mouse--click-3-maybe-context-menu)

when `mouse-3-down-context-menu` is t, and to unbind
[mouse-3] from 'mouse-save-then-kill' because sometimes
'mouse-save-then-kill' still gets called, I haven't investigated why.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-15 22:23                         ` Juri Linkov
@ 2021-07-16  6:49                           ` Eli Zaretskii
  2021-07-16 18:59                             ` Juri Linkov
  0 siblings, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2021-07-16  6:49 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

> From: Juri Linkov <juri@linkov.net>
> Cc: monnier@iro.umontreal.ca,  philipk@posteo.net,  rms@gnu.org,
>   spacibba@aol.com,  emacs-devel@gnu.org,  arthur.miller@live.com,
>   dgutov@yandex.ru,  ghe@sdf.org,  drew.adams@oracle.com
> Date: Fri, 16 Jul 2021 01:23:09 +0300
> 
> >> And some modes like org-mode, flyspell-mode, etc. already redefine
> >> down-mouse-3 to pop up context menus.
> >
> > But those modes define those context menus on special parts of
> > display, where pasting etc. makes less sense, no?
> 
> When the buffer is not read-only, I see no reason to disallow
> pasting text because e.g. in flyspell-mode it makes sense
> to paste a correction to a misspelled word, etc.

IMO, when mouse-3 is clocked on a misspelled word, it makes much more
sense to assume the user wants to fix that word than that the user
wants to paste.

But here's an idea: how about merging the two menus into one in these
cases?  We could add a top-level menu with the two alternatives, each
one would then drop down one of the two possible menus.
Alternatively, just make a long menu by concatenating the contents of
the two original ones.

WDYT?



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-15 22:28                         ` Juri Linkov
@ 2021-07-16  6:51                           ` Eli Zaretskii
  2021-07-16 18:56                             ` Juri Linkov
  0 siblings, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2021-07-16  6:51 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

> From: Juri Linkov <juri@linkov.net>
> Cc: monnier@iro.umontreal.ca,  philipk@posteo.net,  rms@gnu.org,
>   spacibba@aol.com,  emacs-devel@gnu.org,  arthur.miller@live.com,
>   dgutov@yandex.ru,  ghe@sdf.org,  drew.adams@oracle.com
> Date: Fri, 16 Jul 2021 01:28:30 +0300
> 
> Another necessary change to emulate the behavior of modern apps is
> to rebind mouse-save-then-kill to S-mouse-1.
> 
> Maybe it's possible to add a delay so that the current binding [S-down-mouse-1]
> could pop up mouse-appearance-menu only after a delay, e.g. 450ms.
> But on releasing S-mouse-1 immediately, it could use mouse-save-then-kill
> as modern apps do.

Once again, I think lumping such different commands on the same mouse
gesture controlled by some more-or-less arbitrary timeout is not a
good UI.  We should avoid that as much as we possible can.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-15 22:31                         ` Juri Linkov
@ 2021-07-16 15:46                           ` Stefan Monnier
  2021-07-16 18:50                             ` Juri Linkov
  0 siblings, 1 reply; 112+ messages in thread
From: Stefan Monnier @ 2021-07-16 15:46 UTC (permalink / raw)
  To: Juri Linkov
  Cc: Richard Stallman, spacibba, philipk, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

>> Indeed.  Maybe we can bring them together by (when
>> `mouse-3-down-context-menu` is t) using a remapping from `down-mouse-3`
>> to `context-menu`.  It seems pretty intrusive, tho :-(
> I don't know what I did wrong but this does nothing:
>   (global-set-key [down-mouse-3] [context-menu])

This is a keyboard macro and the "extra info" (the `posn`) associated
with the `down-mouse-3` will not be passed on to the `context-menu`
event, so that's probably why it "does nothing".

Maybe something like

    (global-set-key [down-mouse-3]
      (lambda (event)
        (interactive "e")
        (execute-kbd-macro (vector `(context-menu . ,(cdr event))))))

??


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-16 15:46                           ` Stefan Monnier
@ 2021-07-16 18:50                             ` Juri Linkov
  2021-07-16 19:25                               ` Stefan Monnier
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2021-07-16 18:50 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, Richard Stallman, spacibba, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

>> I don't know what I did wrong but this does nothing:
>>   (global-set-key [down-mouse-3] [context-menu])
>
> This is a keyboard macro and the "extra info" (the `posn`) associated
> with the `down-mouse-3` will not be passed on to the `context-menu`
> event, so that's probably why it "does nothing".
>
> Maybe something like
>
>     (global-set-key [down-mouse-3]
>       (lambda (event)
>         (interactive "e")
>         (execute-kbd-macro (vector `(context-menu . ,(cdr event))))))
>
> ??

Nope, this doesn't fly.  Then for debugging tried:

  (global-set-key [context-menu]
    (lambda (&rest args) (interactive) (message "=> %S" args)))

  (global-set-key [down-mouse-3]
        (lambda (event)
          (interactive "e")
          (execute-kbd-macro (vector `(context-menu . ,(cdr event))))))

but it prints => nil



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-16  6:51                           ` Eli Zaretskii
@ 2021-07-16 18:56                             ` Juri Linkov
  2021-07-16 23:13                               ` Stefan Kangas
  2021-07-17  6:02                               ` Eli Zaretskii
  0 siblings, 2 replies; 112+ messages in thread
From: Juri Linkov @ 2021-07-16 18:56 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

>> Another necessary change to emulate the behavior of modern apps is
>> to rebind mouse-save-then-kill to S-mouse-1.
>>
>> Maybe it's possible to add a delay so that the current binding [S-down-mouse-1]
>> could pop up mouse-appearance-menu only after a delay, e.g. 450ms.
>> But on releasing S-mouse-1 immediately, it could use mouse-save-then-kill
>> as modern apps do.
>
> Once again, I think lumping such different commands on the same mouse
> gesture controlled by some more-or-less arbitrary timeout is not a
> good UI.  We should avoid that as much as we possible can.

Then maybe it could be enabled by the same mode e.g. 'modern-mouse-mode'.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-16  6:49                           ` Eli Zaretskii
@ 2021-07-16 18:59                             ` Juri Linkov
  2021-07-16 20:05                               ` [External] : " Drew Adams
  2021-07-18  5:13                               ` Tak Kunihiro
  0 siblings, 2 replies; 112+ messages in thread
From: Juri Linkov @ 2021-07-16 18:59 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

>> >> And some modes like org-mode, flyspell-mode, etc. already redefine
>> >> down-mouse-3 to pop up context menus.
>> >
>> > But those modes define those context menus on special parts of
>> > display, where pasting etc. makes less sense, no?
>> 
>> When the buffer is not read-only, I see no reason to disallow
>> pasting text because e.g. in flyspell-mode it makes sense
>> to paste a correction to a misspelled word, etc.
>
> IMO, when mouse-3 is clocked on a misspelled word, it makes much more
> sense to assume the user wants to fix that word than that the user
> wants to paste.
>
> But here's an idea: how about merging the two menus into one in these
> cases?  We could add a top-level menu with the two alternatives, each
> one would then drop down one of the two possible menus.
> Alternatively, just make a long menu by concatenating the contents of
> the two original ones.
>
> WDYT?

Tak Kunihiro had a very good idea of using a hook-like variable
that contains a list of functions that return parts of the whole
context-menu, then these parts will be collected into the final menu.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-16 18:50                             ` Juri Linkov
@ 2021-07-16 19:25                               ` Stefan Monnier
  0 siblings, 0 replies; 112+ messages in thread
From: Stefan Monnier @ 2021-07-16 19:25 UTC (permalink / raw)
  To: Juri Linkov
  Cc: Richard Stallman, spacibba, philipk, emacs-devel, arthur.miller,
	dgutov, ghe, drew.adams

>>     (global-set-key [down-mouse-3]
>>       (lambda (event)
>>         (interactive "e")
>>         (execute-kbd-macro (vector `(context-menu . ,(cdr event))))))
>>
>> ??
>
> Nope, this doesn't fly.  Then for debugging tried:
>
>   (global-set-key [context-menu]
>     (lambda (&rest args) (interactive) (message "=> %S" args)))
>
>   (global-set-key [down-mouse-3]
>         (lambda (event)
>           (interactive "e")
>           (execute-kbd-macro (vector `(context-menu . ,(cdr event))))))

Then I guess the only way that will work is if the rewrite from `down-mouse-3`
to `context-menu` is performed directly via
`input-decode-map/function-key-map/key-translation-map`.

Of course, you can also forgo rewriting to `context-menu` and
have the `down-mouse-3` event directly bring up the menu.


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: [External] : Re: Context menus and mouse-3
  2021-07-16 18:59                             ` Juri Linkov
@ 2021-07-16 20:05                               ` Drew Adams
  2021-07-18  5:13                               ` Tak Kunihiro
  1 sibling, 0 replies; 112+ messages in thread
From: Drew Adams @ 2021-07-16 20:05 UTC (permalink / raw)
  To: Juri Linkov, Eli Zaretskii
  Cc: philipk@posteo.net, rms@gnu.org, spacibba@aol.com,
	emacs-devel@gnu.org, monnier@iro.umontreal.ca,
	arthur.miller@live.com, dgutov@yandex.ru, ghe@sdf.org

> >> >> And some modes like org-mode, flyspell-mode, etc. already redefine
> >> >> down-mouse-3 to pop up context menus.
> >> >
> >> > But those modes define those context menus on special parts of
> >> > display, where pasting etc. makes less sense, no?
> >>
> >> When the buffer is not read-only, I see no reason to disallow
> >> pasting text because e.g. in flyspell-mode it makes sense
> >> to paste a correction to a misspelled word, etc.
> >
> > IMO, when mouse-3 is clocked on a misspelled word, it makes much more
> > sense to assume the user wants to fix that word than that the user
> > wants to paste.
> >
> > But here's an idea: how about merging the two menus into one in these
> > cases?  We could add a top-level menu with the two alternatives, each
> > one would then drop down one of the two possible menus.
> > Alternatively, just make a long menu by concatenating the contents of
> > the two original ones.
> >
> > WDYT?
> 
> Tak Kunihiro had a very good idea of using a hook-like variable
> that contains a list of functions that return parts of the whole
> context-menu, then these parts will be collected into the final menu.

FWIW -

`mouse3.el' has these variables:

`mouse3-region-popup-entries'
`mouse3-noregion-popup-entries'

`mouse3-region-popup-x-popup-panes'
`mouse3-noregion-popup-x-popup-panes'

Whether the first two or the second two are used is
controlled by option `mouse3-popup-x-popup-panes-flag'.

The difference corresponds to the two possibilities
offered by `x-popup-menu'.  The default is nil, so you
can use keymaps and extended menu items to define the
`mouse-3' menu.  The alternative is easy to use but
offers fewer possibilities.

The 2 `region' vars are used when the region is active.
The 2 `noregion' vars are used otherwise.
___

As for the choice of whether global menus should
be included in a `mouse-3' menu: Why decide that
at design time, hard-coding the behavior?
`mouse3.el' lets users decide, with option
`mouse3-popup-include-global-menus-flag'.
If non-nil then:

If the menu bar is visible then the major-mode menu
is the global menu to include on the `mouse-3' menu.
If the menu-bar is not shown then the menu-bar menus
are the menus to include on the `mouse-3' menu.
___

By default, the `mouse-3' menu has predefined submenus.
Users and code can modify the contents, of course.
(If the alternative panes approach is used, then the
operations are available in the single-level menu.)

These are the predefined submenus.  All except the
first are for when the region is active and nonempty.

`mouse3-noregion-popup-misc-submenu'
  Miscellaneous operations on a thing at mouse pointer:
    Email, open, visit, Dired, find, describe, highlight etc.

`mouse3-region-popup-change-text-submenu'
  Change the selected text:
    Fill, indent, transpose regions, upcase, etc.

`mouse3-region-popup-check-convert-submenu'
  Check, correct, or convert the selected text.

`mouse3-region-popup-copy-submenu'
  Copy selected text: text props, kill, to register etc.

`mouse3-region-popup-highlight-submenu'
  Highlight, unhighlight, copy/yank text props.

`mouse3-region-popup-misc-submenu'
  Miscellaneous operations on selected text:
    Count, narrow, eval, shell, write to file, etc.

`mouse3-region-popup-print-submenu'
  Print, PostScript print, BNF PostScript operations.

`mouse3-region-popup-rectangle-submenu'
  Selected rectangle: kill, delete, open, yank, clear, etc.

`mouse3-region-popup-register-submenu'
  Selected text to register: copy to, delete to, etc.

`mouse3-region-popup-remove/replace-items'
  Remove/replace selected text: kill, delete, yank.

`mouse3-region-popup-remove/replace-rect-submenu'
  Remove/replace selected rectangle:
    Clear, replace from last killed, string, register.

`mouse3-region-popup-search/replace-submenu'
  Isearch, query replace etc.




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-16 18:56                             ` Juri Linkov
@ 2021-07-16 23:13                               ` Stefan Kangas
  2021-07-17  6:22                                 ` Eli Zaretskii
  2021-07-17  6:02                               ` Eli Zaretskii
  1 sibling, 1 reply; 112+ messages in thread
From: Stefan Kangas @ 2021-07-16 23:13 UTC (permalink / raw)
  To: Juri Linkov
  Cc: Ergus, Richard Stallman, Philip K., Emacs developers,
	Stefan Monnier, Arthur Miller, Dmitry Gutov, Gregory Heytings,
	Eli Zaretskii, Drew Adams

Juri Linkov <juri@linkov.net> writes:

> Then maybe it could be enabled by the same mode e.g. 'modern-mouse-mode'.

But why make this conditional on a timeout?  I would have assumed the
"modern" way would be to just show the context menu unconditionally on
mouse-3, and ask for a modifier if you want to manipulate the region.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-16 18:56                             ` Juri Linkov
  2021-07-16 23:13                               ` Stefan Kangas
@ 2021-07-17  6:02                               ` Eli Zaretskii
  2021-07-19 17:48                                 ` Stefan Kangas
  1 sibling, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2021-07-17  6:02 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, drew.adams

> From: Juri Linkov <juri@linkov.net>
> Cc: monnier@iro.umontreal.ca,  philipk@posteo.net,  rms@gnu.org,
>   spacibba@aol.com,  emacs-devel@gnu.org,  arthur.miller@live.com,
>   dgutov@yandex.ru,  ghe@sdf.org,  drew.adams@oracle.com
> Date: Fri, 16 Jul 2021 21:56:56 +0300
> 
> > Once again, I think lumping such different commands on the same mouse
> > gesture controlled by some more-or-less arbitrary timeout is not a
> > good UI.  We should avoid that as much as we possible can.
> 
> Then maybe it could be enabled by the same mode e.g. 'modern-mouse-mode'.

IMO, it's not a good idea to use "modern" in variable names.

Something like mouse-friendly-mode or alt-mouse-mode, maybe?



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-16 23:13                               ` Stefan Kangas
@ 2021-07-17  6:22                                 ` Eli Zaretskii
  2021-07-17 21:46                                   ` Juri Linkov
  0 siblings, 1 reply; 112+ messages in thread
From: Eli Zaretskii @ 2021-07-17  6:22 UTC (permalink / raw)
  To: Stefan Kangas
  Cc: philipk, rms, spacibba, emacs-devel, monnier, arthur.miller,
	dgutov, ghe, juri, drew.adams

> From: Stefan Kangas <stefan@marxist.se>
> Date: Sat, 17 Jul 2021 01:13:45 +0200
> Cc: Eli Zaretskii <eliz@gnu.org>, "Philip K." <philipk@posteo.net>, Richard Stallman <rms@gnu.org>, 
> 	Ergus <spacibba@aol.com>, Emacs developers <emacs-devel@gnu.org>, 
> 	Stefan Monnier <monnier@iro.umontreal.ca>, Arthur Miller <arthur.miller@live.com>, 
> 	Dmitry Gutov <dgutov@yandex.ru>, Gregory Heytings <ghe@sdf.org>, Drew Adams <drew.adams@oracle.com>
> 
> Juri Linkov <juri@linkov.net> writes:
> 
> > Then maybe it could be enabled by the same mode e.g. 'modern-mouse-mode'.
> 
> But why make this conditional on a timeout?  I would have assumed the
> "modern" way would be to just show the context menu unconditionally on
> mouse-3, and ask for a modifier if you want to manipulate the region.

AFAIU, the suggestion is to use the minor mode to _replace_ the
timeout.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-17  6:22                                 ` Eli Zaretskii
@ 2021-07-17 21:46                                   ` Juri Linkov
  0 siblings, 0 replies; 112+ messages in thread
From: Juri Linkov @ 2021-07-17 21:46 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: philipk, rms, Stefan Kangas, spacibba, emacs-devel, monnier,
	arthur.miller, dgutov, ghe, drew.adams

>> > Then maybe it could be enabled by the same mode e.g. 'modern-mouse-mode'.
>> 
>> But why make this conditional on a timeout?  I would have assumed the
>> "modern" way would be to just show the context menu unconditionally on
>> mouse-3, and ask for a modifier if you want to manipulate the region.
>
> AFAIU, the suggestion is to use the minor mode to _replace_ the
> timeout.

Indeed.  And maybe the same mode could still provide an option to
use the timeout if enabling the timeout by default is not an option.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-16 18:59                             ` Juri Linkov
  2021-07-16 20:05                               ` [External] : " Drew Adams
@ 2021-07-18  5:13                               ` Tak Kunihiro
  2021-07-18 15:53                                 ` Stefan Monnier
  1 sibling, 1 reply; 112+ messages in thread
From: Tak Kunihiro @ 2021-07-18  5:13 UTC (permalink / raw)
  To: Juri Linkov
  Cc: spacibba, rms, philipk, emacs-devel, tkk, monnier, arthur.miller,
	dgutov, ghe, Eli Zaretskii, drew.adams

>> IMO, when mouse-3 is clocked on a misspelled word, it makes much more
>> sense to assume the user wants to fix that word than that the user
>> wants to paste.
>>
>> But here's an idea: how about merging the two menus into one in these
>> cases?  We could add a top-level menu with the two alternatives, each
>> one would then drop down one of the two possible menus.
>> Alternatively, just make a long menu by concatenating the contents of
>> the two original ones.
>>
>> WDYT?
>
> Tak Kunihiro had a very good idea of using a hook-like variable
> that contains a list of functions that return parts of the whole
> context-menu, then these parts will be collected into the final menu.

The idea is to define a variable (something like below;
poplife-menu-candidates) with list of functions that returns nil or
keymap (something like below; poplife-mouse-word-menu).  A function
(something like below; poplife-context-menu) will test each of them
until it gets keymap.

In this way, to revise context menu is easy.

(defvar poplife-menu-candidates
  '(poplife-mouse-help-menu             ; HELP menu
    poplife-mouse-info-menu             ; INFO menu
    poplife-mouse-file-menu             ; FILE menu
    poplife-mouse-dir-menu              ; DIR menu
    poplife-mouse-word-menu             ; WORD menu
    poplife-mouse-url-menu              ; URL menu
    ;; menu-bar-edit-menu    ; EDIT menu (default)
    poplife-mouse-edit-menu)            ; EDIT menu
  "List of candidates for context menu.
Candidates are function or keymap.  They will be evaluated in the
order of the list.  A function should accept mouse EVENT, and
return keymap or nil.  The last candidate should return valid
keymap.")

(defun poplife-mouse-word-menu (event)
  "Return 'flyspell-correct-word when word under mouse cursor on EVENT is incorrect."
  (and
   (not (region-active-p))
   ;; Check face by (what-cursor-position t) or C-u C-x =.
   (let ((faces-at-point (mapcar (lambda (xxx) (overlay-get xxx 'face))
                                 (overlays-at (posn-point (event-start event))))))
     (when (or (member 'flyspell-incorrect faces-at-point)
               (member 'flyspell-duplicate faces-at-point))
       #'flyspell-correct-word))))

(defun poplife-context-menu (event)
  "Return key's definition depending on thing under mouse click EVENT.
Items in `poplife-menu-candidates' are examined sequentially.
See `define-key' for the key's definition"
  ;; ~/.emacs.d/init.el ~/.emacs.d/ https://www.gnu.org/software/emacs/
  (when (fboundp 'secondary-selection-to-region) ; 26.1
    (secondary-selection-to-region)) ; When there is only secondary, turn it to region.
  (let ((candidates poplife-menu-candidates)
        context-menu)
    (while (not context-menu)
      (let ((item (car candidates)))
        (setq candidates (cdr candidates))
        ;; See how dired-guess-shell-alist-user is used in dired-guess-default.
        (setq context-menu (cond ((fboundp item)
                                  (funcall item event))
                                 ((and (symbolp item)
                                       (keymapp (symbol-value item)))
                                  (symbol-value item))
                                 (t     ; else
                                  nil)))))
    context-menu))



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-18  5:13                               ` Tak Kunihiro
@ 2021-07-18 15:53                                 ` Stefan Monnier
  2021-07-19 15:55                                   ` Juri Linkov
  0 siblings, 1 reply; 112+ messages in thread
From: Stefan Monnier @ 2021-07-18 15:53 UTC (permalink / raw)
  To: Tak Kunihiro
  Cc: Juri Linkov, Eli Zaretskii, philipk, rms, spacibba, emacs-devel,
	arthur.miller, dgutov, ghe, drew.adams, tkk

> The idea is to define a variable (something like below;
> poplife-menu-candidates) with list of functions that returns nil or
> keymap (something like below; poplife-mouse-word-menu).  A function
> (something like below; poplife-context-menu) will test each of them
> until it gets keymap.

Note: such a variable should have a name that ends in `-hook` or
`-functions` and should be manipulated with the usual hook functions,
e.g. `run-hook-wrapped`.

Note also that the `context-menu-function` already mentioned offers the
same kind of functionality (except you need to use `add-function`
instead of `add-hook` and it offers a bit more flexibility at the cost
of extra work).


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-18 15:53                                 ` Stefan Monnier
@ 2021-07-19 15:55                                   ` Juri Linkov
  2021-07-19 16:37                                     ` Stefan Monnier
  2021-07-19 19:59                                     ` Ergus via Emacs development discussions.
  0 siblings, 2 replies; 112+ messages in thread
From: Juri Linkov @ 2021-07-19 15:55 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, rms, spacibba, emacs-devel, Tak Kunihiro, tkk,
	arthur.miller, dgutov, ghe, Eli Zaretskii, drew.adams

>> The idea is to define a variable (something like below;
>> poplife-menu-candidates) with list of functions that returns nil or
>> keymap (something like below; poplife-mouse-word-menu).  A function
>> (something like below; poplife-context-menu) will test each of them
>> until it gets keymap.
>
> Note: such a variable should have a name that ends in `-hook` or
> `-functions` and should be manipulated with the usual hook functions,
> e.g. `run-hook-wrapped`.
>
> Note also that the `context-menu-function` already mentioned offers the
> same kind of functionality (except you need to use `add-function`
> instead of `add-hook` and it offers a bit more flexibility at the cost
> of extra work).

For easier customization, 'context-menu-functions' could be more hook-like,
so e.g. when the default value will be defined as

  (defcustom context-menu-functions '(context-menu-region)

then users could easily customize the default value.
More minor modes could add own functions to the global value, e.g.

  (add-hook 'context-menu-functions 'bug-reference-context-menu -5)
  (add-hook 'context-menu-functions 'goto-address-context-menu -10)

Major modes could modify buffer-local values:

  (add-hook 'context-menu-functions 'dired-context-menu nil t)
  (add-hook 'context-menu-functions 'info-context-menu -5 t)
  (add-hook 'context-menu-functions 'dictionary-context-menu -10 t)

Then the user could have the final say by using another option, e.g.

  (defcustom context-menu-filter nil

where a user-defined function (that can be extended using `add-function`)
will accept a menu constructed by context-menu-functions
and return the modified menu with reordered/removed/added items
to user's liking.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-19 15:55                                   ` Juri Linkov
@ 2021-07-19 16:37                                     ` Stefan Monnier
  2021-07-20 20:52                                       ` Juri Linkov
  2021-07-19 19:59                                     ` Ergus via Emacs development discussions.
  1 sibling, 1 reply; 112+ messages in thread
From: Stefan Monnier @ 2021-07-19 16:37 UTC (permalink / raw)
  To: Juri Linkov
  Cc: Tak Kunihiro, Eli Zaretskii, philipk, rms, spacibba, emacs-devel,
	arthur.miller, dgutov, ghe, drew.adams, tkk

> For easier customization, 'context-menu-functions' could be more hook-like,

FWIW, I originally thought of using a `-function` because I expect there
are situations where you'll want to override the normal menu with a more
specific one (rather than adding entries only), or move the normal
menu to a submenu.


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-17  6:02                               ` Eli Zaretskii
@ 2021-07-19 17:48                                 ` Stefan Kangas
  2021-07-19 18:08                                   ` Stefan Monnier
  0 siblings, 1 reply; 112+ messages in thread
From: Stefan Kangas @ 2021-07-19 17:48 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: Philip K., Richard Stallman, Ergus, Emacs developers,
	Stefan Monnier, Arthur Miller, Dmitry Gutov, Gregory Heytings,
	Juri Linkov, Drew Adams

Eli Zaretskii <eliz@gnu.org> writes:
> IMO, it's not a good idea to use "modern" in variable names.
>
> Something like mouse-friendly-mode or alt-mouse-mode, maybe?

Sure, any of those would work.

I personally don't mind the word "modern" too much, as it signals
something along the lines of: "avoid this mostly if you are a veteran
user and are too used to the old way".  But I'm all in favour of
finding a better word than "modern" to describe the grab-bag of
features that some of us would like to see under the general umbrella
"making Emacs more similar to contemporary software [unless there is
good reason to be different]".



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-19 17:48                                 ` Stefan Kangas
@ 2021-07-19 18:08                                   ` Stefan Monnier
  0 siblings, 0 replies; 112+ messages in thread
From: Stefan Monnier @ 2021-07-19 18:08 UTC (permalink / raw)
  To: Stefan Kangas
  Cc: Eli Zaretskii, Juri Linkov, Philip K., Richard Stallman, Ergus,
	Emacs developers, Arthur Miller, Dmitry Gutov, Gregory Heytings,
	Drew Adams

Stefan Kangas [2021-07-19 19:48:21] wrote:
> Eli Zaretskii <eliz@gnu.org> writes:
>> IMO, it's not a good idea to use "modern" in variable names.
>> Something like mouse-friendly-mode or alt-mouse-mode, maybe?
> Sure, any of those would work.

To me none of them are any good, because the only useful word there is
`mouse` and it's still pretty vague.

AFAIK the first and most important element is to introduce the concept
of a "context menu" (via `content-menu-function` or something like that)
which modes can use to add there own entries.

Then as a second step comes the choice of how to give access to this
menu, and I wouldn't call that a "mode" because I can't see any reason
why it should be a binary choice.  This menu should be available by
default, the only user-config question is which key-binding(s) to use
for it (some of the choices being to override `down-mouse-3` (and hence
`mouse-3`), or to use `down-mouse-3` with a delay, ...).


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-19 15:55                                   ` Juri Linkov
  2021-07-19 16:37                                     ` Stefan Monnier
@ 2021-07-19 19:59                                     ` Ergus via Emacs development discussions.
  2021-07-20 20:51                                       ` Juri Linkov
  1 sibling, 1 reply; 112+ messages in thread
From: Ergus via Emacs development discussions. @ 2021-07-19 19:59 UTC (permalink / raw)
  To: emacs-devel, Juri Linkov, Stefan Monnier
  Cc: philipk, rms, Tak Kunihiro, tkk, arthur.miller, dgutov, ghe,
	Eli Zaretskii, drew.adams

[-- Attachment #1: Type: text/plain, Size: 2055 bytes --]

Hi Juri:

is there anything to test, a scratch o feature branch? I am very interested in this feature.

On July 19, 2021 5:55:57 PM GMT+02:00, Juri Linkov <juri@linkov.net> wrote:
>>> The idea is to define a variable (something like below;
>>> poplife-menu-candidates) with list of functions that returns nil or
>>> keymap (something like below; poplife-mouse-word-menu).  A function
>>> (something like below; poplife-context-menu) will test each of them
>>> until it gets keymap.
>>
>> Note: such a variable should have a name that ends in `-hook` or
>> `-functions` and should be manipulated with the usual hook functions,
>> e.g. `run-hook-wrapped`.
>>
>> Note also that the `context-menu-function` already mentioned offers
>the
>> same kind of functionality (except you need to use `add-function`
>> instead of `add-hook` and it offers a bit more flexibility at the
>cost
>> of extra work).
>
>For easier customization, 'context-menu-functions' could be more
>hook-like,
>so e.g. when the default value will be defined as
>
>  (defcustom context-menu-functions '(context-menu-region)
>
>then users could easily customize the default value.
>More minor modes could add own functions to the global value, e.g.
>
>  (add-hook 'context-menu-functions 'bug-reference-context-menu -5)
>  (add-hook 'context-menu-functions 'goto-address-context-menu -10)
>
>Major modes could modify buffer-local values:
>
>  (add-hook 'context-menu-functions 'dired-context-menu nil t)
>  (add-hook 'context-menu-functions 'info-context-menu -5 t)
>  (add-hook 'context-menu-functions 'dictionary-context-menu -10 t)
>
>Then the user could have the final say by using another option, e.g.
>
>  (defcustom context-menu-filter nil
>
>where a user-defined function (that can be extended using
>`add-function`)
>will accept a menu constructed by context-menu-functions
>and return the modified menu with reordered/removed/added items
>to user's liking.

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

[-- Attachment #2: Type: text/html, Size: 2585 bytes --]

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-19 19:59                                     ` Ergus via Emacs development discussions.
@ 2021-07-20 20:51                                       ` Juri Linkov
  0 siblings, 0 replies; 112+ messages in thread
From: Juri Linkov @ 2021-07-20 20:51 UTC (permalink / raw)
  To: Ergus
  Cc: philipk, rms, emacs-devel, Tak Kunihiro, tkk, Stefan Monnier,
	arthur.miller, dgutov, ghe, Eli Zaretskii, drew.adams

> is there anything to test, a scratch o feature branch? I am very interested
> in this feature.

Now there is a new branch 'feature/context-menu'.
It provides a new mode 'context-menu-mode'
that binds the Context menu to [down-mouse-3].

For testing, it adds the Context menu to the major mode
Info-mode, so clicking anywhere in the Info buffer
pops up the navigation menu, and clicking on links
adds a menu item to open a link.

Also is adds the Context menu to one minor mode
goto-address-mode where clicking on an address
pops up a menu with an item to open that address.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-19 16:37                                     ` Stefan Monnier
@ 2021-07-20 20:52                                       ` Juri Linkov
  2021-07-20 22:24                                         ` Stefan Monnier
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2021-07-20 20:52 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, rms, spacibba, emacs-devel, Tak Kunihiro, tkk,
	arthur.miller, dgutov, ghe, Eli Zaretskii, drew.adams

>> For easier customization, 'context-menu-functions' could be more hook-like,
>
> FWIW, I originally thought of using a `-function` because I expect there
> are situations where you'll want to override the normal menu with a more
> specific one (rather than adding entries only), or move the normal
> menu to a submenu.

The new branch 'feature/context-menu' now includes also the variable
'context-menu-overriding-function' that can override the normal menu.

But I have no idea on which mode to test it.  It makes sense to
override the normal menu in modes that produce too long menus,
such as a long list of candidates in flyspell-mode.  But flyspell-mode
already overrides the menu with own [down-mouse-3], and rewriting it to
use context-menu-overriding-function might cause backward-incompatibility bugs.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-20 20:52                                       ` Juri Linkov
@ 2021-07-20 22:24                                         ` Stefan Monnier
  2021-07-20 23:15                                           ` Juri Linkov
  0 siblings, 1 reply; 112+ messages in thread
From: Stefan Monnier @ 2021-07-20 22:24 UTC (permalink / raw)
  To: Juri Linkov
  Cc: Tak Kunihiro, Eli Zaretskii, philipk, rms, spacibba, emacs-devel,
	arthur.miller, dgutov, ghe, drew.adams, tkk

> such as a long list of candidates in flyspell-mode.  But flyspell-mode
> already overrides the menu with own [down-mouse-3], and rewriting it to
> use context-menu-overriding-function might cause backward-incompatibility bugs.

Yet, it is definitely one of the packages which should use context-menu.


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-20 22:24                                         ` Stefan Monnier
@ 2021-07-20 23:15                                           ` Juri Linkov
  2021-07-21  4:39                                             ` Tak Kunihiro
  0 siblings, 1 reply; 112+ messages in thread
From: Juri Linkov @ 2021-07-20 23:15 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: philipk, rms, spacibba, emacs-devel, Tak Kunihiro, tkk,
	arthur.miller, dgutov, ghe, Eli Zaretskii, drew.adams

>> such as a long list of candidates in flyspell-mode.  But flyspell-mode
>> already overrides the menu with own [down-mouse-3], and rewriting it to
>> use context-menu-overriding-function might cause backward-incompatibility bugs.
>
> Yet, it is definitely one of the packages which should use context-menu.

I realized now that context-menu-overriding-function is not needed
since it's possible just to reverse the priorities, so the
functions at the end of the list in context-menu-functions
will have higher priority.  Then for example, flyspell-context-menu
called as the last function can remove all items added by earlier calls
and return a new menu with only own items.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-20 23:15                                           ` Juri Linkov
@ 2021-07-21  4:39                                             ` Tak Kunihiro
  2021-07-21  5:07                                               ` [External] : " Drew Adams
  2021-07-21 12:45                                               ` Stefan Monnier
  0 siblings, 2 replies; 112+ messages in thread
From: Tak Kunihiro @ 2021-07-21  4:39 UTC (permalink / raw)
  To: Juri Linkov
  Cc: philipk, rms, spacibba, emacs-devel, tkk, Stefan Monnier,
	arthur.miller, dgutov, ghe, Eli Zaretskii, drew.adams

I think most of the time, a thing under mouse cursor matters for
context-menu instead of mode.

For example, when a thing under mouse cursor is with face
'flyspell-incorrect, it is nice to have 'flyspell-correct-word as shown
below.

(defun poplife-mouse-word-menu (event)
  "Return 'flyspell-correct-word when word under mouse cursor on EVENT is incorrect."
  (and
   (not (region-active-p))
   (let ((faces-at-point (mapcar (lambda (xxx) (overlay-get xxx 'face))
                                 (overlays-at (posn-point (event-start event))))))
     (when (or (member 'flyspell-incorrect faces-at-point)
               (member 'flyspell-duplicate faces-at-point))
       #'flyspell-correct-word))))



^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: [External] : Re: Context menus and mouse-3
  2021-07-21  4:39                                             ` Tak Kunihiro
@ 2021-07-21  5:07                                               ` Drew Adams
  2021-07-21 12:45                                               ` Stefan Monnier
  1 sibling, 0 replies; 112+ messages in thread
From: Drew Adams @ 2021-07-21  5:07 UTC (permalink / raw)
  To: Tak Kunihiro, Juri Linkov
  Cc: philipk@posteo.net, rms@gnu.org, spacibba@aol.com,
	emacs-devel@gnu.org, tkk@misasa.okayama-u.ac.jp, Stefan Monnier,
	arthur.miller@live.com, dgutov@yandex.ru, ghe@sdf.org,
	Eli Zaretskii

> I think most of the time, a thing under mouse
> cursor matters for context-menu instead of mode.

Yes, I agree.  A mode can certainly do particular
things, i.e., have menu items specific to it.
But it should generally be possible to act on a
thing that's under the pointer.

(BTW, it's called the mouse "pointer", as opposed
to the text "cursor" - e.g. in the docs.)

That's why `mouse3.el' has this available in the
`mouse-3' menu by default when the region is not
active (when it's active you get a menu for acting
on the region).

There are several kinds of action, for several
kinds of thing, that you can choose from the menu.

By default there's a `Thing at Point' submenu
with items such as these (a given item is enabled
when there's a relevant thing under the pointer):

 _______________________________
 Open URL in Browser
 Visit File
 Visit File in Other Window
 Dired
 Dired in Other Window
 _______________________________
 Describe File
 Describe Function
 Show Code Defining Function
 Describe Variable
 Show Code Defining Variable
 Describe Face
 Describe Package
 Describe Text Properties
 _______________________________
 Highlight Symbol
 Unhighlight Symbol
 Hi-Lock Symbol
 Un-Hi-Lock Symbol
 _______________________________
 Look Up Symbol in Manual
 Search for Symbol
 Eval & Pretty-Print Lisp Sexp
 _______________________________

But of course this is just the default behavior.
A mode can define its own approach to the menu,
as can a user (by customizing).

If flyspell is available and turned on then you
could have an item for using it on the word under
the pointer, i.e., when the pointer is in fact
over a word.  (I didn't include that by default.)






^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-21  4:39                                             ` Tak Kunihiro
  2021-07-21  5:07                                               ` [External] : " Drew Adams
@ 2021-07-21 12:45                                               ` Stefan Monnier
  2021-07-21 17:26                                                 ` [External] : " Drew Adams
  1 sibling, 1 reply; 112+ messages in thread
From: Stefan Monnier @ 2021-07-21 12:45 UTC (permalink / raw)
  To: Tak Kunihiro
  Cc: Juri Linkov, Eli Zaretskii, philipk, rms, spacibba, emacs-devel,
	arthur.miller, dgutov, ghe, drew.adams, tkk

Tak Kunihiro [2021-07-21 13:39:30] wrote:
> I think most of the time, a thing under mouse cursor matters for
> context-menu instead of mode.

Obviously, but note that the code that decides what "thing under the
cursor" is relevant, and which menu entries should be shown for it is
most likely going to be provided by a mode.

So I guess what I'm saying is that I disagree with "instead of".


        Stefan




^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: [External] : Re: Context menus and mouse-3
  2021-07-21 12:45                                               ` Stefan Monnier
@ 2021-07-21 17:26                                                 ` Drew Adams
  2021-07-22  3:49                                                   ` Tak Kunihiro
  0 siblings, 1 reply; 112+ messages in thread
From: Drew Adams @ 2021-07-21 17:26 UTC (permalink / raw)
  To: Stefan Monnier, Tak Kunihiro
  Cc: spacibba@aol.com, rms@gnu.org, philipk@posteo.net,
	emacs-devel@gnu.org, tkk@misasa.okayama-u.ac.jp,
	arthur.miller@live.com, dgutov@yandex.ru, ghe@sdf.org,
	Eli Zaretskii, Juri Linkov

> > I think most of the time, a thing under mouse cursor matters for
> > context-menu instead of mode.
> 
> Obviously, but note that the code that decides what "thing under the
> cursor" is relevant, and which menu entries should be shown for it is
> most likely going to be provided by a mode.
> 
> So I guess what I'm saying is that I disagree with "instead of".

Yes, fair enough.  Several things can be relevant to
determining what's in a "context" menu - including
modes, buffer text under the pointer, and properties
(text, overlay) under the pointer.

Anything having to do with current Emacs "state",
of any kind, can be considered behavioral "context".
Of course, context that is closely related to the
mouse-pointer state is particularly relevant.

It's not just modes.  It's not just text under the
mouse pointer.  It's not "instead of".  Right.
It's anything you (a user or code) want the menu
to be.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: Context menus and mouse-3
  2021-07-21 17:26                                                 ` [External] : " Drew Adams
@ 2021-07-22  3:49                                                   ` Tak Kunihiro
  2021-07-22  4:06                                                     ` [External] : " Drew Adams
  0 siblings, 1 reply; 112+ messages in thread
From: Tak Kunihiro @ 2021-07-22  3:49 UTC (permalink / raw)
  To: emacs-devel@gnu.org
  Cc: philipk@posteo.net, rms@gnu.org, spacibba@aol.com, Juri Linkov,
	国広卓也, Stefan Monnier,
	arthur.miller@live.com, dgutov@yandex.ru, ghe@sdf.org,
	Eli Zaretskii, Drew Adams

>>> I think most of the time, a thing under mouse cursor matters for
>>> context-menu instead of mode.
>> 
>> Obviously, but note that the code that decides what "thing under the
>> cursor" is relevant, and which menu entries should be shown for it is
>> most likely going to be provided by a mode.
>> 
>> So I guess what I'm saying is that I disagree with "instead of".
> 
> It's not just modes.  It's not just text under the
> mouse pointer.  It's not "instead of".  Right.
> It's anything you (a user or code) want the menu
> to be.

I think operation double click on icon in file browser is a good
analogue to operation via context menu.

Double click opens an icon.
I think by default, context menu should provide a way to open a
thing under mouse pointer.

What is appropriate open, isn’t obvious.

| thing     | open          |
|-----------+---------------|
| file      | file-file     |
| directory | dired         |
| url       | browse-url    |
| function  | describe-help |




^ permalink raw reply	[flat|nested] 112+ messages in thread

* RE: [External] : Re: Context menus and mouse-3
  2021-07-22  3:49                                                   ` Tak Kunihiro
@ 2021-07-22  4:06                                                     ` Drew Adams
  0 siblings, 0 replies; 112+ messages in thread
From: Drew Adams @ 2021-07-22  4:06 UTC (permalink / raw)
  To: Tak Kunihiro, emacs-devel@gnu.org
  Cc: philipk@posteo.net, rms@gnu.org, spacibba@aol.com, Juri Linkov,
	Stefan Monnier, arthur.miller@live.com, dgutov@yandex.ru,
	ghe@sdf.org, Eli Zaretskii

> I think operation double click on icon in file browser is a good
> analogue to operation via context menu.
> 
> Double click opens an icon.
> I think by default, context menu should provide a way to open a
> thing under mouse pointer.
> 
> What is appropriate open, isn’t obvious.
> 
> | thing     | open          |
> |-----------+---------------|
> | file      | file-file     |
> | directory | dired         |
> | url       | browse-url    |
> | function  | describe-help |

Not just "open", however that operation might be
defined for a given kind of thing under the mouse
pointer.  That is, there need not be just one
appropriate action for a given thing.

A double-click is associated with only a _single_
action (unless combined with modifier keys).

Here we're talking about a _menu_, which means a
number of choices.  Including possibly multiple
choices for the same type of thing.

I gave several examples from the `mouse3.el' menu.
E.g. 4 actions for a symbol pointed to, 2 actions
each for a function or variable name pointed to.

The possibilities are endless.  Which is another
reason to allow both programmatic and user control
over the menu in any given context.

^ permalink raw reply	[flat|nested] 112+ messages in thread

end of thread, other threads:[~2021-07-22  4:06 UTC | newest]

Thread overview: 112+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-14  3:06 Context menus and mouse-3 [was: Changes for emacs 28] Drew Adams
2020-09-14  6:11 ` Ergus
2020-09-14  6:28   ` Stefan Monnier
2020-09-14  6:48     ` Ergus
2020-09-14  7:49       ` tomas
2020-09-14  7:58         ` Thibaut Verron
2020-09-14  8:29           ` tomas
2020-09-14  9:03             ` Thibaut Verron
2020-09-14  9:12               ` Göktuğ Kayaalp
2020-09-14 11:37               ` tomas
2020-09-14 12:36                 ` Thibaut Verron
2020-09-14 15:59             ` Drew Adams
2020-09-14 15:12         ` Eli Zaretskii
2020-09-14 15:47         ` Drew Adams
2020-09-14 20:54           ` tomas
2020-09-15  4:35     ` Richard Stallman
2020-09-15 13:11       ` Stefan Monnier
2020-09-19  7:47         ` Tak Kunihiro
2020-09-19  8:02         ` Tak Kunihiro
2021-07-11 23:38         ` Context menus and mouse-3 Juri Linkov
2021-07-12  1:25           ` [External] : " Drew Adams
2021-07-12 11:55           ` Eli Zaretskii
2021-07-12 20:56             ` Juri Linkov
2021-07-13  0:19               ` [External] : " Drew Adams
2021-07-13 11:32               ` Eli Zaretskii
2021-07-13 23:46                 ` Juri Linkov
2021-07-14  4:30                   ` Eli Zaretskii
2021-07-14 23:37                     ` Juri Linkov
2021-07-15  6:22                       ` Eli Zaretskii
2021-07-15 22:23                         ` Juri Linkov
2021-07-16  6:49                           ` Eli Zaretskii
2021-07-16 18:59                             ` Juri Linkov
2021-07-16 20:05                               ` [External] : " Drew Adams
2021-07-18  5:13                               ` Tak Kunihiro
2021-07-18 15:53                                 ` Stefan Monnier
2021-07-19 15:55                                   ` Juri Linkov
2021-07-19 16:37                                     ` Stefan Monnier
2021-07-20 20:52                                       ` Juri Linkov
2021-07-20 22:24                                         ` Stefan Monnier
2021-07-20 23:15                                           ` Juri Linkov
2021-07-21  4:39                                             ` Tak Kunihiro
2021-07-21  5:07                                               ` [External] : " Drew Adams
2021-07-21 12:45                                               ` Stefan Monnier
2021-07-21 17:26                                                 ` [External] : " Drew Adams
2021-07-22  3:49                                                   ` Tak Kunihiro
2021-07-22  4:06                                                     ` [External] : " Drew Adams
2021-07-19 19:59                                     ` Ergus via Emacs development discussions.
2021-07-20 20:51                                       ` Juri Linkov
2021-07-12 22:32           ` Stefan Monnier
2021-07-12 23:56             ` Juri Linkov
2021-07-13  3:01               ` Stefan Monnier
2021-07-13 23:32                 ` Juri Linkov
2021-07-14  2:14                   ` Stefan Monnier
2021-07-14 23:32                     ` Juri Linkov
2021-07-15  1:18                       ` Stefan Monnier
2021-07-15 22:31                         ` Juri Linkov
2021-07-16 15:46                           ` Stefan Monnier
2021-07-16 18:50                             ` Juri Linkov
2021-07-16 19:25                               ` Stefan Monnier
2021-07-15  6:24                       ` Eli Zaretskii
2021-07-15 22:28                         ` Juri Linkov
2021-07-16  6:51                           ` Eli Zaretskii
2021-07-16 18:56                             ` Juri Linkov
2021-07-16 23:13                               ` Stefan Kangas
2021-07-17  6:22                                 ` Eli Zaretskii
2021-07-17 21:46                                   ` Juri Linkov
2021-07-17  6:02                               ` Eli Zaretskii
2021-07-19 17:48                                 ` Stefan Kangas
2021-07-19 18:08                                   ` Stefan Monnier
2020-09-14 15:10   ` Context menus and mouse-3 [was: Changes for emacs 28] Eli Zaretskii
2020-09-14 16:42     ` Göktuğ Kayaalp
2020-09-14  8:15 ` Göktuğ Kayaalp
2020-09-14  8:33   ` tomas
2020-09-14 15:57   ` Drew Adams
2020-09-15 19:17     ` Juri Linkov
2020-09-15 20:33       ` Drew Adams
2020-09-15 22:47         ` Ergus via Emacs development discussions.
2020-09-16  0:29           ` Corwin Brust
2020-09-16  1:47             ` Drew Adams
2020-09-16  1:25           ` Drew Adams
2020-09-16  8:10             ` Ergus
2020-09-16 15:02               ` Drew Adams
2020-09-17  3:57               ` Richard Stallman
2020-09-17 20:10                 ` Ergus
2020-09-17 21:58                   ` Philip K.
2020-09-17  3:51             ` Richard Stallman
2020-09-16 14:13           ` Eli Zaretskii
2020-09-16 19:41         ` Juri Linkov
2020-09-16  2:24       ` Eli Zaretskii
2020-09-16 19:35         ` Juri Linkov
2020-09-16 23:10           ` Dmitry Gutov
2020-09-17  3:58           ` Richard Stallman
2020-09-17  7:48             ` Juri Linkov
2020-09-17 20:13               ` Ergus
2020-09-18  8:19                 ` Juri Linkov
2020-09-18 10:53               ` Stefan Kangas
2020-09-19  4:01                 ` Richard Stallman
  -- strict thread matches above, loose matches on Subject: below --
2020-09-16  6:28 Context menus and mouse-3 Tak Kunihiro
2020-09-16 14:18 ` Eli Zaretskii
2020-09-16 14:37   ` Thibaut Verron
2020-09-16 15:06     ` Eli Zaretskii
2020-09-16 15:39       ` Thibaut Verron
2020-09-17  3:57     ` Richard Stallman
2020-09-16 19:45 ` Juri Linkov
2020-09-16 23:49   ` Tak Kunihiro
2020-09-17  2:33     ` Tak Kunihiro
2020-09-17  7:43     ` Juri Linkov
2020-09-17  9:22       ` Robert Pluim
2020-09-17 18:59         ` Juri Linkov
2020-09-17 19:41       ` chad
2020-09-18  8:23         ` Juri Linkov
2020-09-18 18:41           ` chad

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).