hls-rename-plugin 2.0.0.1 → 2.1.0.0
raw patch · 2 files changed
+46/−47 lines, 2 filesdep +lensdep +mtldep ~ghcidedep ~hls-plugin-apidep ~hls-test-utilsPVP ok
version bump matches the API change (PVP)
Dependencies added: lens, mtl
Dependency ranges changed: ghcide, hls-plugin-api, hls-test-utils
API changes (from Hackage documentation)
Files
- hls-rename-plugin.cabal +6/−4
- src/Ide/Plugin/Rename.hs +40/−43
hls-rename-plugin.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: hls-rename-plugin-version: 2.0.0.1+version: 2.1.0.0 synopsis: Rename plugin for Haskell Language Server description: Please see the README on GitHub at <https://github.com/haskell/haskell-language-server#readme>@@ -29,14 +29,16 @@ , extra , ghc , ghc-exactprint- , ghcide == 2.0.0.1+ , ghcide == 2.1.0.0 , hashable , hiedb , hie-compat- , hls-plugin-api == 2.0.0.1+ , hls-plugin-api == 2.1.0.0 , hls-refactor-plugin+ , lens , lsp , lsp-types+ , mtl , mod , syb , text@@ -58,4 +60,4 @@ , filepath , hls-plugin-api , hls-rename-plugin- , hls-test-utils == 2.0.0.1+ , hls-test-utils == 2.1.0.0
src/Ide/Plugin/Rename.hs view
@@ -6,9 +6,9 @@ {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-}-{-# LANGUAGE RecordWildCards #-} module Ide.Plugin.Rename (descriptor, E.Log) where @@ -17,23 +17,27 @@ AnnParen, AnnPragma) #endif +import Compat.HieTypes+import Control.Lens ((^.)) import Control.Monad+import Control.Monad.Except import Control.Monad.IO.Class import Control.Monad.Trans.Class import Control.Monad.Trans.Except-import Data.Generics import Data.Bifunctor (first)+import Data.Generics import Data.Hashable import Data.HashSet (HashSet) import qualified Data.HashSet as HS import Data.List.Extra hiding (length) import qualified Data.Map as M-import qualified Data.Set as S import Data.Maybe import Data.Mod.Word+import qualified Data.Set as S import qualified Data.Text as T import Development.IDE (Recorder, WithPriority, usePropertyAction)+import Development.IDE.Core.PluginUtils import Development.IDE.Core.PositionMapping import Development.IDE.Core.RuleTypes import Development.IDE.Core.Service@@ -49,26 +53,27 @@ import Development.IDE.Spans.AtPoint import Development.IDE.Types.Location import HieDb.Query+import Ide.Plugin.Error import Ide.Plugin.Properties import Ide.PluginUtils import Ide.Types+import qualified Language.LSP.Protocol.Lens as L+import Language.LSP.Protocol.Message+import Language.LSP.Protocol.Types import Language.LSP.Server-import Language.LSP.Types-import Compat.HieTypes instance Hashable (Mod a) where hash n = hash (unMod n) descriptor :: Recorder (WithPriority E.Log) -> PluginId -> PluginDescriptor IdeState descriptor recorder pluginId = mkExactprintPluginDescriptor recorder $ (defaultPluginDescriptor pluginId)- { pluginHandlers = mkPluginHandler STextDocumentRename renameProvider+ { pluginHandlers = mkPluginHandler SMethod_TextDocumentRename renameProvider , pluginConfigDescriptor = defaultConfigDescriptor { configCustomConfig = mkCustomConfig properties } } -renameProvider :: PluginMethodHandler IdeState TextDocumentRename-renameProvider state pluginId (RenameParams (TextDocumentIdentifier uri) pos _prog newNameText) =- pluginResponse $ do- nfp <- handleUriToNfp uri+renameProvider :: PluginMethodHandler IdeState Method_TextDocumentRename+renameProvider state pluginId (RenameParams _prog docId@(TextDocumentIdentifier uri) pos newNameText) = do+ nfp <- getNormalizedFilePathE uri directOldNames <- getNamesAtPos state nfp pos directRefs <- concat <$> mapM (refsAtName state nfp) directOldNames @@ -78,7 +83,7 @@ See the `IndirectPuns` test for an example. -} indirectOldNames <- concat . filter ((>1) . Prelude.length) <$> mapM (uncurry (getNamesAtPos state) . locToFilePos) directRefs- let oldNames = (filter matchesDirect indirectOldNames) ++ directOldNames+ let oldNames = filter matchesDirect indirectOldNames ++ directOldNames matchesDirect n = occNameFS (nameOccName n) `elem` directFS where directFS = map (occNameFS. nameOccName) directOldNames@@ -87,14 +92,16 @@ -- Validate rename crossModuleEnabled <- liftIO $ runAction "rename: config" state $ usePropertyAction #crossModule pluginId properties unless crossModuleEnabled $ failWhenImportOrExport state nfp refs oldNames- when (any isBuiltInSyntax oldNames) $ throwE "Invalid rename of built-in syntax"+ when (any isBuiltInSyntax oldNames) $ throwError $ PluginInternalError "Invalid rename of built-in syntax" -- Perform rename let newName = mkTcOcc $ T.unpack newNameText filesRefs = collectWith locToUri refs- getFileEdit = flip $ getSrcEdit state . replaceRefs newName- fileEdits <- mapM (uncurry getFileEdit) filesRefs- pure $ foldl' (<>) mempty fileEdits+ getFileEdit (uri, locations) = do+ verTxtDocId <- lift $ getVersionedTextDoc (TextDocumentIdentifier uri)+ getSrcEdit state verTxtDocId (replaceRefs newName locations)+ fileEdits <- mapM getFileEdit filesRefs+ pure $ InL $ foldl' (<>) mempty fileEdits -- | Limit renaming across modules. failWhenImportOrExport ::@@ -103,19 +110,17 @@ NormalizedFilePath -> HashSet Location -> [Name] ->- ExceptT String m ()+ ExceptT PluginError m () failWhenImportOrExport state nfp refLocs names = do- pm <- handleMaybeM ("No parsed module for: " ++ show nfp) $ liftIO $ runAction- "Rename.GetParsedModule"- state- (use GetParsedModule nfp)+ pm <- runActionE "Rename.GetParsedModule" state+ (useE GetParsedModule nfp) let hsMod = unLoc $ pm_parsed_source pm case (unLoc <$> hsmodName hsMod, hsmodExports hsMod) of (mbModName, _) | not $ any (\n -> nameIsLocalOrFrom (replaceModName n mbModName) n) names- -> throwE "Renaming of an imported name is unsupported"+ -> throwError $ PluginInternalError "Renaming of an imported name is unsupported" (_, Just (L _ exports)) | any ((`HS.member` refLocs) . unsafeSrcSpanToLoc . getLoc) exports- -> throwE "Renaming of an exported name is unsupported"- (Just _, Nothing) -> throwE "Explicit export list required for renaming"+ -> throwError $ PluginInternalError "Renaming of an exported name is unsupported"+ (Just _, Nothing) -> throwError $ PluginInternalError "Explicit export list required for renaming" _ -> pure () ---------------------------------------------------------------------------------------------------@@ -125,16 +130,14 @@ getSrcEdit :: (MonadLsp config m) => IdeState ->+ VersionedTextDocumentIdentifier -> (ParsedSource -> ParsedSource) ->- Uri ->- ExceptT String m WorkspaceEdit-getSrcEdit state updatePs uri = do+ ExceptT PluginError m WorkspaceEdit+getSrcEdit state verTxtDocId updatePs = do ccs <- lift getClientCapabilities- nfp <- handleUriToNfp uri- annAst <- handleMaybeM ("No parsed source for: " ++ show nfp) $ liftIO $ runAction- "Rename.GetAnnotatedParsedSource"- state- (use GetAnnotatedParsedSource nfp)+ nfp <- getNormalizedFilePathE (verTxtDocId ^. L.uri)+ annAst <- runActionE "Rename.GetAnnotatedParsedSource" state+ (useE GetAnnotatedParsedSource nfp) let (ps, anns) = (astA annAst, annsA annAst) #if !MIN_VERSION_ghc(9,2,1) let src = T.pack $ exactPrint ps anns@@ -143,7 +146,7 @@ let src = T.pack $ exactPrint ps res = T.pack $ exactPrint (updatePs ps) #endif- pure $ diffText ccs (uri, src) res IncludeDeletions+ pure $ diffText ccs (verTxtDocId, src) res IncludeDeletions -- | Replace names at every given `Location` (in a given `ParsedSource`) with a given new name. replaceRefs ::@@ -190,7 +193,7 @@ IdeState -> NormalizedFilePath -> Name ->- ExceptT String m [Location]+ ExceptT PluginError m [Location] refsAtName state nfp name = do ShakeExtras{withHieDb} <- liftIO $ runAction "Rename.HieDb" state getShakeExtras ast <- handleGetHieAst state nfp@@ -215,7 +218,7 @@ --------------------------------------------------------------------------------------------------- -- Util -getNamesAtPos :: MonadIO m => IdeState -> NormalizedFilePath -> Position -> ExceptT String m [Name]+getNamesAtPos :: MonadIO m => IdeState -> NormalizedFilePath -> Position -> ExceptT PluginError m [Name] getNamesAtPos state nfp pos = do (HAR{hieAst}, pm) <- handleGetHieAst state nfp pure $ getNamesAtPoint hieAst pos pm@@ -224,10 +227,9 @@ MonadIO m => IdeState -> NormalizedFilePath ->- ExceptT String m (HieAstResult, PositionMapping)-handleGetHieAst state nfp = handleMaybeM- ("No AST for file: " ++ show nfp)- (liftIO $ fmap (fmap (first removeGenerated)) $ runAction "Rename.GetHieAst" state $ useWithStale GetHieAst nfp)+ ExceptT PluginError m (HieAstResult, PositionMapping)+handleGetHieAst state nfp =+ fmap (first removeGenerated) $ runActionE "Rename.GetHieAst" state $ useWithStaleE GetHieAst nfp -- | We don't want to rename in code generated by GHC as this gives false positives. -- So we restrict the HIE file to remove all the generated code.@@ -242,11 +244,6 @@ #else hf #endif--handleUriToNfp :: (Monad m) => Uri -> ExceptT String m NormalizedFilePath-handleUriToNfp uri = handleMaybe- ("No filepath for uri: " ++ show uri)- (toNormalizedFilePath <$> uriToFilePath uri) -- head is safe since groups are non-empty collectWith :: (Hashable a, Eq a, Eq b) => (a -> b) -> HashSet a -> [(b, HashSet a)]