hls-alternate-number-format-plugin 1.2.0.0 → 1.3.0.0
raw patch · 5 files changed
+56/−86 lines, 5 filesdep +extradep ~ghcidedep ~hls-plugin-apidep ~hls-test-utilsPVP ok
version bump matches the API change (PVP)
Dependencies added: extra
Dependency ranges changed: ghcide, hls-plugin-api, hls-test-utils
API changes (from Hackage documentation)
- Ide.Plugin.AlternateNumberFormat: descriptor :: Recorder (WithPriority Log) -> PluginDescriptor IdeState
+ Ide.Plugin.AlternateNumberFormat: descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState
Files
- hls-alternate-number-format-plugin.cabal +9/−4
- src/Ide/Plugin/AlternateNumberFormat.hs +38/−65
- src/Ide/Plugin/Conversion.hs +5/−4
- src/Ide/Plugin/Literals.hs +1/−10
- test/Main.hs +3/−3
hls-alternate-number-format-plugin.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: hls-alternate-number-format-plugin-version: 1.2.0.0+version: 1.3.0.0 synopsis: Provide Alternate Number Formats plugin for Haskell Language Server description: Please see the README on GitHub at <https://github.com/haskell/haskell-language-server#readme>@@ -17,6 +17,10 @@ test/testdata/*.hs test/testdata/*.yaml +source-repository head+ type: git+ location: https://github.com/haskell/haskell-language-server.git+ library buildable: True exposed-modules: Ide.Plugin.AlternateNumberFormat, Ide.Plugin.Conversion@@ -27,10 +31,11 @@ aeson , base >=4.12 && < 5 , containers- , ghcide ^>= 1.8+ , extra+ , ghcide ^>= 1.9 , ghc-boot-th , hls-graph- , hls-plugin-api ^>= 1.5+ , hls-plugin-api ^>= 1.6 , hie-compat , lens , lsp ^>=1.6@@ -59,7 +64,7 @@ , base >=4.12 && < 5 , filepath , hls-alternate-number-format-plugin- , hls-test-utils ^>=1.3 || ^>= 1.4+ , hls-test-utils ^>=1.5 , lsp , QuickCheck , regex-tdfa
src/Ide/Plugin/AlternateNumberFormat.hs view
@@ -2,40 +2,36 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ViewPatterns #-} module Ide.Plugin.AlternateNumberFormat (descriptor, Log(..)) where -import Control.Lens ((^.))-import Control.Monad.Except (ExceptT, MonadIO, liftIO)-import qualified Data.HashMap.Strict as HashMap-import Data.String (IsString)-import Data.Text (Text)-import qualified Data.Text as T-import Development.IDE (GetParsedModule (GetParsedModule),- GhcSession (GhcSession),- IdeState, RuleResult, Rules,- define, getFileContents,- hscEnv, realSrcSpanToRange,- runAction, use, useWithStale)-import qualified Development.IDE.Core.Shake as Shake-import Development.IDE.GHC.Compat hiding (getSrcSpan)-import Development.IDE.GHC.Compat.Util (toList)-import Development.IDE.Graph.Classes (Hashable, NFData, rnf)-import Development.IDE.Spans.Pragmas (NextPragmaInfo,- getNextPragmaInfo,- insertNewPragma)-import Development.IDE.Types.Logger as Logger-import GHC.Generics (Generic)-import GHC.LanguageExtensions.Type (Extension)-import Ide.Plugin.Conversion (AlternateFormat,- ExtensionNeeded (NeedsExtension, NoExtension),- alternateFormat)+import Control.Lens ((^.))+import Control.Monad.Except (ExceptT, MonadIO, liftIO)+import qualified Data.HashMap.Strict as HashMap+import Data.Text (Text, unpack)+import qualified Data.Text as T+import Development.IDE (GetParsedModule (GetParsedModule),+ IdeState, RuleResult, Rules,+ define, realSrcSpanToRange,+ runAction, use)+import qualified Development.IDE.Core.Shake as Shake+import Development.IDE.GHC.Compat hiding (getSrcSpan)+import Development.IDE.GHC.Util (getExtensions)+import Development.IDE.Graph.Classes (Hashable, NFData, rnf)+import Development.IDE.Spans.Pragmas (NextPragmaInfo, getFirstPragma,+ insertNewPragma)+import Development.IDE.Types.Logger as Logger+import GHC.Generics (Generic)+import Ide.Plugin.Conversion (AlternateFormat,+ ExtensionNeeded (NeedsExtension, NoExtension),+ alternateFormat) import Ide.Plugin.Literals-import Ide.PluginUtils (getNormalizedFilePath,- handleMaybeM, pluginResponse)+import Ide.Plugin.RangeMap (RangeMap)+import qualified Ide.Plugin.RangeMap as RangeMap+import Ide.PluginUtils (getNormalizedFilePath,+ handleMaybeM, pluginResponse) import Ide.Types import Language.LSP.Types-import qualified Language.LSP.Types.Lens as L+import qualified Language.LSP.Types.Lens as L newtype Log = LogShake Shake.Log deriving Show @@ -43,11 +39,8 @@ pretty = \case LogShake log -> pretty log -alternateNumberFormatId :: IsString a => a-alternateNumberFormatId = "alternateNumberFormat"--descriptor :: Recorder (WithPriority Log) -> PluginDescriptor IdeState-descriptor recorder = (defaultPluginDescriptor alternateNumberFormatId)+descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState+descriptor recorder pId = (defaultPluginDescriptor pId) { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionHandler , pluginRules = collectLiteralsRule recorder }@@ -61,7 +54,7 @@ type instance RuleResult CollectLiterals = CollectLiteralsResult data CollectLiteralsResult = CLR- { literals :: [Literal]+ { literals :: RangeMap Literal , enabledExtensions :: [GhcExtension] } deriving (Generic) @@ -79,30 +72,25 @@ collectLiteralsRule recorder = define (cmapWithPrio LogShake recorder) $ \CollectLiterals nfp -> do pm <- use GetParsedModule nfp -- get the current extensions active and transform them into FormatTypes- let exts = getExtensions <$> pm+ let exts = map GhcExtension . getExtensions <$> pm -- collect all the literals for a file lits = collectLiterals . pm_parsed_source <$> pm- pure ([], CLR <$> lits <*> exts)- where- getExtensions = map GhcExtension . toList . extensionFlags . ms_hspp_opts . pm_mod_summary+ litMap = RangeMap.fromList (realSrcSpanToRange . getSrcSpan) <$> lits+ pure ([], CLR <$> litMap <*> exts) codeActionHandler :: PluginMethodHandler IdeState 'TextDocumentCodeAction-codeActionHandler state _ (CodeActionParams _ _ docId currRange _) = pluginResponse $ do+codeActionHandler state pId (CodeActionParams _ _ docId currRange _) = pluginResponse $ do nfp <- getNormalizedFilePath (docId ^. L.uri)- CLR{..} <- requestLiterals state nfp- pragma <- getFirstPragma state nfp+ CLR{..} <- requestLiterals pId state nfp+ pragma <- getFirstPragma pId state nfp -- remove any invalid literals (see validTarget comment)- let litsInRange = filter inCurrentRange literals+ let litsInRange = RangeMap.filterByRange currRange literals -- generate alternateFormats and zip with the literal that generated the alternates literalPairs = map (\lit -> (lit, alternateFormat lit)) litsInRange -- make a code action for every literal and its' alternates (then flatten the result) actions = concatMap (\(lit, alts) -> map (mkCodeAction nfp lit enabledExtensions pragma) alts) literalPairs pure $ List actions where- inCurrentRange :: Literal -> Bool- inCurrentRange lit = let srcSpan = getSrcSpan lit- in currRange `contains` srcSpan- mkCodeAction :: NormalizedFilePath -> Literal -> [GhcExtension] -> NextPragmaInfo -> AlternateFormat -> Command |? CodeAction mkCodeAction nfp lit enabled npi af@(alt, ext) = InR CodeAction { _title = mkCodeActionTitle lit af enabled@@ -138,23 +126,8 @@ needsExtension :: Extension -> [GhcExtension] -> Bool needsExtension ext ghcExts = ext `notElem` map unExt ghcExts --- from HaddockComments.hs-contains :: Range -> RealSrcSpan -> Bool-contains Range {_start, _end} x = isInsideRealSrcSpan _start x || isInsideRealSrcSpan _end x--isInsideRealSrcSpan :: Position -> RealSrcSpan -> Bool-p `isInsideRealSrcSpan` r = let (Range sp ep) = realSrcSpanToRange r in sp <= p && p <= ep--getFirstPragma :: MonadIO m => IdeState -> NormalizedFilePath -> ExceptT String m NextPragmaInfo-getFirstPragma state nfp = handleMaybeM "Error: Could not get NextPragmaInfo" $ do- ghcSession <- liftIO $ runAction (alternateNumberFormatId <> ".GhcSession") state $ useWithStale GhcSession nfp- (_, fileContents) <- liftIO $ runAction (alternateNumberFormatId <> ".GetFileContents") state $ getFileContents nfp- case ghcSession of- Just (hscEnv -> hsc_dflags -> sessionDynFlags, _) -> pure $ Just $ getNextPragmaInfo sessionDynFlags fileContents- Nothing -> pure Nothing--requestLiterals :: MonadIO m => IdeState -> NormalizedFilePath -> ExceptT String m CollectLiteralsResult-requestLiterals state = handleMaybeM "Error: Could not Collect Literals"+requestLiterals :: MonadIO m => PluginId -> IdeState -> NormalizedFilePath -> ExceptT String m CollectLiteralsResult+requestLiterals (PluginId pId) state = handleMaybeM "Could not Collect Literals" . liftIO- . runAction (alternateNumberFormatId <> ".CollectLiterals") state+ . runAction (unpack pId <> ".CollectLiterals") state . use CollectLiterals
src/Ide/Plugin/Conversion.hs view
@@ -23,6 +23,7 @@ import Data.Char (toUpper) import Data.List (delete)+import Data.List.Extra (enumerate, upper) import Data.Maybe (mapMaybe) import Data.Ratio (denominator, numerator) import Data.Text (Text)@@ -108,10 +109,10 @@ getFracFormat _ = Nothing intFormats :: [IntFormatType]-intFormats = [minBound .. maxBound]+intFormats = enumerate fracFormats :: [FracFormatType]-fracFormats = [minBound .. maxBound]+fracFormats = enumerate -- | Regex to match a Haskell Hex Literal hexRegex :: Text@@ -157,8 +158,8 @@ toBase :: (Num a, Ord a) => (a -> ShowS) -> String -> a -> String toBase conv header n- | n < 0 = '-' : header <> map toUpper (conv (abs n) "")- | otherwise = header <> map toUpper (conv n "")+ | n < 0 = '-' : header <> upper (conv (abs n) "")+ | otherwise = header <> upper (conv n "") toOctal :: (Integral a, Show a) => a -> String toOctal = toBase showOct "0o"
src/Ide/Plugin/Literals.hs view
@@ -62,17 +62,8 @@ _ -> Nothing getLiteral _ = Nothing ----- GHC 8.8 typedefs LPat = Pat-#if __GLASGOW_HASKELL__ == 808-type LocPat a = GenLocated SrcSpan (Pat a)-#else-type LocPat a = LPat a-#endif- -- | Destructure Patterns to unwrap any Literals-getPattern :: LocPat GhcPs -> Maybe Literal+getPattern :: LPat GhcPs -> Maybe Literal getPattern (L (locA -> (RealSrcSpan patSpan _)) pat) = case pat of LitPat _ lit -> case lit of HsInt _ val -> fromIntegralLit patSpan val
test/Main.hs view
@@ -19,8 +19,8 @@ main :: IO () main = defaultTestRunner test -alternateNumberFormatPlugin :: PluginDescriptor IdeState-alternateNumberFormatPlugin = AlternateNumberFormat.descriptor mempty+alternateNumberFormatPlugin :: PluginTestDescriptor AlternateNumberFormat.Log+alternateNumberFormatPlugin = mkPluginTestDescriptor AlternateNumberFormat.descriptor "alternateNumberFormat" -- NOTE: For whatever reason, this plugin does not play nice with creating Code Actions on time. -- As a result tests will mostly pass if `import Prelude` is added at the top. We (mostly fendor) surmise this has something@@ -29,7 +29,7 @@ test = testGroup "alternateNumberFormat" [ codeActionHex "TIntDtoH" 3 13 , codeActionOctal "TIntDtoO" 3 13- , codeActionBinary "TIntDtoB" 4 12+ , codeActionBinary "TIntDtoB" 4 13 , codeActionNumDecimal "TIntDtoND" 5 13 , codeActionFracExp "TFracDtoE" 3 13 , codeActionFloatHex "TFracDtoHF" 4 13