Skip to content

Commit d8b3753

Browse files
committed
Pull out tactic providers
1 parent cffba27 commit d8b3753

File tree

3 files changed

+190
-152
lines changed

3 files changed

+190
-152
lines changed

plugins/hls-tactics-plugin/hls-tactics-plugin.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ library
3333
Ide.Plugin.Tactic.Judgements
3434
Ide.Plugin.Tactic.KnownStrategies
3535
Ide.Plugin.Tactic.KnownStrategies.QuickCheck
36+
Ide.Plugin.Tactic.LanguageServer
37+
Ide.Plugin.Tactic.LanguageServer.TacticProviders
3638
Ide.Plugin.Tactic.Machinery
3739
Ide.Plugin.Tactic.Naming
3840
Ide.Plugin.Tactic.Range

plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic.hs

Lines changed: 7 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
1-
{-# LANGUAGE DeriveAnyClass #-}
2-
{-# LANGUAGE DeriveGeneric #-}
3-
{-# LANGUAGE GADTs #-}
4-
{-# LANGUAGE LambdaCase #-}
5-
{-# LANGUAGE NumDecimals #-}
6-
{-# LANGUAGE OverloadedStrings #-}
7-
{-# LANGUAGE ScopedTypeVariables #-}
8-
{-# LANGUAGE TupleSections #-}
9-
{-# LANGUAGE TypeApplications #-}
10-
{-# LANGUAGE ViewPatterns #-}
1+
{-# LANGUAGE GADTs #-}
2+
{-# LANGUAGE LambdaCase #-}
3+
{-# LANGUAGE NumDecimals #-}
4+
{-# LANGUAGE OverloadedStrings #-}
5+
{-# LANGUAGE TypeApplications #-}
116

127
-- | A plugin that uses tactics to synthesize code
138
module Ide.Plugin.Tactic
@@ -19,7 +14,6 @@ module Ide.Plugin.Tactic
1914
import Bag (listToBag, bagToList)
2015
import Control.Arrow
2116
import Control.Monad
22-
import Control.Monad.Error.Class (MonadError(throwError))
2317
import Control.Monad.Trans
2418
import Control.Monad.Trans.Maybe
2519
import Data.Aeson
@@ -46,9 +40,6 @@ import Development.IDE.GHC.ExactPrint
4640
import Development.IDE.Spans.LocalBindings (getDefiningBindings)
4741
import Development.Shake (Action)
4842
import qualified FastString
49-
import GHC.Generics (Generic)
50-
import GHC.LanguageExtensions.Type (Extension (LambdaCase))
51-
import Ide.Plugin.Tactic.Auto
5243
import Ide.Plugin.Tactic.CaseSplit
5344
import Ide.Plugin.Tactic.Context
5445
import Ide.Plugin.Tactic.GHC
@@ -57,16 +48,15 @@ import Ide.Plugin.Tactic.Range
5748
import Ide.Plugin.Tactic.Tactics
5849
import Ide.Plugin.Tactic.TestTypes
5950
import Ide.Plugin.Tactic.Types
60-
import Ide.PluginUtils
6151
import Ide.Types
6252
import Language.LSP.Server
6353
import Language.LSP.Types
6454
import OccName
6555
import Prelude hiding (span)
66-
import Refinery.Tactic (goal)
6756
import SrcLoc (containsSpan)
6857
import System.Timeout
6958
import TcRnTypes (tcg_binds)
59+
import Ide.Plugin.Tactic.LanguageServer.TacticProviders
7060

7161

7262
descriptor :: PluginId -> PluginDescriptor IdeState
@@ -84,85 +74,13 @@ descriptor plId = (defaultPluginDescriptor plId)
8474
tacticDesc :: T.Text -> T.Text
8575
tacticDesc name = "fill the hole using the " <> name <> " tactic"
8676

87-
------------------------------------------------------------------------------
88-
-- | A 'TacticProvider' is a way of giving context-sensitive actions to the LS
89-
-- UI.
90-
type TacticProvider = DynFlags -> PluginId -> Uri -> Range -> Judgement -> IO [Command |? CodeAction]
91-
92-
93-
------------------------------------------------------------------------------
94-
-- | Construct a 'CommandId'
95-
tcCommandId :: TacticCommand -> CommandId
96-
tcCommandId c = coerce $ T.pack $ "tactics" <> show c <> "Command"
9777

9878

9979
------------------------------------------------------------------------------
10080
-- | The name of the command for the LS.
10181
tcCommandName :: TacticCommand -> T.Text
10282
tcCommandName = T.pack . show
10383

104-
------------------------------------------------------------------------------
105-
-- | Mapping from tactic commands to their contextual providers. See 'provide',
106-
-- 'filterGoalType' and 'filterBindingType' for the nitty gritty.
107-
commandProvider :: TacticCommand -> TacticProvider
108-
commandProvider Auto = provide Auto ""
109-
commandProvider Intros =
110-
filterGoalType isFunction $
111-
provide Intros ""
112-
commandProvider Destruct =
113-
filterBindingType destructFilter $ \occ _ ->
114-
provide Destruct $ T.pack $ occNameString occ
115-
commandProvider Homomorphism =
116-
filterBindingType homoFilter $ \occ _ ->
117-
provide Homomorphism $ T.pack $ occNameString occ
118-
commandProvider DestructLambdaCase =
119-
requireExtension LambdaCase $
120-
filterGoalType (isJust . lambdaCaseable) $
121-
provide DestructLambdaCase ""
122-
commandProvider HomomorphismLambdaCase =
123-
requireExtension LambdaCase $
124-
filterGoalType ((== Just True) . lambdaCaseable) $
125-
provide HomomorphismLambdaCase ""
126-
127-
128-
------------------------------------------------------------------------------
129-
-- | A mapping from tactic commands to actual tactics for refinery.
130-
commandTactic :: TacticCommand -> OccName -> TacticsM ()
131-
commandTactic Auto = const auto
132-
commandTactic Intros = const intros
133-
commandTactic Destruct = useNameFromHypothesis destruct
134-
commandTactic Homomorphism = useNameFromHypothesis homo
135-
commandTactic DestructLambdaCase = const destructLambdaCase
136-
commandTactic HomomorphismLambdaCase = const homoLambdaCase
137-
138-
139-
------------------------------------------------------------------------------
140-
-- | Lift a function over 'HyInfo's to one that takes an 'OccName' and tries to
141-
-- look it up in the hypothesis.
142-
useNameFromHypothesis :: (HyInfo CType -> TacticsM a) -> OccName -> TacticsM a
143-
useNameFromHypothesis f name = do
144-
hy <- jHypothesis <$> goal
145-
case M.lookup name $ hyByName hy of
146-
Just hi -> f hi
147-
Nothing -> throwError $ NotInScope name
148-
149-
150-
151-
------------------------------------------------------------------------------
152-
-- | We should show homos only when the goal type is the same as the binding
153-
-- type, and that both are usual algebraic types.
154-
homoFilter :: Type -> Type -> Bool
155-
homoFilter (algebraicTyCon -> Just t1) (algebraicTyCon -> Just t2) = t1 == t2
156-
homoFilter _ _ = False
157-
158-
159-
------------------------------------------------------------------------------
160-
-- | We should show destruct for bindings only when those bindings have usual
161-
-- algebraic types.
162-
destructFilter :: Type -> Type -> Bool
163-
destructFilter _ (algebraicTyCon -> Just _) = True
164-
destructFilter _ _ = False
165-
16684

16785
runIde :: IdeState -> Action a -> IO a
16886
runIde state = runAction "tactic" state
@@ -182,71 +100,8 @@ codeActionProvider state plId (CodeActionParams _ _ (TextDocumentIdentifier uri)
182100
range
183101
jdg
184102
pure $ Right $ List actions
185-
codeActionProvider _ _ _ = pure $ Right $ codeActions []
186-
187-
188-
codeActions :: [CodeAction] -> List (Command |? CodeAction)
189-
codeActions = List . fmap InR
190-
191-
192-
------------------------------------------------------------------------------
193-
-- | Terminal constructor for providing context-sensitive tactics. Tactics
194-
-- given by 'provide' are always available.
195-
provide :: TacticCommand -> T.Text -> TacticProvider
196-
provide tc name _ plId uri range _ = do
197-
let title = tacticTitle tc name
198-
params = TacticParams { tp_file = uri , tp_range = range , tp_var_name = name }
199-
cmd = mkLspCommand plId (tcCommandId tc) title (Just [toJSON params])
200-
pure
201-
$ pure
202-
$ InR
203-
$ CodeAction title (Just CodeActionQuickFix) Nothing Nothing Nothing Nothing
204-
$ Just cmd
205-
103+
codeActionProvider _ _ _ = pure $ Right $ List []
206104

207-
------------------------------------------------------------------------------
208-
-- | Restrict a 'TacticProvider', making sure it appears only when the given
209-
-- predicate holds for the goal.
210-
requireExtension :: Extension -> TacticProvider -> TacticProvider
211-
requireExtension ext tp dflags plId uri range jdg =
212-
case xopt ext dflags of
213-
True -> tp dflags plId uri range jdg
214-
False -> pure []
215-
216-
217-
------------------------------------------------------------------------------
218-
-- | Restrict a 'TacticProvider', making sure it appears only when the given
219-
-- predicate holds for the goal.
220-
filterGoalType :: (Type -> Bool) -> TacticProvider -> TacticProvider
221-
filterGoalType p tp dflags plId uri range jdg =
222-
case p $ unCType $ jGoal jdg of
223-
True -> tp dflags plId uri range jdg
224-
False -> pure []
225-
226-
227-
------------------------------------------------------------------------------
228-
-- | Multiply a 'TacticProvider' for each binding, making sure it appears only
229-
-- when the given predicate holds over the goal and binding types.
230-
filterBindingType
231-
:: (Type -> Type -> Bool) -- ^ Goal and then binding types.
232-
-> (OccName -> Type -> TacticProvider)
233-
-> TacticProvider
234-
filterBindingType p tp dflags plId uri range jdg =
235-
let hy = jHypothesis jdg
236-
g = jGoal jdg
237-
in fmap join $ for (unHypothesis hy) $ \hi ->
238-
let ty = unCType $ hi_type hi
239-
in case p (unCType g) ty of
240-
True -> tp (hi_name hi) ty dflags plId uri range jdg
241-
False -> pure []
242-
243-
244-
data TacticParams = TacticParams
245-
{ tp_file :: Uri -- ^ Uri of the file to fill the hole in
246-
, tp_range :: Range -- ^ The range of the hole
247-
, tp_var_name :: T.Text
248-
}
249-
deriving (Show, Eq, Generic, ToJSON, FromJSON)
250105

251106

252107
------------------------------------------------------------------------------

0 commit comments

Comments
 (0)