{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ExplicitNamespaces #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Ide.Plugin.Cabal.FieldSuggest ( fieldErrorName, fieldErrorAction, -- * Re-exports T.Text, Diagnostic (..), ) where import qualified Data.Map.Strict as Map import qualified Data.Text as T import Language.LSP.Protocol.Types (CodeAction (..), CodeActionKind (..), Diagnostic (..), Position (..), Range (..), TextEdit (..), Uri, WorkspaceEdit (..)) import Text.Regex.TDFA -- | Generate all code actions for given file, erroneous/unknown field and suggestions fieldErrorAction :: Uri -- ^ File for which the diagnostic was generated -> T.Text -- ^ Original (unknown) field -> [T.Text] -- ^ Suggestions for the given file -> Range -- ^ Location of diagnostic -> [CodeAction] fieldErrorAction uri original suggestions range = fmap mkCodeAction suggestions where mkCodeAction suggestion = let -- Range returned by cabal here represents fragment from start of offending identifier -- to end of line, we modify this range to be to the end of the identifier adjustRange (Range rangeFrom@(Position lineNr col) _) = Range rangeFrom (Position lineNr (col + fromIntegral (T.length original))) title = "Replace with " <> suggestion' tedit = [TextEdit (adjustRange range ) suggestion'] edit = WorkspaceEdit (Just $ Map.singleton uri tedit) Nothing Nothing in CodeAction title (Just CodeActionKind_QuickFix) (Just []) Nothing Nothing (Just edit) Nothing Nothing where -- dropping colon from the end of suggestion suggestion' = T.dropEnd 1 suggestion -- | Given a diagnostic returned by 'Ide.Plugin.Cabal.Diag.errorDiagnostic', -- if it represents an "Unknown field"-error with incorrect identifier -- then return the incorrect identifier together with original diagnostics. fieldErrorName :: Diagnostic -> -- ^ Output of 'Ide.Plugin.Cabal.Diag.errorDiagnostic' Maybe (T.Text, Diagnostic) -- ^ Original (incorrect) field name with the suggested replacement fieldErrorName diag = mSuggestion (_message diag) >>= \case [original] -> Just (original, diag) _ -> Nothing where regex :: T.Text regex = "Unknown field: \"(.*)\"" mSuggestion msg = getMatch <$> (msg :: T.Text) =~~ regex getMatch :: (T.Text, T.Text, T.Text, [T.Text]) -> [T.Text] getMatch (_, _, _, results) = results