@@ -408,6 +408,7 @@ instance PluginMethod Request Method_TextDocumentCodeAction where
408
408
uri = msgParams ^. L. textDocument . L. uri
409
409
410
410
instance PluginMethod Request Method_CodeActionResolve where
411
+ -- See Note [Resolve in PluginHandlers]
411
412
pluginEnabled _ msgParams pluginDesc config =
412
413
pluginResolverResponsible (msgParams ^. L. data_) pluginDesc
413
414
&& pluginEnabledConfig plcCodeActionsOn (configForPlugin config pluginDesc)
@@ -447,6 +448,7 @@ instance PluginMethod Request Method_TextDocumentCodeLens where
447
448
uri = msgParams ^. L. textDocument . L. uri
448
449
449
450
instance PluginMethod Request Method_CodeLensResolve where
451
+ -- See Note [Resolve in PluginHandlers]
450
452
pluginEnabled _ msgParams pluginDesc config =
451
453
pluginResolverResponsible (msgParams ^. L. data_) pluginDesc
452
454
&& pluginEnabledConfig plcCodeActionsOn (configForPlugin config pluginDesc)
@@ -469,6 +471,7 @@ instance PluginMethod Request Method_TextDocumentDocumentSymbol where
469
471
uri = msgParams ^. L. textDocument . L. uri
470
472
471
473
instance PluginMethod Request Method_CompletionItemResolve where
474
+ -- See Note [Resolve in PluginHandlers]
472
475
pluginEnabled _ msgParams pluginDesc config = pluginResolverResponsible (msgParams ^. L. data_) pluginDesc
473
476
&& pluginEnabledConfig plcCompletionOn (configForPlugin config pluginDesc)
474
477
@@ -551,7 +554,8 @@ instance PluginRequestMethod Method_TextDocumentCodeAction where
551
554
| otherwise = False
552
555
553
556
instance PluginRequestMethod Method_CodeActionResolve where
554
- -- Resolve methods should only have one response
557
+ -- A resolve request should only have one response.
558
+ -- See Note [Resolve in PluginHandlers].
555
559
combineResponses _ _ _ _ (x :| _) = x
556
560
557
561
instance PluginRequestMethod Method_TextDocumentDefinition where
@@ -572,7 +576,8 @@ instance PluginRequestMethod Method_WorkspaceSymbol where
572
576
instance PluginRequestMethod Method_TextDocumentCodeLens where
573
577
574
578
instance PluginRequestMethod Method_CodeLensResolve where
575
- -- A resolve request should only ever get one response
579
+ -- A resolve request should only ever get one response.
580
+ -- See note Note [Resolve in PluginHandlers]
576
581
combineResponses _ _ _ _ (x :| _) = x
577
582
578
583
instance PluginRequestMethod Method_TextDocumentRename where
@@ -616,7 +621,8 @@ instance PluginRequestMethod Method_TextDocumentDocumentSymbol where
616
621
in [si] <> children'
617
622
618
623
instance PluginRequestMethod Method_CompletionItemResolve where
619
- -- resolve methods should only have one response
624
+ -- A resolve request should only have one response.
625
+ -- See Note [Resolve in PluginHandlers]
620
626
combineResponses _ _ _ _ (x :| _) = x
621
627
622
628
instance PluginRequestMethod Method_TextDocumentCompletion where
@@ -774,7 +780,8 @@ type PluginMethodHandler a m = a -> PluginId -> MessageParams m -> LspM Config (
774
780
775
781
type PluginNotificationMethodHandler a m = a -> VFS -> PluginId -> MessageParams m -> LspM Config ()
776
782
777
- -- | Make a handler for plugins
783
+ -- | Make a handler for plugins. For how resolve works with this see
784
+ -- Note [Resolve in PluginHandlers]
778
785
mkPluginHandler
779
786
:: forall ideState m . PluginRequestMethod m
780
787
=> SClientMethod m
@@ -896,7 +903,7 @@ type ResolveFunction ideState a (m :: Method ClientToServer Request) =
896
903
-> LspM Config (Either ResponseError (MessageResult m ))
897
904
898
905
-- | Make a handler for resolve methods. In here we take your provided ResolveFunction
899
- -- and turn it into a PluginHandlers
906
+ -- and turn it into a PluginHandlers. See Note [Resolve in PluginHandlers]
900
907
mkResolveHandler
901
908
:: forall ideState a m . (FromJSON a , PluginRequestMethod m , L. HasData_ (MessageParams m ) (Maybe Value ))
902
909
=> SClientMethod m
@@ -1084,8 +1091,39 @@ getProcessID = fromIntegral <$> P.getProcessID
1084
1091
installSigUsr1Handler h = void $ installHandler sigUSR1 (Catch h) Nothing
1085
1092
#endif
1086
1093
1094
+ -- | Determine whether this request should be routed to the plugin. Fails closed
1095
+ -- if we can't determine which plugin it should be routed to.
1087
1096
pluginResolverResponsible :: Maybe Value -> PluginDescriptor c -> Bool
1088
1097
pluginResolverResponsible (Just (fromJSON -> (Success (PluginResolveData o _ _)))) pluginDesc =
1089
1098
pluginId pluginDesc == o
1090
1099
-- We want to fail closed
1091
1100
pluginResolverResponsible _ _ = False
1101
+
1102
+ {- Note [Resolve in PluginHandlers]
1103
+ Resolve methods have a few guarantees that need to be made by HLS,
1104
+ specifically they need to only be called once, as neither their errors nor
1105
+ their responses can be easily combined. Whereas commands, which similarly have
1106
+ the same requirements have their own codepaths for execution, for resolve
1107
+ methods we are relying on the standard PluginHandlers codepath.
1108
+ That isn't a problem, but it does mean we need to do some things extra for
1109
+ these methods.
1110
+ - First of all, whenever a handler that can be resolved sets the data_ field
1111
+ in their response, we need to intercept it, and wrap it in a data type
1112
+ PluginResolveData that allows us to route the future resolve request to the
1113
+ specific plugin which is responsible for it. (We also throw in the URI for
1114
+ convenience, because everyone needs that). We do that in mkPluginHandler.
1115
+ - When we get any resolve requests we check their data field for our
1116
+ PluginResolveData that will allow us to route the request to the right
1117
+ plugin. If we can't find out which plugin to route the request to, then we
1118
+ just don't route it at all. This is done in pluginEnabled, and
1119
+ pluginResolverResponsible.
1120
+ - Finally we have mkResolveHandler, which takes the resolve request and
1121
+ unwraps the plugins data from our PluginResolveData, parses it and passes it
1122
+ it on to the registered handler.
1123
+ It should be noted that there are some restrictions with this approach: First,
1124
+ if a plugin does not set the data_ field, than the request will not be able
1125
+ to be resolved. This is because we only wrap data_ fields that have been set
1126
+ with our PluginResolvableData tag. Second, if a plugin were to register two
1127
+ resolve handlers for the same method, than our assumptions that we never have
1128
+ two responses break, and behavior is undefined.
1129
+ -}
0 commit comments