11{-# LANGUAGE CPP #-}
22{-# LANGUAGE OverloadedStrings #-}
3+ {-# LANGUAGE TypeFamilies #-}
34
45module Wingman.LanguageServer where
56
@@ -12,25 +13,30 @@ import Data.Coerce
1213import Data.Functor ((<&>) )
1314import Data.Generics.Aliases (mkQ )
1415import Data.Generics.Schemes (everything )
16+ import qualified Data.HashMap.Strict as Map
1517import Data.IORef (readIORef )
1618import qualified Data.Map as M
1719import Data.Maybe
1820import Data.Monoid
1921import qualified Data.Set as S
2022import qualified Data.Text as T
2123import Data.Traversable
24+ import Development.IDE (getFilesOfInterest , ShowDiagnostic (ShowDiag ), srcSpanToRange )
2225import Development.IDE (hscEnv )
26+ import Development.IDE.Core.PositionMapping
2327import Development.IDE.Core.RuleTypes
28+ import Development.IDE.Core.Rules (usePropertyAction )
2429import Development.IDE.Core.Service (runAction )
25- import Development.IDE.Core.Shake (IdeState (.. ), use )
30+ import Development.IDE.Core.Shake (IdeState (.. ), uses , define , use )
2631import qualified Development.IDE.Core.Shake as IDE
2732import Development.IDE.Core.UseStale
2833import Development.IDE.GHC.Compat
2934import Development.IDE.GHC.Error (realSrcSpanToRange )
3035import Development.IDE.Spans.LocalBindings (Bindings , getDefiningBindings )
31- import Development.Shake (Action , RuleResult )
36+ import Development.Shake (Action , RuleResult , Rules , action )
3237import Development.Shake.Classes (Typeable , Binary , Hashable , NFData )
3338import qualified FastString
39+ import GHC.Generics (Generic )
3440import GhcPlugins (tupleDataCon , consDataCon , substTyAddInScope , ExternalPackageState , HscEnv (hsc_EPS ), liftIO )
3541import qualified Ide.Plugin.Config as Plugin
3642import Ide.Plugin.Properties
@@ -109,7 +115,8 @@ unsafeRunStaleIde state nfp a = do
109115------------------------------------------------------------------------------
110116
111117properties :: Properties
112- '[ 'PropertyKey " max_use_ctor_actions" 'TInteger
118+ '[ 'PropertyKey " hole_severity" ('TEnum (Maybe DiagnosticSeverity ))
119+ , 'PropertyKey " max_use_ctor_actions" 'TInteger
113120 , 'PropertyKey " features" 'TString
114121 , 'PropertyKey " timeout_duration" 'TInteger
115122 ]
@@ -120,6 +127,15 @@ properties = emptyProperties
120127 " Feature set used by Wingman" " "
121128 & defineIntegerProperty # max_use_ctor_actions
122129 " Maximum number of `Use constructor <x>` code actions that can appear" 5
130+ & defineEnumProperty # hole_severity
131+ " The severity to use when showing hole diagnostics. These are noisy, but some editors don't allow jumping to all severities."
132+ [ (Just DsError , " error" )
133+ , (Just DsWarning , " warning" )
134+ , (Just DsInfo , " info" )
135+ , (Just DsHint , " hint" )
136+ , (Nothing , " none" )
137+ ]
138+ Nothing
123139
124140
125141-- | Get the the plugin config
@@ -421,3 +437,61 @@ mkShowMessageParams ufm = ShowMessageParams (ufmSeverity ufm) $ T.pack $ show uf
421437showLspMessage :: MonadLsp cfg m => ShowMessageParams -> m ()
422438showLspMessage = sendNotification SWindowShowMessage
423439
440+
441+ -- This rule only exists for generating file diagnostics
442+ -- so the RuleResult is empty
443+ data WriteDiagnostics = WriteDiagnostics
444+ deriving (Eq , Show , Typeable , Generic )
445+
446+ instance Hashable WriteDiagnostics
447+ instance NFData WriteDiagnostics
448+ instance Binary WriteDiagnostics
449+
450+ type instance RuleResult WriteDiagnostics = ()
451+
452+ wingmanRules :: PluginId -> Rules ()
453+ wingmanRules plId = do
454+ define $ \ WriteDiagnostics nfp ->
455+ usePropertyAction # hole_severity plId properties >>= \ case
456+ Nothing -> pure (mempty , Just () )
457+ Just severity ->
458+ use GetParsedModule nfp >>= \ case
459+ Nothing ->
460+ pure ([] , Nothing )
461+ Just pm -> do
462+ let holes :: [Range ]
463+ holes =
464+ everything (<>)
465+ (mkQ mempty $ \ case
466+ L span (HsVar _ (L _ name))
467+ | isHole (occName name) ->
468+ maybeToList $ srcSpanToRange span
469+ L span (HsUnboundVar _ (TrueExprHole occ))
470+ | isHole occ ->
471+ maybeToList $ srcSpanToRange span
472+ #if __GLASGOW_HASKELL__ <= 808
473+ L span (EWildPat _) ->
474+ maybeToList $ srcSpanToRange span
475+ #endif
476+ (_ :: LHsExpr GhcPs ) -> mempty
477+ ) $ pm_parsed_source pm
478+ pure
479+ ( fmap (\ r -> (nfp, ShowDiag , mkDiagnostic severity r)) holes
480+ , Just ()
481+ )
482+
483+ action $ do
484+ files <- getFilesOfInterest
485+ void $ uses WriteDiagnostics $ Map. keys files
486+
487+
488+ mkDiagnostic :: DiagnosticSeverity -> Range -> Diagnostic
489+ mkDiagnostic severity r =
490+ Diagnostic r
491+ (Just severity)
492+ (Just $ InR " hole" )
493+ (Just " wingman" )
494+ " Hole"
495+ (Just $ List [DtUnnecessary ])
496+ Nothing
497+
0 commit comments