on master help sign in
Use NormalizedFilePath and adapt types of haskell-lsp-0.21 (#479)

* Use custom version of h-l-t * Use normalized path functions from h-l-t * Restore empty path corner case * Create a wrapper over NFP to override IsString * Use maybe instead fromMaybe * Use patched version of lsp-types in all yaml files * Remove unused import * Rename specific NormalizeFilePath to NormalizeFilePath' * Remove specific newtype and IsString instance * Use released haskell-lsp-0.21 * Adapt to type changes of haskell-lsp-0.21 * Add tags field to CompletionItem * Fix test case about empty file path * Correct stack.yaml used in azure ci cache * Build ghcide including tests in windows azure ci * Qualify haskell-lsp modules to avoid name clashes

commit9951f35b08b997fb0565443d7f61400df3a2557d authorJavier Neira <atreyu.bbb@gmail.com> dateMon 23 Mar 2020, 09:07 (7 years ago) parent209be0b
26 files changed+87−197
.azure/linux-stack.yml+1−1 .azure/windows-stack.yml+2−4 exe/Main.hs+4−4 exe/Rules.hs+2−2 ghcide.cabal+2−2 src/Development/IDE/Core/Compile.hs+1−1 src/Development/IDE/Core/FileExists.hs+4−29 src/Development/IDE/Core/Preprocessor.hs+3−2 src/Development/IDE/Core/Rules.hs+5−4 src/Development/IDE/Core/Shake.hs+4−4 src/Development/IDE/GHC/Error.hs+3−2 src/Development/IDE/GHC/Util.hs+1−1 src/Development/IDE/Import/FindImports.hs+1−1 src/Development/IDE/LSP/HoverDefinition.hs+1−1 src/Development/IDE/LSP/Notifications.hs+2−2 src/Development/IDE/LSP/Outline.hs+1−1 src/Development/IDE/Plugin/CodeAction.hs+2−2 src/Development/IDE/Plugin/Completions.hs+1−1 src/Development/IDE/Plugin/Completions/Logic.hs+5−5 src/Development/IDE/Types/Diagnostics.hs+2−1 src/Development/IDE/Types/Location.hs+21−116 stack-ghc-lib.yaml+3−3 stack.yaml+3−3 stack84.yaml+3−3 stack88.yaml+4 test/exe/Main.hs+6−2
.azure/linux-stack.yml+1−1
@@ -17,7 +17,7 @@ jobs:
1717 - checkout: self
1818 - task: Cache@2
1919 inputs:
20− key: stack-cache-v2 | $(Agent.OS) | $(Build.SourcesDirectory)/stack.yaml | $(Build.SourcesDirectory)/ghcide.cabal
20+ key: stack-cache-v2 | $(Agent.OS) | $(Build.SourcesDirectory)/$(STACK_YAML) | $(Build.SourcesDirectory)/ghcide.cabal
2121 path: .azure-cache
2222 cacheHitVar: CACHE_RESTORED
2323 displayName: "Cache stack artifacts"
.azure/windows-stack.yml+2−4
@@ -46,11 +46,9 @@ jobs:
4646 stack install alex --stack-yaml $STACK_YAML
4747 stack build --only-dependencies --stack-yaml $STACK_YAML
4848 displayName: 'stack build --only-dependencies'
49− - bash: stack test --ghc-options=-Werror --stack-yaml $STACK_YAML || stack test --ghc-options=-Werror --stack-yaml $STACK_YAML || stack test --ghc-options=-Werror --stack-yaml $STACK_YAML
50− # ghcide stack tests are flaky, see https://github.com/digital-asset/daml/issues/2606.
49+ - bash: stack test --no-run-tests --ghc-options=-Werror --stack-yaml $STACK_YAML
5150 displayName: 'stack test --ghc-options=-Werror'
52− # TODO: Enable when failing tests are fixed or marked as broken. See https://github.com/digital-asset/ghcide/issues/474
53− condition: False
51+ # TODO: run test suite when failing tests are fixed or marked as broken. See https://github.com/digital-asset/ghcide/issues/474
5452 - bash: |
5553 mkdir -p .azure-cache
5654 tar -vczf .azure-cache/stack-root.tar.gz $(cygpath $STACK_ROOT)
exe/Main.hs+4−4
@@ -146,8 +146,8 @@ main = do
146146 ide <- initialise def (cradleRules >> mainRule) (pure $ IdInt 0) (showEvent lock) (logger Info) noopDebouncer options vfs
147147
148148 putStrLn "\nStep 6/6: Type checking the files"
149− setFilesOfInterest ide $ HashSet.fromList $ map toNormalizedFilePath files
150− results <- runActionSync ide $ uses TypeCheck $ map toNormalizedFilePath files
149+ setFilesOfInterest ide $ HashSet.fromList $ map toNormalizedFilePath' files
150+ results <- runActionSync ide $ uses TypeCheck $ map toNormalizedFilePath' files
151151 let (worked, failed) = partition fst $ zip (map isJust results) files
152152 when (failed /= []) $
153153 putStr $ unlines $ "Files that failed:" : map ((++) " * " . snd) failed
@@ -183,7 +183,7 @@ kick = do
183183-- | Print an LSP event.
184184showEvent :: Lock -> FromServerMessage -> IO ()
185185showEvent _ (EventFileDiagnostics _ []) = return ()
186−showEvent lock (EventFileDiagnostics (toNormalizedFilePath -> file) diags) =
186+showEvent lock (EventFileDiagnostics (toNormalizedFilePath' -> file) diags) =
187187 withLock lock $ T.putStrLn $ showDiagnosticsColored $ map (file,ShowDiag,) diags
188188showEvent lock e = withLock lock $ print e
189189
@@ -199,7 +199,7 @@ loadSession dir = liftIO $ do
199199 let session :: Maybe FilePath -> Action HscEnvEq
200200 session file = do
201201 -- In the absence of a cradle file, just pass the directory from where to calculate an implicit cradle
202− let cradle = toNormalizedFilePath $ fromMaybe dir file
202+ let cradle = toNormalizedFilePath' $ fromMaybe dir file
203203 use_ LoadCradle cradle
204204 return $ \file -> session =<< liftIO (cradleLoc file)
205205
exe/Rules.hs+2−2
@@ -36,8 +36,8 @@ import qualified System.Directory.Extra as IO
3636import System.Environment (lookupEnv)
3737import System.FilePath.Posix (addTrailingPathSeparator,
3838 (</>))
39−import Language.Haskell.LSP.Messages as LSP
40−import Language.Haskell.LSP.Types as LSP
39+import qualified Language.Haskell.LSP.Messages as LSP
40+import qualified Language.Haskell.LSP.Types as LSP
4141import Data.Aeson (ToJSON(toJSON))
4242import Development.IDE.Types.Logger (logDebug)
4343
ghcide.cabal+2−2
@@ -43,8 +43,8 @@ library
4343 filepath,
4444 haddock-library >= 1.8,
4545 hashable,
46− haskell-lsp-types == 0.20.*,
47− haskell-lsp == 0.20.*,
46+ haskell-lsp-types == 0.21.*,
47+ haskell-lsp == 0.21.*,
4848 mtl,
4949 network-uri,
5050 prettyprinter-ansi-terminal,
src/Development/IDE/Core/Compile.hs+1−1
@@ -93,7 +93,7 @@ computePackageDeps
9393computePackageDeps env pkg = do
9494 let dflags = hsc_dflags env
9595 case lookupInstalledPackage dflags pkg of
96− Nothing -> return $ Left [ideErrorText (toNormalizedFilePath noFilePath) $
96+ Nothing -> return $ Left [ideErrorText (toNormalizedFilePath' noFilePath) $
9797 T.pack $ "unknown package: " ++ show pkg]
9898 Just pkgInfo -> return $ Right $ depends pkgInfo
9999
src/Development/IDE/Core/FileExists.hs+4−29
@@ -146,9 +146,10 @@ fileExistsFast getLspId vfs file = do
146146 WorkspaceDidChangeWatchedFiles
147147 (Just (A.toJSON regOptions))
148148 regOptions =
149− DidChangeWatchedFilesRegistrationOptions { watchers = List [watcher] }
150− watcher = FileSystemWatcher { globPattern = fromNormalizedFilePath fp
151− , kind = Just 5 -- Create and Delete events only
149+ DidChangeWatchedFilesRegistrationOptions { _watchers = List [watcher] }
150+ watchKind = WatchKind { _watchCreate = True, _watchChange = False, _watchDelete = True}
151+ watcher = FileSystemWatcher { _globPattern = fromNormalizedFilePath fp
152+ , _kind = Just watchKind
152153 }
153154
154155 eventer $ ReqRegisterCapability req
@@ -174,29 +175,3 @@ getFileExistsVFS vfs file = do
174175 handle (\(_ :: IOException) -> return False) $
175176 (isJust <$> getVirtualFile vfs (filePathToUri' file)) ||^
176177 Dir.doesFileExist (fromNormalizedFilePath file)
177−
178−--------------------------------------------------------------------------------------------------
179−-- The message definitions below probably belong in haskell-lsp-types
180−
181−data DidChangeWatchedFilesRegistrationOptions = DidChangeWatchedFilesRegistrationOptions
182− { watchers :: List FileSystemWatcher
183− }
184−
185−instance A.ToJSON DidChangeWatchedFilesRegistrationOptions where
186− toJSON DidChangeWatchedFilesRegistrationOptions {..} =
187− A.object ["watchers" A..= watchers]
188−
189−data FileSystemWatcher = FileSystemWatcher
190− { -- | The glob pattern to watch.
191− -- For details on glob pattern syntax, check the spec: https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#workspace_didChangeWatchedFiles
192− globPattern :: String
193− -- | The kind of event to subscribe to. Defaults to all.
194− -- Defined as a bitmap of Create(1), Change(2), and Delete(4)
195− , kind :: Maybe Int
196− }
197−
198−instance A.ToJSON FileSystemWatcher where
199− toJSON FileSystemWatcher {..} =
200− A.object
201− $ ["globPattern" A..= globPattern]
202− ++ [ "kind" A..= x | Just x <- [kind] ]
src/Development/IDE/Core/Preprocessor.hs+3−2
@@ -96,7 +96,7 @@ data CPPDiag
9696
9797diagsFromCPPLogs :: FilePath -> [CPPLog] -> [FileDiagnostic]
9898diagsFromCPPLogs filename logs =
99− map (\d -> (toNormalizedFilePath filename, ShowDiag, cppDiagToDiagnostic d)) $
99+ map (\d -> (toNormalizedFilePath' filename, ShowDiag, cppDiagToDiagnostic d)) $
100100 go [] logs
101101 where
102102 -- On errors, CPP calls logAction with a real span for the initial log and
@@ -118,7 +118,8 @@ diagsFromCPPLogs filename logs =
118118 _code = Nothing,
119119 _source = Just "CPP",
120120 _message = T.unlines $ cdMessage d,
121− _relatedInformation = Nothing
121+ _relatedInformation = Nothing,
122+ _tags = Nothing
122123 }
123124
124125
src/Development/IDE/Core/Rules.hs+5−4
@@ -80,14 +80,14 @@ useE :: IdeRule k v => k -> NormalizedFilePath -> MaybeT Action v
8080useE k = MaybeT . use k
8181
8282useNoFileE :: IdeRule k v => k -> MaybeT Action v
83−useNoFileE k = useE k ""
83+useNoFileE k = useE k emptyFilePath
8484
8585usesE :: IdeRule k v => k -> [NormalizedFilePath] -> MaybeT Action [v]
8686usesE k = MaybeT . fmap sequence . uses k
8787
8888defineNoFile :: IdeRule k v => (k -> Action v) -> Rules ()
8989defineNoFile f = define $ \k file -> do
90− if file == "" then do res <- f k; return ([], Just res) else
90+ if file == emptyFilePath then do res <- f k; return ([], Just res) else
9191 fail $ "Rule " ++ show k ++ " should always be called with the empty string for a file"
9292
9393
@@ -130,7 +130,7 @@ getHieFile file mod = do
130130getHomeHieFile :: NormalizedFilePath -> Action ([a], Maybe HieFile)
131131getHomeHieFile f = do
132132 pm <- use_ GetParsedModule f
133− let normal_hie_f = toNormalizedFilePath hie_f
133+ let normal_hie_f = toNormalizedFilePath' hie_f
134134 hie_f = ml_hie_file $ ms_location $ pm_mod_summary pm
135135 mbHieTimestamp <- use GetModificationTime normal_hie_f
136136 srcTimestamp <- use_ GetModificationTime f
@@ -292,9 +292,10 @@ reportImportCyclesRule =
292292 , _message = "Cyclic module dependency between " <> showCycle mods
293293 , _code = Nothing
294294 , _relatedInformation = Nothing
295+ , _tags = Nothing
295296 }
296297 where loc = srcSpanToLocation (getLoc imp)
297− fp = toNormalizedFilePath $ srcSpanToFilename (getLoc imp)
298+ fp = toNormalizedFilePath' $ srcSpanToFilename (getLoc imp)
298299 getModuleName file = do
299300 pm <- use_ GetParsedModule file
300301 pure (moduleNameString . moduleName . ms_mod $ pm_mod_summary pm)
src/Development/IDE/Core/Shake.hs+4−4
@@ -414,7 +414,7 @@ shakeRun IdeState{shakeExtras=ShakeExtras{..}, ..} acts =
414414 Right _ -> "completed"
415415 profile = case res of
416416 Right (_, Just fp) ->
417− let link = case filePathToUri' $ toNormalizedFilePath fp of
417+ let link = case filePathToUri' $ toNormalizedFilePath' fp of
418418 NormalizedUri _ x -> x
419419 in ", profile saved at " <> T.unpack link
420420 _ -> ""
@@ -473,13 +473,13 @@ useWithStale :: IdeRule k v
473473useWithStale key file = head <$> usesWithStale key [file]
474474
475475useNoFile :: IdeRule k v => k -> Action (Maybe v)
476−useNoFile key = use key ""
476+useNoFile key = use key emptyFilePath
477477
478478use_ :: IdeRule k v => k -> NormalizedFilePath -> Action v
479479use_ key file = head <$> uses_ key [file]
480480
481481useNoFile_ :: IdeRule k v => k -> Action v
482−useNoFile_ key = use_ key ""
482+useNoFile_ key = use_ key emptyFilePath
483483
484484uses_ :: IdeRule k v => k -> [NormalizedFilePath] -> Action [v]
485485uses_ key files = do
@@ -819,7 +819,7 @@ filterDiagnostics ::
819819 DiagnosticStore ->
820820 DiagnosticStore
821821filterDiagnostics keep =
822− HMap.filterWithKey (\uri _ -> maybe True (keep . toNormalizedFilePath) $ uriToFilePath' $ fromNormalizedUri uri)
822+ HMap.filterWithKey (\uri _ -> maybe True (keep . toNormalizedFilePath') $ uriToFilePath' $ fromNormalizedUri uri)
823823
824824filterVersionMap
825825 :: HMap.HashMap NormalizedUri (Set.Set TextDocumentVersion)
src/Development/IDE/GHC/Error.hs+3−2
@@ -40,7 +40,7 @@ import qualified Outputable as Out
4040
4141
4242diagFromText :: T.Text -> D.DiagnosticSeverity -> SrcSpan -> T.Text -> FileDiagnostic
43−diagFromText diagSource sev loc msg = (toNormalizedFilePath $ srcSpanToFilename loc,ShowDiag,)
43+diagFromText diagSource sev loc msg = (toNormalizedFilePath' $ srcSpanToFilename loc,ShowDiag,)
4444 Diagnostic
4545 { _range = srcSpanToRange loc
4646 , _severity = Just sev
@@ -48,6 +48,7 @@ diagFromText diagSource sev loc msg = (toNormalizedFilePath $ srcSpanToFilename
4848 , _message = msg
4949 , _code = Nothing
5050 , _relatedInformation = Nothing
51+ , _tags = Nothing
5152 }
5253
5354-- | Produce a GHC-style error from a source span and a message.
@@ -80,7 +81,7 @@ srcSpanToFilename (RealSrcSpan real) = FS.unpackFS $ srcSpanFile real
8081srcSpanToLocation :: SrcSpan -> Location
8182srcSpanToLocation src =
8283 -- important that the URI's we produce have been properly normalized, otherwise they point at weird places in VS Code
83− Location (fromNormalizedUri $ filePathToUri' $ toNormalizedFilePath $ srcSpanToFilename src) (srcSpanToRange src)
84+ Location (fromNormalizedUri $ filePathToUri' $ toNormalizedFilePath' $ srcSpanToFilename src) (srcSpanToRange src)
8485
8586isInsideSrcSpan :: Position -> SrcSpan -> Bool
8687p `isInsideSrcSpan` r = sp <= p && p <= ep
src/Development/IDE/GHC/Util.hs+1−1
@@ -139,7 +139,7 @@ moduleImportPath (takeDirectory . fromNormalizedFilePath -> pathDir) pm
139139 -- A for module A.B
140140 modDir =
141141 takeDirectory $
142− fromNormalizedFilePath $ toNormalizedFilePath $
142+ fromNormalizedFilePath $ toNormalizedFilePath' $
143143 moduleNameSlashes $ GHC.moduleName mod'
144144
145145-- | An 'HscEnv' with equality. Two values are considered equal
src/Development/IDE/Import/FindImports.hs+1−1
@@ -58,7 +58,7 @@ locateModuleFile :: MonadIO m
5858 -> m (Maybe NormalizedFilePath)
5959locateModuleFile dflags exts doesExist isSource modName = do
6060 let candidates =
61− [ toNormalizedFilePath (prefix </> M.moduleNameSlashes modName <.> maybeBoot ext)
61+ [ toNormalizedFilePath' (prefix </> M.moduleNameSlashes modName <.> maybeBoot ext)
6262 | prefix <- importPaths dflags, ext <- exts]
6363 findM doesExist candidates
6464 where
src/Development/IDE/LSP/HoverDefinition.hs+1−1
@@ -55,7 +55,7 @@ request label getResults notFound found ide (TextDocumentPositionParams (TextDoc
5555
5656logAndRunRequest :: T.Text -> (NormalizedFilePath -> Position -> Action b) -> IdeState -> Position -> String -> IO b
5757logAndRunRequest label getResults ide pos path = do
58− let filePath = toNormalizedFilePath path
58+ let filePath = toNormalizedFilePath' path
5959 logInfo (ideLogger ide) $
6060 label <> " request at position " <> T.pack (showPosition pos) <>
6161 " in file: " <> T.pack path
src/Development/IDE/LSP/Notifications.hs+2−2
@@ -30,7 +30,7 @@ import Development.IDE.Core.OfInterest
3030
3131
3232whenUriFile :: Uri -> (NormalizedFilePath -> IO ()) -> IO ()
33−whenUriFile uri act = whenJust (LSP.uriToFilePath uri) $ act . toNormalizedFilePath
33+whenUriFile uri act = whenJust (LSP.uriToFilePath uri) $ act . toNormalizedFilePath'
3434
3535setHandlersNotifications :: PartialHandlers c
3636setHandlersNotifications = PartialHandlers $ \WithMessage{..} x -> return x
@@ -62,7 +62,7 @@ setHandlersNotifications = PartialHandlers $ \WithMessage{..} x -> return x
6262 let events =
6363 mapMaybe
6464 (\(FileEvent uri ev) ->
65− (, ev /= FcDeleted) . toNormalizedFilePath
65+ (, ev /= FcDeleted) . toNormalizedFilePath'
6666 <$> LSP.uriToFilePath uri
6767 )
6868 ( F.toList fileEvents )
src/Development/IDE/LSP/Outline.hs+1−1
@@ -37,7 +37,7 @@ moduleOutline
3737 :: LSP.LspFuncs c -> IdeState -> DocumentSymbolParams -> IO (Either ResponseError DSResult)
3838moduleOutline _lsp ideState DocumentSymbolParams { _textDocument = TextDocumentIdentifier uri }
3939 = case uriToFilePath uri of
40− Just (toNormalizedFilePath -> fp) -> do
40+ Just (toNormalizedFilePath' -> fp) -> do
4141 mb_decls <- runAction ideState $ use GetParsedModule fp
4242 pure $ Right $ case mb_decls of
4343 Nothing -> DSDocumentSymbols (List [])
src/Development/IDE/Plugin/CodeAction.hs+2−2
@@ -64,7 +64,7 @@ codeAction lsp state (TextDocumentIdentifier uri) _range CodeActionContext{_diag
6464 -- logInfo (ideLogger ide) $ T.pack $ "Code action req: " ++ show arg
6565 contents <- LSP.getVirtualFileFunc lsp $ toNormalizedUri uri
6666 let text = Rope.toText . (_text :: VirtualFile -> Rope.Rope) <$> contents
67− mbFile = toNormalizedFilePath <$> uriToFilePath uri
67+ mbFile = toNormalizedFilePath' <$> uriToFilePath uri
6868 (ideOptions, parsedModule, join -> env) <- runAction state $
6969 (,,) <$> getIdeOptions
7070 <*> getParsedModule `traverse` mbFile
@@ -85,7 +85,7 @@ codeLens
8585 -> IO (Either ResponseError (List CodeLens))
8686codeLens _lsp ideState CodeLensParams{_textDocument=TextDocumentIdentifier uri} = do
8787 fmap (Right . List) $ case uriToFilePath' uri of
88− Just (toNormalizedFilePath -> filePath) -> do
88+ Just (toNormalizedFilePath' -> filePath) -> do
8989 _ <- runAction ideState $ runMaybeT $ useE TypeCheck filePath
9090 diag <- getDiagnostics ideState
9191 hDiag <- getHiddenDiagnostics ideState
src/Development/IDE/Plugin/Completions.hs+1−1
@@ -66,7 +66,7 @@ getCompletionsLSP lsp ide
6666 contents <- LSP.getVirtualFileFunc lsp $ toNormalizedUri uri
6767 fmap Right $ case (contents, uriToFilePath' uri) of
6868 (Just cnts, Just path) -> do
69− let npath = toNormalizedFilePath path
69+ let npath = toNormalizedFilePath' path
7070 (ideOpts, compls) <- runAction ide $ do
7171 opts <- getIdeOptions
7272 compls <- useWithStale ProduceCompletions npath
src/Development/IDE/Plugin/Completions/Logic.hs+5−5
@@ -132,7 +132,7 @@ occNameToComKind ty oc
132132
133133mkCompl :: IdeOptions -> CompItem -> CompletionItem
134134mkCompl IdeOptions{..} CI{origName,importedFrom,thingType,label,isInfix,docs} =
135− CompletionItem label kind ((colon <>) <$> typeText)
135+ CompletionItem label kind (List []) ((colon <>) <$> typeText)
136136 (Just $ CompletionDocMarkup $ MarkupContent MkMarkdown $ T.intercalate sectionSeparator docs')
137137 Nothing Nothing Nothing Nothing (Just insertText) (Just Snippet)
138138 Nothing Nothing Nothing Nothing Nothing
@@ -186,13 +186,13 @@ getArgText typ = argText
186186
187187mkModCompl :: T.Text -> CompletionItem
188188mkModCompl label =
189− CompletionItem label (Just CiModule) Nothing
189+ CompletionItem label (Just CiModule) (List []) Nothing
190190 Nothing Nothing Nothing Nothing Nothing Nothing Nothing
191191 Nothing Nothing Nothing Nothing Nothing
192192
193193mkImportCompl :: T.Text -> T.Text -> CompletionItem
194194mkImportCompl enteredQual label =
195− CompletionItem m (Just CiModule) (Just label)
195+ CompletionItem m (Just CiModule) (List []) (Just label)
196196 Nothing Nothing Nothing Nothing Nothing Nothing Nothing
197197 Nothing Nothing Nothing Nothing Nothing
198198 where
@@ -200,13 +200,13 @@ mkImportCompl enteredQual label =
200200
201201mkExtCompl :: T.Text -> CompletionItem
202202mkExtCompl label =
203− CompletionItem label (Just CiKeyword) Nothing
203+ CompletionItem label (Just CiKeyword) (List []) Nothing
204204 Nothing Nothing Nothing Nothing Nothing Nothing Nothing
205205 Nothing Nothing Nothing Nothing Nothing
206206
207207mkPragmaCompl :: T.Text -> T.Text -> CompletionItem
208208mkPragmaCompl label insertText =
209− CompletionItem label (Just CiKeyword) Nothing
209+ CompletionItem label (Just CiKeyword) (List []) Nothing
210210 Nothing Nothing Nothing Nothing Nothing (Just insertText) (Just Snippet)
211211 Nothing Nothing Nothing Nothing Nothing
212212
src/Development/IDE/Types/Diagnostics.hs+2−1
@@ -38,7 +38,8 @@ ideErrorText fp msg = (fp, ShowDiag, LSP.Diagnostic {
3838 _code = Nothing,
3939 _source = Just "compiler",
4040 _message = msg,
41− _relatedInformation = Nothing
41+ _relatedInformation = Nothing,
42+ _tags = Nothing
4243 })
4344
4445-- | Defines whether a particular diagnostic should be reported
src/Development/IDE/Types/Location.hs+21−116
@@ -10,15 +10,15 @@ module Development.IDE.Types.Location
1010 , Position(..)
1111 , showPosition
1212 , Range(..)
13− , Uri(..)
14− , NormalizedUri
13+ , LSP.Uri(..)
14+ , LSP.NormalizedUri
1515 , LSP.toNormalizedUri
1616 , LSP.fromNormalizedUri
17− , NormalizedFilePath
17+ , LSP.NormalizedFilePath
1818 , fromUri
19− , toNormalizedFilePath
20− , fromNormalizedFilePath
21− , filePathToUri
19+ , emptyFilePath
20+ , toNormalizedFilePath'
21+ , LSP.fromNormalizedFilePath
2222 , filePathToUri'
2323 , uriToFilePath'
2424 , readSrcSpan
@@ -26,135 +26,40 @@ module Development.IDE.Types.Location
2626
2727import Control.Applicative
2828import Language.Haskell.LSP.Types (Location(..), Range(..), Position(..))
29−import Control.DeepSeq
3029import Control.Monad
31−import Data.Binary
32−import Data.Maybe as Maybe
33−import Data.Hashable
30+import Data.Hashable (Hashable(hash))
3431import Data.String
35−import qualified Data.Text as T
3632import FastString
37−import Network.URI
38−import System.FilePath
39−import qualified System.FilePath.Posix as FPP
40−import qualified System.FilePath.Windows as FPW
41−import System.Info.Extra
4233import qualified Language.Haskell.LSP.Types as LSP
43−import Language.Haskell.LSP.Types as LSP (
44− filePathToUri
45− , NormalizedUri(..)
46− , Uri(..)
47− , toNormalizedUri
48− , fromNormalizedUri
49− )
5034import SrcLoc as GHC
5135import Text.ParserCombinators.ReadP as ReadP
52−import GHC.Generics
36+import Data.Maybe (fromMaybe)
5337
54−
55−-- | Newtype wrapper around FilePath that always has normalized slashes.
56−-- The NormalizedUri and hash of the FilePath are cached to avoided
57−-- repeated normalisation when we need to compute them (which is a lot).
58−--
59−-- This is one of the most performance critical parts of ghcide, do not
60−-- modify it without profiling.
61−data NormalizedFilePath = NormalizedFilePath NormalizedUriWrapper !Int !FilePath
62− deriving (Generic, Eq, Ord)
63−
64−instance NFData NormalizedFilePath where
65−instance Binary NormalizedFilePath where
66− put (NormalizedFilePath _ _ fp) = put fp
67− get = do
68− v <- Data.Binary.get :: Get FilePath
69− return (toNormalizedFilePath v)
70−
71−
72−instance Show NormalizedFilePath where
73− show (NormalizedFilePath _ _ fp) = "NormalizedFilePath " ++ show fp
74−
75−instance Hashable NormalizedFilePath where
76− hash (NormalizedFilePath _ h _) = h
77−
78−-- Just to define NFData and Binary
79−newtype NormalizedUriWrapper =
80− NormalizedUriWrapper { unwrapNormalizedFilePath :: NormalizedUri }
81− deriving (Show, Generic, Eq, Ord)
82−
83−instance NFData NormalizedUriWrapper where
84− rnf = rwhnf
85−
86−
87−instance Hashable NormalizedUriWrapper where
88−
89−instance IsString NormalizedFilePath where
90− fromString = toNormalizedFilePath
91−
92−toNormalizedFilePath :: FilePath -> NormalizedFilePath
38+toNormalizedFilePath' :: FilePath -> LSP.NormalizedFilePath
9339-- We want to keep empty paths instead of normalising them to "."
94−toNormalizedFilePath "" = NormalizedFilePath (NormalizedUriWrapper emptyPathUri) (hash ("" :: String)) ""
95−toNormalizedFilePath fp =
96− let nfp = normalise fp
97− in NormalizedFilePath (NormalizedUriWrapper $ filePathToUriInternal' nfp) (hash nfp) nfp
40+toNormalizedFilePath' "" = emptyFilePath
41+toNormalizedFilePath' fp = LSP.toNormalizedFilePath fp
9842
99−fromNormalizedFilePath :: NormalizedFilePath -> FilePath
100−fromNormalizedFilePath (NormalizedFilePath _ _ fp) = fp
43+emptyFilePath :: LSP.NormalizedFilePath
44+emptyFilePath = LSP.NormalizedFilePath emptyPathUri ""
10145
10246-- | We use an empty string as a filepath when we don’t have a file.
10347-- However, haskell-lsp doesn’t support that in uriToFilePath and given
10448-- that it is not a valid filepath it does not make sense to upstream a fix.
10549-- So we have our own wrapper here that supports empty filepaths.
106−uriToFilePath' :: Uri -> Maybe FilePath
50+uriToFilePath' :: LSP.Uri -> Maybe FilePath
10751uriToFilePath' uri
108− | uri == fromNormalizedUri emptyPathUri = Just ""
52+ | uri == LSP.fromNormalizedUri emptyPathUri = Just ""
10953 | otherwise = LSP.uriToFilePath uri
11054
111−emptyPathUri :: NormalizedUri
112−emptyPathUri = filePathToUriInternal' ""
113−
114−filePathToUri' :: NormalizedFilePath -> NormalizedUri
115−filePathToUri' (NormalizedFilePath (NormalizedUriWrapper u) _ _) = u
55+emptyPathUri :: LSP.NormalizedUri
56+emptyPathUri = LSP.NormalizedUri (hash ("" :: String)) ""
11657
117−filePathToUriInternal' :: FilePath -> NormalizedUri
118−filePathToUriInternal' fp = toNormalizedUri $ Uri $ T.pack $ LSP.fileScheme <> "//" <> platformAdjustToUriPath fp
119− where
120− -- The definitions below are variants of the corresponding functions in Language.Haskell.LSP.Types.Uri that assume that
121− -- the filepath has already been normalised. This is necessary since normalising the filepath has a nontrivial cost.
122−
123− toNormalizedUri :: Uri -> NormalizedUri
124− toNormalizedUri (Uri t) =
125− let fp = T.pack $ escapeURIString isUnescapedInURI $ unEscapeString $ T.unpack t
126− in NormalizedUri (hash fp) fp
127−
128− platformAdjustToUriPath :: FilePath -> String
129− platformAdjustToUriPath srcPath
130− | isWindows = '/' : escapedPath
131− | otherwise = escapedPath
132− where
133− (splitDirectories, splitDrive)
134− | isWindows =
135− (FPW.splitDirectories, FPW.splitDrive)
136− | otherwise =
137− (FPP.splitDirectories, FPP.splitDrive)
138− escapedPath =
139− case splitDrive srcPath of
140− (drv, rest) ->
141− convertDrive drv `FPP.joinDrive`
142− FPP.joinPath (map (escapeURIString unescaped) $ splitDirectories rest)
143− -- splitDirectories does not remove the path separator after the drive so
144− -- we do a final replacement of \ to /
145− convertDrive drv
146− | isWindows && FPW.hasTrailingPathSeparator drv =
147− FPP.addTrailingPathSeparator (init drv)
148− | otherwise = drv
149− unescaped c
150− | isWindows = isUnreserved c || c `elem` [':', '\\', '/']
151− | otherwise = isUnreserved c || c == '/'
152−
153−
154−
155−fromUri :: LSP.NormalizedUri -> NormalizedFilePath
156−fromUri = toNormalizedFilePath . fromMaybe noFilePath . uriToFilePath' . fromNormalizedUri
58+filePathToUri' :: LSP.NormalizedFilePath -> LSP.NormalizedUri
59+filePathToUri' = LSP.normalizedFilePathToUri
15760
61+fromUri :: LSP.NormalizedUri -> LSP.NormalizedFilePath
62+fromUri = fromMaybe (toNormalizedFilePath' noFilePath) . LSP.uriToNormalizedFilePath
15863
15964noFilePath :: FilePath
16065noFilePath = "<unknown>"
stack-ghc-lib.yaml+3−3
@@ -2,9 +2,9 @@ resolver: nightly-2019-09-16
22packages:
33- .
44extra-deps:
5−- haskell-lsp-0.20.0.0
6−- haskell-lsp-types-0.20.0.0
7−- lsp-test-0.10.1.0
5+- haskell-lsp-0.21.0.0
6+- haskell-lsp-types-0.21.0.0
7+- lsp-test-0.10.2.0
88- hie-bios-0.4.0
99- ghc-lib-parser-8.8.1
1010- ghc-lib-8.8.1
stack.yaml+3−3
@@ -2,9 +2,9 @@ resolver: nightly-2019-09-21
22packages:
33- .
44extra-deps:
5−- haskell-lsp-0.20.0.0
6−- haskell-lsp-types-0.20.0.0
7−- lsp-test-0.10.1.0
5+- haskell-lsp-0.21.0.0
6+- haskell-lsp-types-0.21.0.0
7+- lsp-test-0.10.2.0
88- hie-bios-0.4.0
99- fuzzy-0.1.0.0
1010- regex-pcre-builtin-0.95.1.1.8.43
stack84.yaml+3−3
@@ -5,9 +5,9 @@ packages:
55extra-deps:
66- aeson-1.4.6.0
77- base-orphans-0.8.2
8−- haskell-lsp-0.20.0.0
9−- haskell-lsp-types-0.20.0.0
10−- lsp-test-0.10.1.0
8+- haskell-lsp-0.21.0.0
9+- haskell-lsp-types-0.21.0.0
10+- lsp-test-0.10.2.0
1111- rope-utf16-splay-0.3.1.0
1212- filepattern-0.1.1
1313- js-dgtable-0.5.2
stack88.yaml+4
@@ -2,5 +2,9 @@ resolver: nightly-2020-02-13
22packages:
33- .
44extra-deps:
5+- haskell-lsp-0.21.0.0
6+- haskell-lsp-types-0.21.0.0
7+- lsp-test-0.10.2.0
8+
59nix:
610 packages: [zlib]
test/exe/Main.hs+6−2
@@ -1658,6 +1658,7 @@ completionTests
16581658 complItem label kind ty = CompletionItem
16591659 { _label = label
16601660 , _kind = kind
1661+ , _tags = List []
16611662 , _detail = (":: " <>) <$> ty
16621663 , _documentation = Nothing
16631664 , _deprecated = Nothing
@@ -1675,6 +1676,7 @@ completionTests
16751676 keywordItem label = CompletionItem
16761677 { _label = label
16771678 , _kind = Just CiKeyword
1679+ , _tags = List []
16781680 , _detail = Nothing
16791681 , _documentation = Nothing
16801682 , _deprecated = Nothing
@@ -2104,8 +2106,10 @@ findCodeAction doc range t = head <$> findCodeActions doc range [t]
21042106unitTests :: TestTree
21052107unitTests = do
21062108 testGroup "Unit"
2107− [ testCase "empty file path" $
2108− uriToFilePath' (fromNormalizedUri $ filePathToUri' "") @?= Just ""
2109+ [ testCase "empty file path does NOT work with the empty String literal" $
2110+ uriToFilePath' (fromNormalizedUri $ filePathToUri' "") @?= Just "."
2111+ , testCase "empty file path works using toNormalizedFilePath'" $
2112+ uriToFilePath' (fromNormalizedUri $ filePathToUri' (toNormalizedFilePath' "")) @?= Just ""
21092113 ]
21102114
21112115-- | Wrapper around 'LSPTest.openDoc'' that sends file creation events