* 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: [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 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: 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 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-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
* 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-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
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).