unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* How to define a (derived) minor mode inaccessible to the user
@ 2021-01-22  5:11 Marcin Borkowski
  2021-01-22  5:34 ` [External] : " Drew Adams
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Marcin Borkowski @ 2021-01-22  5:11 UTC (permalink / raw)
  To: Help Gnu Emacs mailing list

Hello everyone,

I'd like to define a special-purpose major mode, derived from
`special-mode', in such a way that the user cannot set it using M-x.
(It is to be called via another command.)  It seems that
`define-derived-mode' always sets the mode as `interactive'.  I tried to
define my mode using

(define-derived-mode
  my--mode
  special-mode
  "My mode")

and then did

M-: (symbol-plist 'my--mode)

expecting an `interactive-form' entry on the plist - but it was not
there.  (I wanted to remove it from the list so that it can't be called
with M-x.)

What's going on?  Is it possible to define a (derived) major mode so
that it can't be called interactively?

TIA,

--
Marcin Borkowski
http://mbork.pl



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

* RE: [External] : How to define a (derived) minor mode inaccessible to the user
  2021-01-22  5:11 How to define a (derived) minor mode inaccessible to the user Marcin Borkowski
@ 2021-01-22  5:34 ` Drew Adams
  2021-01-22 15:01   ` Marcin Borkowski
  2021-01-22 14:19 ` Stefan Monnier
  2021-01-23 13:08 ` Michael Heerdegen
  2 siblings, 1 reply; 10+ messages in thread
From: Drew Adams @ 2021-01-22  5:34 UTC (permalink / raw)
  To: Marcin Borkowski, Help Gnu Emacs mailing list

FYI: your Subject line says "minor mode" but your
message content speaks of "major mode".  I think
you mean only the latter, no?




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

* Re: How to define a (derived) minor mode inaccessible to the user
  2021-01-22  5:11 How to define a (derived) minor mode inaccessible to the user Marcin Borkowski
  2021-01-22  5:34 ` [External] : " Drew Adams
@ 2021-01-22 14:19 ` Stefan Monnier
  2021-01-22 15:23   ` Marcin Borkowski
  2021-01-23 13:08 ` Michael Heerdegen
  2 siblings, 1 reply; 10+ messages in thread
From: Stefan Monnier @ 2021-01-22 14:19 UTC (permalink / raw)
  To: help-gnu-emacs

> I'd like to define a special-purpose major mode, derived from
> `special-mode', in such a way that the user cannot set it using M-x.

Can you explain why?

> (It is to be called via another command.)

That doesn't explain why it would be harmful to also expose the actual
major mode command.

E.g. You can do `M-x comint-mode` even though it likely won't do you
much good since `comint-mode` needs to be used together with a process
and is hence normally enabled by the command that launches the process.

> It seems that `define-derived-mode' always sets the mode as
> `interactive'.

Indeed.

> M-: (symbol-plist 'my--mode)
> expecting an `interactive-form' entry on the plist

The `interactive-form` property is virtually never used.  Instead, the
interactive form is traditionally stored within the function.

If you *really* care about hiding the major mode from the user
I suggest you use an "obscure" or "scary" name.

> What's going on?  Is it possible to define a (derived) major mode so
> that it can't be called interactively?

Of course it is:

    (define-derived-mode my-mode "My" "My doc.")
    (defconst my-mode (symbol-function 'my-mode))
    (fmakunbound 'my-mode)

and then you can enable the mode with `(funcall my-mode)`.


        Stefan




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

* Re: [External] : How to define a (derived) minor mode inaccessible to the user
  2021-01-22  5:34 ` [External] : " Drew Adams
@ 2021-01-22 15:01   ` Marcin Borkowski
  0 siblings, 0 replies; 10+ messages in thread
From: Marcin Borkowski @ 2021-01-22 15:01 UTC (permalink / raw)
  To: Drew Adams; +Cc: Help Gnu Emacs mailing list


On 2021-01-22, at 06:34, Drew Adams <drew.adams@oracle.com> wrote:

> FYI: your Subject line says "minor mode" but your
> message content speaks of "major mode".  I think
> you mean only the latter, no?

Yes, sorry, my bad.

-- 
Marcin Borkowski
http://mbork.pl



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

* Re: How to define a (derived) minor mode inaccessible to the user
  2021-01-22 14:19 ` Stefan Monnier
@ 2021-01-22 15:23   ` Marcin Borkowski
  2021-01-22 15:38     ` Stefan Monnier
  0 siblings, 1 reply; 10+ messages in thread
From: Marcin Borkowski @ 2021-01-22 15:23 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs


On 2021-01-22, at 15:19, Stefan Monnier <monnier@iro.umontreal.ca> wrote:

>> I'd like to define a special-purpose major mode, derived from
>> `special-mode', in such a way that the user cannot set it using M-x.
>
> Can you explain why?

Because I woulnd't like the user to accidentally turn it on?  (It might
be a bit of OCD on my part, too.)  Also, because I didn't know how to do
it and the very fact bugged me a bit;-).  Also, see below.

>> (It is to be called via another command.)
>
> That doesn't explain why it would be harmful to also expose the actual
> major mode command.

Maybe not harmful, but here's another argument: assume that I have this
new mode, let's call it "blue-mode", with all its commands named
"blue-...", and the entry point being the command "blue-display".  Now,
when the user says M-x blue- TAB, "blue-mode" will show up and pollute
the list (meaning: it will occupy some room on the list while being
useless, since blue-display is what user really wants to start using
blue-mode).

> E.g. You can do `M-x comint-mode` even though it likely won't do you
> much good since `comint-mode` needs to be used together with a process
> and is hence normally enabled by the command that launches the process.
>
>> It seems that `define-derived-mode' always sets the mode as
>> `interactive'.
>
> Indeed.
>
>> M-: (symbol-plist 'my--mode)
>> expecting an `interactive-form' entry on the plist
>
> The `interactive-form` property is virtually never used.  Instead, the
> interactive form is traditionally stored within the function.

So how does `execute-extended-command' know what to list, then?
A cursory look told me that it uses `read-extended-command', which uses
`commandp'.  So, how does `commandp' know?  (I'm not well versed in C,
but do I guess correctly that it checks the `interactive-form' property,
and if nil, it (somehow) looks for `(interactive ...)' in its
definition?)

> If you *really* care about hiding the major mode from the user
> I suggest you use an "obscure" or "scary" name.

Well, the convention is to use two dashes, but how can the end-user (not
knowing Elisp and the conventions) know that?

>> What's going on?  Is it possible to define a (derived) major mode so
>> that it can't be called interactively?
>
> Of course it is:
>
>     (define-derived-mode my-mode "My" "My doc.")
>     (defconst my-mode (symbol-function 'my-mode))
>     (fmakunbound 'my-mode)
>
> and then you can enable the mode with `(funcall my-mode)`.

So, basically you move the function definition from the function cell to
the value cell of `my-mode', right?  Clever!  Is it actually used
anywhere in Emacs?

Thanks,

--
Marcin Borkowski
http://mbork.pl



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

* Re: How to define a (derived) minor mode inaccessible to the user
  2021-01-22 15:23   ` Marcin Borkowski
@ 2021-01-22 15:38     ` Stefan Monnier
  2021-01-28  7:42       ` Marcin Borkowski
  0 siblings, 1 reply; 10+ messages in thread
From: Stefan Monnier @ 2021-01-22 15:38 UTC (permalink / raw)
  To: Marcin Borkowski; +Cc: help-gnu-emacs

>> The `interactive-form` property is virtually never used.  Instead, the
>> interactive form is traditionally stored within the function.
> So how does `execute-extended-command' know what to list, then?

You can use `commandp` to know if it's got an interactive form or not,
and `interactive-form` (the function) to extract it from a function.

> A cursory look told me that it uses `read-extended-command', which uses
> `commandp'.  So, how does `commandp' know?  (I'm not well versed in C,
> but do I guess correctly that it checks the `interactive-form' property,
> and if nil, it (somehow) looks for `(interactive ...)' in its
> definition?)

Pretty much, yes (with the extra handling for the cases where the
function is not a `(lambda ...)` list but a byte-compiled object, or an
autoloaded function, or a function implemented in C).

>> If you *really* care about hiding the major mode from the user
>> I suggest you use an "obscure" or "scary" name.
> Well, the convention is to use two dashes, but how can the end-user (not
> knowing Elisp and the conventions) know that?

That's indeed the convention for functions.  For commands we don't
really have a convention for "commands that should be hidden from `M-x".
We used to prevent completion from revealing obsolete commands.
It's been reverted recently (to my disappointment), but we could add
a similar feature for "commands not to be used via M-x" (could be used
for those commands that only work when bound to a mouse event, for
example).

Maybe `smex` offers something like that.  When I rewrote
`execute-extended-command' into Elisp, I hoped that it would encourage
people to hack on it and add features to it (like this one), but sadly
it doesn't seem to have had much effect of this kind so far.

We could add some property that holds a predicate function which
`execute-extended-command' could use to filter out commands which can't
be used in the current context (e.g. the predicate could check the
major mode, for those commands which only work in a given major mode).

> So, basically you move the function definition from the function cell to
> the value cell of `my-mode', right?  Clever!  Is it actually used
> anywhere in Emacs?

No, and I don't recommend it.
E.g `C-h m` will then fail to show the proper docstring of the major mode.


        Stefan




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

* Re: How to define a (derived) minor mode inaccessible to the user
  2021-01-22  5:11 How to define a (derived) minor mode inaccessible to the user Marcin Borkowski
  2021-01-22  5:34 ` [External] : " Drew Adams
  2021-01-22 14:19 ` Stefan Monnier
@ 2021-01-23 13:08 ` Michael Heerdegen
  2021-01-28  7:45   ` Marcin Borkowski
  2 siblings, 1 reply; 10+ messages in thread
From: Michael Heerdegen @ 2021-01-23 13:08 UTC (permalink / raw)
  To: Marcin Borkowski; +Cc: Help Gnu Emacs mailing list

Marcin Borkowski <mbork@mbork.pl> writes:

> Hello everyone,
>
> I'd like to define a special-purpose major mode, derived from
> `special-mode', in such a way that the user cannot set it using M-x.
> (It is to be called via another command.)

I wonder if that feature then does have to be defined as a regular mode
at all, or if something else would fit: if there could be some other
solution to what you want.

Second point: If it's really bad for the user to enable the mode, give
it a name like "*-helper-mode" or so, and I guess you could add
something like

(when (called-interactively-p 'any)
  (user-error "This mode is for internal use only"))

to the mode function's body.

Michael.



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

* Re: How to define a (derived) minor mode inaccessible to the user
  2021-01-22 15:38     ` Stefan Monnier
@ 2021-01-28  7:42       ` Marcin Borkowski
  2021-01-28 14:31         ` Stefan Monnier
  0 siblings, 1 reply; 10+ messages in thread
From: Marcin Borkowski @ 2021-01-28  7:42 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs


On 2021-01-22, at 16:38, Stefan Monnier <monnier@iro.umontreal.ca> wrote:

>>> The `interactive-form` property is virtually never used.  Instead, the
>>> interactive form is traditionally stored within the function.
>> So how does `execute-extended-command' know what to list, then?
>
> You can use `commandp` to know if it's got an interactive form or not,
> and `interactive-form` (the function) to extract it from a function.
>
>> A cursory look told me that it uses `read-extended-command', which uses
>> `commandp'.  So, how does `commandp' know?  (I'm not well versed in C,
>> but do I guess correctly that it checks the `interactive-form' property,
>> and if nil, it (somehow) looks for `(interactive ...)' in its
>> definition?)
>
> Pretty much, yes (with the extra handling for the cases where the
> function is not a `(lambda ...)` list but a byte-compiled object, or an
> autoloaded function, or a function implemented in C).

OK, thanks.

>>> If you *really* care about hiding the major mode from the user
>>> I suggest you use an "obscure" or "scary" name.
>> Well, the convention is to use two dashes, but how can the end-user (not
>> knowing Elisp and the conventions) know that?
>
> That's indeed the convention for functions.  For commands we don't
> really have a convention for "commands that should be hidden from `M-x".
> We used to prevent completion from revealing obsolete commands.
> It's been reverted recently (to my disappointment), but we could add
> a similar feature for "commands not to be used via M-x" (could be used
> for those commands that only work when bound to a mouse event, for
> example).
>
> Maybe `smex` offers something like that.  When I rewrote
> `execute-extended-command' into Elisp, I hoped that it would encourage
> people to hack on it and add features to it (like this one), but sadly
> it doesn't seem to have had much effect of this kind so far.
>
> We could add some property that holds a predicate function which
> `execute-extended-command' could use to filter out commands which can't
> be used in the current context (e.g. the predicate could check the
> major mode, for those commands which only work in a given major mode).
>
>> So, basically you move the function definition from the function cell to
>> the value cell of `my-mode', right?  Clever!  Is it actually used
>> anywhere in Emacs?
>
> No, and I don't recommend it.
> E.g `C-h m` will then fail to show the proper docstring of the major mode.

I see.  Still interesting.

Thanks,

-- 
Marcin Borkowski
http://mbork.pl



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

* Re: How to define a (derived) minor mode inaccessible to the user
  2021-01-23 13:08 ` Michael Heerdegen
@ 2021-01-28  7:45   ` Marcin Borkowski
  0 siblings, 0 replies; 10+ messages in thread
From: Marcin Borkowski @ 2021-01-28  7:45 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: Help Gnu Emacs mailing list


On 2021-01-23, at 14:08, Michael Heerdegen <michael_heerdegen@web.de> wrote:

> Marcin Borkowski <mbork@mbork.pl> writes:
>
>> Hello everyone,
>>
>> I'd like to define a special-purpose major mode, derived from
>> `special-mode', in such a way that the user cannot set it using M-x.
>> (It is to be called via another command.)
>
> I wonder if that feature then does have to be defined as a regular mode
> at all, or if something else would fit: if there could be some other
> solution to what you want.

Well, I could just use special-mode instead of a custom, derived one.
But I think it would not be good practice - I assume special-mode is not
to be used directly but only to create derived modes.

> Second point: If it's really bad for the user to enable the mode, give
> it a name like "*-helper-mode" or so, and I guess you could add
> something like
>
> (when (called-interactively-p 'any)
>   (user-error "This mode is for internal use only"))
>
> to the mode function's body.

Nice, thanks!

It's not that it would be _bad_ for the user.  It just doesn't make any
sense.  And given that people sometimes do things by accident, and not
everyone knows about view-lossage etc., making it impossible/hard to
turn such a mode manually seems reasonable.

Best,

-- 
Marcin Borkowski
http://mbork.pl



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

* Re: How to define a (derived) minor mode inaccessible to the user
  2021-01-28  7:42       ` Marcin Borkowski
@ 2021-01-28 14:31         ` Stefan Monnier
  0 siblings, 0 replies; 10+ messages in thread
From: Stefan Monnier @ 2021-01-28 14:31 UTC (permalink / raw)
  To: Marcin Borkowski; +Cc: help-gnu-emacs

>> No, and I don't recommend it.
>> E.g `C-h m` will then fail to show the proper docstring of the major mode.
>
> I see.  Still interesting.

I think removing the major mode from the completions offered by `M-x` is
the best option, and adding that possibility would be a useful
improvement to `M-x` for other purposes as well, so I'd welcome a patch
that does that.

The patch below installed a few months back should get you started: it
removed a functionality by which M-x refrained from completing
obsolete commands.

So you could get what you want by reverting that patch and changing it
so it hides commands marked with some new property instead of commands
marked as obsolete.


        Stefan


diff --git a/lisp/simple.el b/lisp/simple.el
index b5002dd189..16ff8637b9 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -1881,22 +1881,17 @@ read-extended-command
 	   '(metadata
 	     (annotation-function . read-extended-command--annotation)
 	     (category . command))
-         (let ((pred
-                (if (memq action '(nil t))
-                    ;; Exclude obsolete commands from completions.
-                    (lambda (sym)
-                      (and (funcall pred sym)
-                           (or (equal string (symbol-name sym))
-                               (not (get sym 'byte-obsolete-info)))))
-                  pred)))
-           (complete-with-action action obarray string pred))))
+         (complete-with-action action obarray string pred)))
      #'commandp t nil 'extended-command-history)))
 
 (defun read-extended-command--annotation (command-name)
-  (let* ((function (and (stringp command-name) (intern-soft command-name)))
-         (binding (where-is-internal function overriding-local-map t)))
-    (when (and binding (not (stringp binding)))
-      (format " (%s)" (key-description binding)))))
+  (let* ((fun (and (stringp command-name) (intern-soft command-name)))
+         (binding (where-is-internal fun overriding-local-map t))
+         (obsolete (get fun 'byte-obsolete-info)))
+    (cond (obsolete
+           (format " (%s)" (car obsolete)))
+          ((and binding (not (stringp binding)))
+           (format " (%s)" (key-description binding))))))
 
 (defcustom suggest-key-bindings t
   "Non-nil means show the equivalent key-binding when M-x command has one.




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

end of thread, other threads:[~2021-01-28 14:31 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-01-22  5:11 How to define a (derived) minor mode inaccessible to the user Marcin Borkowski
2021-01-22  5:34 ` [External] : " Drew Adams
2021-01-22 15:01   ` Marcin Borkowski
2021-01-22 14:19 ` Stefan Monnier
2021-01-22 15:23   ` Marcin Borkowski
2021-01-22 15:38     ` Stefan Monnier
2021-01-28  7:42       ` Marcin Borkowski
2021-01-28 14:31         ` Stefan Monnier
2021-01-23 13:08 ` Michael Heerdegen
2021-01-28  7:45   ` Marcin Borkowski

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).