Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lsp-interface generates a lot of noise in pcase documentation #4430

Closed
chrisbouchard opened this issue Apr 16, 2024 · 10 comments · Fixed by #4559
Closed

lsp-interface generates a lot of noise in pcase documentation #4430

chrisbouchard opened this issue Apr 16, 2024 · 10 comments · Fixed by #4559

Comments

@chrisbouchard
Copy link
Contributor

chrisbouchard commented Apr 16, 2024

Is your feature related or already mentioned on the wishlist? — No, I don't believe so.

TL;DR

I'd like to consider if there's a way lsp-mode could be (or could evolve to be) more conscientious with its use of pcase-defmacro.

Context

I recently opened the function documentation for pcase in my Emacs (to read about the map pattern). I noticed that, interspersed with the standard documentation, there was a lot of “noise” like:

-- (WatchKind &rest PROPERTY-BINDINGS)

Not documented.

-- (CodeAction &rest PROPERTY-BINDINGS)

Not documented.

-- (JSONError &rest PROPERTY-BINDINGS)

Not documented.

To quantify, the function documentation for `pcase' in my Emacs is just under 1300 lines long, of which about 1200 are these auto-generated patterns.

I didn't know where these patterns came from at first, but a quick Google for “emacs WatchKind” lead me to lsp-protocol.el, and from there I found the pcase-macro in lsp-interface (added in #2481). pcase-defmacro includes each new pattern into pcase's function documentation for discoverability.

As a user, this is not a great experience. It's important to me that the pcase function documentation be readable, because it's the primary in-editor way that I can discover what patterns are available (including via extensions). I do appreciate that these are technically patterns that are available, but I get the sense they weren't really intended for general consumption, and anyway their sheer number overwhelms any usefulness in documenting them like this.

Also, since these patterns aren't namespaced, there's (a) no indication that they belong to this project, and (b) no guarantee they don't collide with patterns defined by a different package.

My Ideal Solution

Forgetting for a moment that there is already code using the existing patterns, I would love if lsp-interface followed the approach used by cl-struct and defined a single pcase pattern like (lsp-interface INTERFACE &rest PROPERTY-BINDINGS). This pcase-defmacro could include a proper docstring—e.g., describing its use and the forms allowed as property bindings. It would also address the namespacing concern. And most importantly (for me), it would be a single entry in the pcase function documentation rather than hundreds.

I imagine that the current generated pcase-defmacro in lsp-interface could be repurposed as a generated lsp-interface--pcase-pattern-INTERFACE function, to which the lsp-interface pattern could delegate based on its interface parameter. (This would happen during macro compilation, so there wouldn't be a runtime cost for the indirection.)

So for example, code like

(pcase expr
  ((JSONError :message :code) ...))

would instead be written

(pcase expr
  ((lsp-interface JSONError :message :code) ...))

and expand to the exact same base pcase patterns.

Something Practical?

Returning to the real world, I appreciate that my suggestion would be a breaking change. I suppose the first question is: Does my suggestion seem palatable? My primary goal is to keep the pcase function documentation readable, so I'm not married to it in particular—I'm just not sure there's a solution other than to reduce the number of patterns defined. (For example, I think it would be a non-starter to simply include a docstring in the existing pcase-defmacro, since that would add hundreds more lines of repeated documentation to pcase's documentation.)

Also, as a newcomer to lsp-mode's development, are these interface patterns intended to be used outside of lsp-mode itself? I did a quick GitHub code search and only found a couple uses in lsp-mode itself. I also couldn't find the feature mentioned in the changelog or documentation. If this isn't a supported feature, maybe a breaking change wouldn't be too painful?

Alternatively, I imagine a new lsp-interface pattern could be added along side the existing patterns, which could then be deprecated. For example, the existing pcase-defmacro body could be turned into the generated lsp-interface--pcase-pattern-INTERFACE function, and the pcase-defmacro repurposed to return a new lsp-interface pattern.

Thanks for your attention and feedback. Whatever the path forward, I'll be happy to contribute—I don't mean this to be a rant or demand! I'll probably start poking at the deprecation approach when I get some free time.

@chrisbouchard chrisbouchard changed the title lsp-interface generates a lot of noise in pcase lsp-interface generates a lot of noise in pcase documentation Apr 16, 2024
@iNecas
Copy link
Contributor

iNecas commented Jul 26, 2024

I'm recently experiencing performance issues in Emacs every time generating a documentation for pcase is needed. I've narrowed the issue down to when calling (documentation 'pcase), which can easily take tens of seconds, and eventually causes issues in code completion or searching documentation via helpful functions. I don't have a final proof, but I highly suspect lsp-mode adding so many pcases there is contributing a lot to it.

Running emacs master branch on 2024-07-15 eae1104f97ef944127eb5c977129b55f137e0830 and I see couple of changes in pcase recently, so it might be contributing to this.

@kiennq
Copy link
Member

kiennq commented Sep 21, 2024

I like your proposal especially when it has the precedent of cl-struct.
Would you be willing to provide a PR for that? This will be a breaking change, but it would gear toward a better functionality as well documentation readability for pcase.
@leungbk as well.

@chrisbouchard
Copy link
Contributor Author

chrisbouchard commented Sep 22, 2024

@kiennq Yeah! I started looking into it a bit last week. I can say that there doesn't seem to be any way to deprecate a pcase form defined with pcase-defmacro, like one would a normal function or macro, so that's something that would need to be communicated separately.

(I tried using (declare (obsolete …)), and also make-obsolete on the NAME--pcase-macroexpander function it generates. Unfortunately the byte compiler never actually sees a (NAME--pcase-macroexpander …) form when compiling (pcase … ((NAME …))—the NAME--pcase-macroexpander function is called directly while expanding the pcase macro—so there's no deprecation warning. Also, the way that pcase builds its docstring means it won't generate a deprecation warning there either.)

@dgutov
Copy link

dgutov commented Sep 22, 2024

Maybe deprecating is not much as issue, if the macros are only used in the same package.

@chrisbouchard
Copy link
Contributor Author

chrisbouchard commented Sep 23, 2024

That's actually something I'm unclear on: are these pcase forms part of lsp-mode's public interface? Or are they only an internal implementation detail? I'm only an lsp-mode end user, so I'm not familiar with the conventions.

I was planning to keep the old pcase forms around in this PR, delegating to the new one—then they could be dropped in the next major version. If they are only meant to be used internally, then maybe we can just drop them now. (Though, of course, Hyrum's Law might apply…)

chrisbouchard added a commit to chrisbouchard/lsp-mode that referenced this issue Sep 23, 2024
This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to
replace the old per-interface (INTERFACE ...) forms -- the latter are now
deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as
obsolete.)

I've turned the existing pcase-defmacro definition into a helper function. The
new pcase form delegates to that helper function, and the old pcase forms now
delegate to the new form.

This change addresses a few issues, which are detailed in emacs-lsp#4430. In short:

* The existing forms aren't namespaced.
* The lsp-mode package adds hundreds of forms, which each add several lines to
pcase's generated docstring, adding up to over 1000 lines.
* Starting in Emacs 1.31, the number of forms added by lsp-mode causes a
noticeable slowdown when loading the interactive help for pcase.
@chrisbouchard
Copy link
Contributor Author

I just opened #4559 as a draft. It currently adds the new (lsp-interface INTERFACE ...) pcase form and preserves the old per-interface forms as well. I'll start replacing uses of the old pcase forms in lsp-mode next.

chrisbouchard added a commit to chrisbouchard/lsp-mode that referenced this issue Sep 23, 2024
This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to
replace the old per-interface (INTERFACE ...) forms -- the latter are now
deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as
obsolete.)

I've turned the existing pcase-defmacro definition into a helper function. The
new pcase form delegates to that helper function, and the old pcase forms now
delegate to the new form.

This change addresses a few issues, which are detailed in emacs-lsp#4430. In short:

* The existing forms aren't namespaced.
* The lsp-mode package adds hundreds of forms, which each add several lines to
pcase's generated docstring, adding up to over 1000 lines.
* Starting in Emacs 1.31, the number of forms added by lsp-mode causes a
noticeable slowdown when loading the interactive help for pcase.
chrisbouchard added a commit to chrisbouchard/lsp-mode that referenced this issue Sep 23, 2024
This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to
replace the old per-interface (INTERFACE ...) forms -- the latter are now
deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as
obsolete.)

I've turned the existing pcase-defmacro definition into a helper function. The
new pcase form delegates to that helper function, and the old pcase forms now
delegate to the new form.

This change addresses a few issues, which are detailed in emacs-lsp#4430. In short:

* The existing forms aren't namespaced.
* The lsp-mode package adds hundreds of forms, which each add several lines to
pcase's generated docstring, adding up to over 1000 lines.
* Starting in Emacs 1.31, the number of forms added by lsp-mode causes a
noticeable slowdown when loading the interactive help for pcase.
@kiennq
Copy link
Member

kiennq commented Sep 23, 2024

@yyoncho @leungbk, is it okay to drop support for the old pcase form? It makes Emacs slower (might be due to a bug in the new version) and also pollute the pcase docs so more relevant forms are hidden.
We can announce this as a breaking change in the CHANGELOG so broken packages that depends on the old behaviors can fix it if they want.

kiennq added a commit to kiennq/lsp-mode that referenced this issue Sep 23, 2024
* Provide a unified (lsp-interface INTERFACE ...) pcase form

This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to
replace the old per-interface (INTERFACE ...) forms -- the latter are now
deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as
obsolete.)

I've turned the existing pcase-defmacro definition into a helper function. The
new pcase form delegates to that helper function, and the old pcase forms now
delegate to the new form.

This change addresses a few issues, which are detailed in emacs-lsp#4430. In short:

* The existing forms aren't namespaced.
* The lsp-mode package adds hundreds of forms, which each add several lines to
pcase's generated docstring, adding up to over 1000 lines.
* Starting in Emacs 1.31, the number of forms added by lsp-mode causes a
noticeable slowdown when loading the interactive help for pcase.

* Add a comment and TODO about deprecating per-interface pcase forms

* Improve docstring for (lsp-interface ...) pcase form

I've tried to summarize the behavior of the existing implementation.

---------

Co-authored-by: Chris Bouchard <chris@upliftinglemma.net>
kiennq added a commit to kiennq/lsp-mode that referenced this issue Sep 23, 2024
* Provide a unified (lsp-interface INTERFACE ...) pcase form

This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to
replace the old per-interface (INTERFACE ...) forms -- the latter are now
deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as
obsolete.)

I've turned the existing pcase-defmacro definition into a helper function. The
new pcase form delegates to that helper function, and the old pcase forms now
delegate to the new form.

This change addresses a few issues, which are detailed in emacs-lsp#4430. In short:

* The existing forms aren't namespaced.
* The lsp-mode package adds hundreds of forms, which each add several lines to
pcase's generated docstring, adding up to over 1000 lines.
* Starting in Emacs 1.31, the number of forms added by lsp-mode causes a
noticeable slowdown when loading the interactive help for pcase.

* Add a comment and TODO about deprecating per-interface pcase forms

* Improve docstring for (lsp-interface ...) pcase form

I've tried to summarize the behavior of the existing implementation.

---------

Co-authored-by: Chris Bouchard <chris@upliftinglemma.net>
kiennq added a commit to kiennq/lsp-mode that referenced this issue Sep 23, 2024
* Provide a unified (lsp-interface INTERFACE ...) pcase form

This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to
replace the old per-interface (INTERFACE ...) forms -- the latter are now
deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as
obsolete.)

I've turned the existing pcase-defmacro definition into a helper function. The
new pcase form delegates to that helper function, and the old pcase forms now
delegate to the new form.

This change addresses a few issues, which are detailed in emacs-lsp#4430. In short:

* The existing forms aren't namespaced.
* The lsp-mode package adds hundreds of forms, which each add several lines to
pcase's generated docstring, adding up to over 1000 lines.
* Starting in Emacs 1.31, the number of forms added by lsp-mode causes a
noticeable slowdown when loading the interactive help for pcase.

* Add a comment and TODO about deprecating per-interface pcase forms

* Improve docstring for (lsp-interface ...) pcase form

I've tried to summarize the behavior of the existing implementation.

---------

Co-authored-by: Chris Bouchard <chris@upliftinglemma.net>
@leungbk
Copy link
Member

leungbk commented Sep 23, 2024 via email

kiennq added a commit to kiennq/lsp-mode that referenced this issue Sep 23, 2024
* Provide a unified (lsp-interface INTERFACE ...) pcase form

This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to
replace the old per-interface (INTERFACE ...) forms -- the latter are now
deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as
obsolete.)

I've turned the existing pcase-defmacro definition into a helper function. The
new pcase form delegates to that helper function, and the old pcase forms now
delegate to the new form.

This change addresses a few issues, which are detailed in emacs-lsp#4430. In short:

* The existing forms aren't namespaced.
* The lsp-mode package adds hundreds of forms, which each add several lines to
pcase's generated docstring, adding up to over 1000 lines.
* Starting in Emacs 1.31, the number of forms added by lsp-mode causes a
noticeable slowdown when loading the interactive help for pcase.

* Add a comment and TODO about deprecating per-interface pcase forms

* Improve docstring for (lsp-interface ...) pcase form

I've tried to summarize the behavior of the existing implementation.

---------

Co-authored-by: Chris Bouchard <chris@upliftinglemma.net>
@chrisbouchard
Copy link
Contributor Author

I'm OK with dropping the old form.

That does simplify things. 🎉

chrisbouchard added a commit to chrisbouchard/lsp-mode that referenced this issue Sep 24, 2024
The consensus in emacs-lsp#4430 is that we're ok with making this breaking change and
communicating it in the CHANGELOG. I've replaced all uses in lsp-mode itself.
chrisbouchard added a commit to chrisbouchard/lsp-mode that referenced this issue Sep 24, 2024
The consensus in emacs-lsp#4430 is that we're ok with making this breaking change and
communicating it in the CHANGELOG. I've replaced all uses in lsp-mode itself.
chrisbouchard added a commit to chrisbouchard/lsp-mode that referenced this issue Sep 24, 2024
This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to
replace the old per-interface (INTERFACE ...) forms -- the latter are now
deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as
obsolete.)

I've turned the existing pcase-defmacro definition into a helper function. The
new pcase form delegates to that helper function, and the old pcase forms now
delegate to the new form.

This change addresses a few issues, which are detailed in emacs-lsp#4430. In short:

* The existing forms aren't namespaced.
* The lsp-mode package adds hundreds of forms, which each add several lines to
  pcase's generated docstring, adding up to over 1000 lines.
* Starting in Emacs 31, the number of forms added by lsp-mode causes a
  noticeable slowdown when loading the interactive help for pcase.
chrisbouchard added a commit to chrisbouchard/lsp-mode that referenced this issue Sep 24, 2024
The consensus in emacs-lsp#4430 is that we're ok with making this breaking change and
communicating it in the CHANGELOG. I've replaced all uses in lsp-mode itself.
chrisbouchard added a commit to chrisbouchard/lsp-mode that referenced this issue Sep 24, 2024
This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to
replace the old per-interface (INTERFACE ...) forms -- the latter are now
deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as
obsolete.)

I've turned the existing pcase-defmacro definition into a helper function. The
new pcase form delegates to that helper function, and the old pcase forms now
delegate to the new form.

This change addresses a few issues, which are detailed in emacs-lsp#4430. In short:

* The existing forms aren't namespaced.
* The lsp-mode package adds hundreds of forms, which each add several lines to
  pcase's generated docstring, adding up to over 1000 lines.
* Starting in Emacs 31, the number of forms added by lsp-mode causes a
  noticeable slowdown when loading the interactive help for pcase.
chrisbouchard added a commit to chrisbouchard/lsp-mode that referenced this issue Sep 24, 2024
The consensus in emacs-lsp#4430 is that we're ok with making this breaking change and
communicating it in the CHANGELOG. I've replaced all uses in lsp-mode itself.
@chrisbouchard
Copy link
Contributor Author

Sorry for all the commit noise. I think that PR is ready for review. 👍

kiennq pushed a commit that referenced this issue Sep 26, 2024
* Provide a unified (lsp-interface INTERFACE ...) pcase form

This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to
replace the old per-interface (INTERFACE ...) forms -- the latter are now
deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as
obsolete.)

I've turned the existing pcase-defmacro definition into a helper function. The
new pcase form delegates to that helper function, and the old pcase forms now
delegate to the new form.

This change addresses a few issues, which are detailed in #4430. In short:

* The existing forms aren't namespaced.
* The lsp-mode package adds hundreds of forms, which each add several lines to
  pcase's generated docstring, adding up to over 1000 lines.
* Starting in Emacs 31, the number of forms added by lsp-mode causes a
  noticeable slowdown when loading the interactive help for pcase.

* Add a comment and TODO about deprecating per-interface pcase forms

* Improve docstring for (lsp-interface ...) pcase form

I've tried to summarize the behavior of the existing implementation.

* Replace per-interface pcase forms with the new unified form

I used ripgrep to search for all occurrences of `pcase`, and then checked each
to see if it was using a pattern that looked like an LSP interface name. It's
very possible I missed something, but hopefully not.

* Remove the per-interface pcase forms

The consensus in #4430 is that we're ok with making this breaking change and
communicating it in the CHANGELOG. I've replaced all uses in lsp-mode itself.

* Add CHANGELOG entry for pcase changes

I'm an Org newb, so hopefully this is well-formatted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants