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

Fully support use of workspace/configuration #512

Merged
merged 10 commits into from
Aug 24, 2023
Merged

Conversation

michaelpj
Copy link
Collaborator

lsp will now rely primarily on workspace/configuration to get configuration from the client. See Note [LSP configuration] for details.

lsp-test also now handles workspace/configuration properly.

Fixes #510

I'm working on the HLS patch, we shouldn't merge this until that's working. But I'm fairly sure that the lsp and lsp-test changes are good, so I'm putting this up for review.

`lsp` will now rely primarily on `workspace/configuration` to get
configuration from the client. See `Note [LSP configuration]` for
details.

`lsp-test` also now handles `workspace/configuration` properly.
Copy link
Contributor

@July541 July541 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This pr overall is masterful, every part looks pretty well!

Here are just some of my curious questions.

import Language.LSP.Protocol.Utils.SMethodMap (SMethodMap)
import qualified Language.LSP.Protocol.Utils.SMethodMap as SMethodMap
import Language.LSP.VFS
import Language.LSP.Diagnostics
import System.Random hiding (next)
import Control.Monad.Trans.Identity
import Control.Monad.Catch (MonadMask, MonadCatch, MonadThrow)
import Prettyprinter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Format?

lsp/src/Language/LSP/Server/Core.hs Show resolved Hide resolved
pretty (ConfigurationNotSupported) = "LSP: not requesting configuration since the client does not support workspace/configuration"
pretty (ConfigurationParseError settings err) =
vsep [
"LSP: configuration parse error:"

This comment was marked as resolved.

lsp/src/Language/LSP/Server/Core.hs Show resolved Hide resolved
, viaShow settings
]
pretty (BadConfigurationResponse err) = "LSP: error when requesting configuration: " <+> viaShow err
pretty (WrongConfigSections sections) = "LSP: expected only one configuration section, got: " <+> viaShow sections
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pretty (WrongConfigSections sections) = "LSP: expected only one configuration section, got: " <+> viaShow sections
pretty (WrongConfigSections sections) = "LSP: expect only one configuration section, got: " <+> viaShow sections

Maybe?

SMethod_WorkspaceDidChangeConfiguration -> handle' logger (Just $ handleConfigChange logger) m msg
SMethod_WorkspaceDidChangeConfiguration -> handle' logger (Just $ handleDidChangeConfiguration logger) m msg
-- See Note [LSP configuration]
SMethod_Initialized -> handle' logger (Just $ \_ -> requestConfigUpdate (cmap (fmap LspCore) logger)) m msg
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are requesting config update for every time initialized, considering downstream users, should we mark this as optional?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initialized gets sent only once, which is when client receives our response to initialize. So this is a one-off thing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, it's not a big deal.

section <- LspT $ asks resConfigSection
tryChangeConfig (cmap (fmap LspCore) logger) (lookForConfigSection section $ req ^. L.params . L.settings)
-- See Note [LSP configuration]
requestConfigUpdate (cmap (fmap LspCore) logger)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused about why also we need requestConfigUpdate if tryChangeConfig succeeds.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that's a good question. I guess if we actually manage to parse out what's in didChangeConfiguration then we probably don't need to request new config 🤔

Or maybe we should just fully commit to using workspace/configuration and not look in the body of didChangeConfiguration at all. That seems to be the way that the spec maintainers want us to go...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that's right, I wanted to support clients that don't handle workspace/configuration. So then parsing it out of didChangeConfiguration is important.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still confused here.. tryChangeConfig has updated the config, is there any situation we still need requestConfigUpdate?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll write it out in detail in the doc. Basically, all of the following are "allowable" scenarios:

  1. Client supports workspace/configuration, sends an empty update in didChangeConfiguration. This is what new vscode will do, I believe. Then the first attempt will fail (nothing in didChange), and the second will succeed (requesting config).
  2. Client does not support workspace/configuration, and sends updated config in didChangeConfiguration. This is rare, I think, but we should support it. Then the first attempt will succeed and the second attempt will fail (or not even try).

We do get some redundancy in the slightly odd case of a client that supports both ways, but I'm not too worried about that tbh.

import Control.Monad.State
import Control.Monad.Writer.Strict
import Data.Foldable (traverse_)
import Data.String (fromString)

This comment was marked as resolved.

-- indicating what went wrong. The parsed configuration object will be
-- stored internally and can be accessed via 'config'.
-- It is also called on the `initializationOptions` field of the InitializeParams
, configSection :: T.Text
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this always have the same value with resConfigSection?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we copy over a bunch of fields from ServerDefinition into LanguageContextEnv...

| ProgressCancel ProgressToken
| Exiting

deriving instance Show LspProcessingLog

instance Pretty LspProcessingLog where
pretty (VfsLog l) = pretty l
pretty (LspCore l) = pretty l
pretty (MessageProcessingError bs err) =
vsep [
"LSP: incoming message parse error:"

This comment was marked as resolved.

@michaelpj michaelpj merged commit a81ea6d into master Aug 24, 2023
15 checks passed
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 this pull request may close these issues.

Support workspace/configuration request for every server initilize
2 participants