Skip to content

Commit

Permalink
Keep stale lenses for module name (haskell#3570)
Browse files Browse the repository at this point in the history
* Keep stale lenses for module name

* Return Nothing if toCurrentRange failed

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
July541 and mergify[bot] authored Apr 26, 2023
1 parent 6640ebf commit cda1325
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 40 deletions.
88 changes: 48 additions & 40 deletions plugins/hls-module-name-plugin/src/Ide/Plugin/ModuleName.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,53 @@ module Ide.Plugin.ModuleName (
Log,
) where

import Control.Monad (forM_, void)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Class (lift)
import Control.Monad (forM_, void)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Maybe
import Data.Aeson (Value (Null), toJSON)
import Data.Char (isLower)
import qualified Data.HashMap.Strict as HashMap
import Data.List (intercalate, isPrefixOf,
minimumBy)
import qualified Data.List.NonEmpty as NE
import Data.Maybe (maybeToList)
import Data.Ord (comparing)
import Data.String (IsString)
import qualified Data.Text as T
import Development.IDE (GetParsedModule (GetParsedModule),
GhcSession (GhcSession),
IdeState, Pretty,
Priority (Debug), Recorder,
WithPriority, colon, evalGhcEnv,
hscEnvWithImportPaths, logWith,
realSrcSpanToRange, runAction,
uriToFilePath', use, use_, (<+>))
import Development.IDE.GHC.Compat (GenLocated (L),
getSessionDynFlags, hsmodName,
importPaths, locA,
moduleNameString,
pattern RealSrcSpan,
pm_parsed_source, unLoc)
import Development.IDE.Types.Logger (Pretty (..))
import Data.Aeson (Value (Null), toJSON)
import Data.Char (isLower)
import qualified Data.HashMap.Strict as HashMap
import Data.List (intercalate, isPrefixOf,
minimumBy)
import qualified Data.List.NonEmpty as NE
import Data.Maybe (fromMaybe, maybeToList)
import Data.Ord (comparing)
import Data.String (IsString)
import qualified Data.Text as T
import Development.IDE (GetParsedModule (GetParsedModule),
GhcSession (GhcSession),
IdeState, Pretty,
Priority (Debug),
Recorder, WithPriority,
colon, evalGhcEnv,
hscEnvWithImportPaths,
logWith,
realSrcSpanToRange,
runAction,
uriToFilePath',
useWithStale,
useWithStale_, (<+>))
import Development.IDE.Core.PositionMapping (toCurrentRange)
import Development.IDE.GHC.Compat (GenLocated (L),
getSessionDynFlags,
hsmodName, importPaths,
locA, moduleNameString,
pattern RealSrcSpan,
pm_parsed_source, unLoc)
import Development.IDE.Types.Logger (Pretty (..))
import Ide.Types
import Language.LSP.Server
import Language.LSP.Types hiding
(SemanticTokenAbsolute (length, line),
SemanticTokenRelative (length),
SemanticTokensEdit (_start))
import Language.LSP.VFS (virtualFileText)
import System.Directory (makeAbsolute)
import System.FilePath (dropExtension, normalise,
pathSeparator, splitDirectories,
takeFileName)
import Language.LSP.Types hiding
(SemanticTokenAbsolute (length, line),
SemanticTokenRelative (length),
SemanticTokensEdit (_start))
import Language.LSP.VFS (virtualFileText)
import System.Directory (makeAbsolute)
import System.FilePath (dropExtension, normalise,
pathSeparator,
splitDirectories,
takeFileName)

-- |Plugin descriptor
descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState
Expand Down Expand Up @@ -134,7 +141,7 @@ pathModuleNames :: Recorder (WithPriority Log) -> IdeState -> NormalizedFilePath
pathModuleNames recorder state normFilePath filePath
| isLower . head $ takeFileName filePath = return ["Main"]
| otherwise = do
session <- runAction "ModuleName.ghcSession" state $ use_ GhcSession normFilePath
session <- fst <$> (runAction "ModuleName.ghcSession" state $ useWithStale_ GhcSession normFilePath)
srcPaths <- evalGhcEnv (hscEnvWithImportPaths session) $ importPaths <$> getSessionDynFlags
logWith recorder Debug (SrcPaths srcPaths)

Expand All @@ -160,9 +167,10 @@ pathModuleNames recorder state normFilePath filePath
-- | The module name, as stated in the module
codeModuleName :: IdeState -> NormalizedFilePath -> IO (Maybe (Range, T.Text))
codeModuleName state nfp = runMaybeT $ do
pm <- MaybeT . runAction "ModuleName.GetParsedModule" state $ use GetParsedModule nfp
(pm, mp) <- MaybeT . runAction "ModuleName.GetParsedModule" state $ useWithStale GetParsedModule nfp
L (locA -> (RealSrcSpan l _)) m <- MaybeT . pure . hsmodName . unLoc $ pm_parsed_source pm
pure (realSrcSpanToRange l, T.pack $ moduleNameString m)
range <- MaybeT . pure $ toCurrentRange mp (realSrcSpanToRange l)
pure (range, T.pack $ moduleNameString m)

data Log =
CorrectNames [T.Text]
Expand Down
10 changes: 10 additions & 0 deletions plugins/hls-module-name-plugin/test/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ tests =
[CodeLens { _command = Just c }] <- getCodeLenses doc
executeCommand c
void $ skipManyTill anyMessage (message SWorkspaceApplyEdit)
, testCase "Keep stale lens even if parse failed" $ do
runSessionWithServer moduleNamePlugin testDataDir $ do
doc <- openDoc "Stale.hs" "haskell"
oldLens <- getCodeLenses doc
let edit = TextEdit (mkRange 1 0 1 0) "f ="
_ <- applyEdit doc edit
newLens <- getCodeLenses doc
txt <- documentContents doc
liftIO $ newLens @?= oldLens
closeDoc doc
]

goldenWithModuleName :: TestName -> FilePath -> (TextDocumentIdentifier -> Session ()) -> TestTree
Expand Down
1 change: 1 addition & 0 deletions plugins/hls-module-name-plugin/test/testdata/Stale.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module Foo where

0 comments on commit cda1325

Please sign in to comment.