on master help sign in
Escape colons in URIs to be consistent with VSCode (#1504)

The details are described in a comment but the short story is that a roundtrip Uri -> FilePath -> Uri necessarily loses information on which characters were escaped. The long-term solution here is to avoid this roundtrip altogether but this at least fixes the issue for now.

commit30b531a51fa37769f51709631880af43d2be8f06 authorMoritz Kiefer <moritz.kiefer@purelyfunctional.org> dateTue 4 Jun 2019, 09:45 (7 years ago) parent7c3213c
4 files changed+22−9
BUILD.bazel+1 src/Development/IDE/Functions/GHCError.hs+1−2 src/Development/IDE/State/FileStore.hs+5−5 src/Development/IDE/Types/Diagnostics.hs+15−2
BUILD.bazel+1
@@ -19,6 +19,7 @@ depends = [
1919 "haskell-lsp",
2020 "haskell-lsp-types",
2121 "mtl",
22+ "network-uri",
2223 "pretty",
2324 "rope-utf16-splay",
2425 "safe-exceptions",
src/Development/IDE/Functions/GHCError.hs+1−2
@@ -38,7 +38,6 @@ import Data.Maybe
3838import ErrUtils
3939import SrcLoc
4040import qualified Outputable as Out
41−import qualified Language.Haskell.LSP.Types as LSP
4241
4342
4443
@@ -79,7 +78,7 @@ srcSpanToFilename (RealSrcSpan real) = FS.unpackFS $ srcSpanFile real
7978
8079srcSpanToLocation :: SrcSpan -> Location
8180srcSpanToLocation src =
82− Location (LSP.filePathToUri $ srcSpanToFilename src) (srcSpanToRange src)
81+ Location (D.filePathToUri' $ srcSpanToFilename src) (srcSpanToRange src)
8382
8483-- | Convert a GHC severity to a DAML compiler Severity. Severities below
8584-- "Warning" level are dropped (returning Nothing).
src/Development/IDE/State/FileStore.hs+5−5
@@ -96,7 +96,7 @@ getFileExistsRule vfs =
9696 defineEarlyCutoff $ \GetFileExists file -> do
9797 alwaysRerun
9898 res <- liftIO $ handle (\(_ :: IOException) -> return False) $
99− (isJust <$> getVirtualFile vfs (filePathToUri file)) ||^
99+ (isJust <$> getVirtualFile vfs (filePathToUri' file)) ||^
100100 Dir.doesFileExist file
101101 return (Just $ if res then BS.singleton '1' else BS.empty, ([], Just res))
102102
@@ -109,7 +109,7 @@ getModificationTimeRule vfs =
109109 defineEarlyCutoff $ \GetModificationTime file -> do
110110 let wrap time = (Just $ BS.pack $ showTimePrecise time, ([], Just $ ModificationTime time))
111111 alwaysRerun
112− mbVirtual <- liftIO $ getVirtualFile vfs $ filePathToUri file
112+ mbVirtual <- liftIO $ getVirtualFile vfs $ filePathToUri' file
113113 case mbVirtual of
114114 Just (VirtualFile ver _ _) -> pure (Just $ BS.pack $ show ver, ([], Just $ VFSVersion ver))
115115 Nothing -> liftIO $ fmap wrap (Dir.getModificationTime file) `catch` \(e :: IOException) -> do
@@ -124,7 +124,7 @@ getFileContentsRule vfs =
124124 -- need to depend on modification time to introduce a dependency with Cutoff
125125 time <- use_ GetModificationTime file
126126 res <- liftIO $ ideTryIOException file $ do
127− mbVirtual <- getVirtualFile vfs $ filePathToUri file
127+ mbVirtual <- getVirtualFile vfs $ filePathToUri' file
128128 case mbVirtual of
129129 Just (VirtualFile _ rope _) -> return $ textToStringBuffer $ Rope.toText rope
130130 Nothing -> hGetStringBuffer file
@@ -157,8 +157,8 @@ setBufferModified :: IdeState -> FilePath -> Maybe T.Text -> IO ()
157157setBufferModified state absFile mbContents = do
158158 VFSHandle{..} <- getIdeGlobalState state
159159 case mbContents of
160− Nothing -> removeVirtualFile (filePathToUri absFile)
161− Just contents -> setVirtualFileContents (filePathToUri absFile) contents
160+ Nothing -> removeVirtualFile (filePathToUri' absFile)
161+ Just contents -> setVirtualFileContents (filePathToUri' absFile) contents
162162 void $ shakeRun state []
163163
164164
src/Development/IDE/Types/Diagnostics.hs+15−2
@@ -28,7 +28,7 @@ module Development.IDE.Types.Diagnostics (
2828 showDiagnostics,
2929 showDiagnosticsColored,
3030 defDiagnostic,
31− filePathToUri,
31+ filePathToUri',
3232 uriToFilePath',
3333 ProjectDiagnostics,
3434 emptyDiagnostics,
@@ -47,6 +47,7 @@ import qualified Data.Map as Map
4747import qualified Data.Text as T
4848import Data.Text.Prettyprint.Doc.Syntax
4949import qualified Data.SortedList as SL
50+import Network.URI (escapeURIString)
5051import qualified Text.PrettyPrint.Annotated.HughesPJClass as Pretty
5152import qualified Language.Haskell.LSP.Types as LSP
5253import Language.Haskell.LSP.Types as LSP (
@@ -67,9 +68,21 @@ import Development.IDE.Types.Location
6768-- So we have our own wrapper here that supports empty filepaths.
6869uriToFilePath' :: Uri -> Maybe FilePath
6970uriToFilePath' uri
70− | uri == filePathToUri "" = Just ""
71+ | uri == filePathToUri' "" = Just ""
7172 | otherwise = LSP.uriToFilePath uri
7273
74+-- TODO This is a temporary hack: VSCode escapes ':' in URIs while haskell-lsp’s filePathToUri doesn't.
75+-- This causes issues since haskell-lsp stores the original URI in the VFS while we roundtrip once via
76+-- uriToFilePath' and filePathToUri before we look it up again. At that point : will be unescaped in the URI
77+-- so the lookup fails. The long-term solution here is to avoid roundtripping URIs but that is a larger task
78+-- so for now we have our own version of filePathToUri that does escape colons.
79+filePathToUri' :: FilePath -> Uri
80+filePathToUri' fp =
81+ case T.stripPrefix "file:" (getUri uri) of
82+ Just suffix -> Uri $ T.pack $ "file:" <> escapeURIString (/= ':') (T.unpack suffix)
83+ Nothing -> uri
84+ where uri = filePathToUri fp
85+
7386ideErrorText :: FilePath -> T.Text -> FileDiagnostic
7487ideErrorText fp = errorDiag fp "Ide Error"
7588