on a58751e help sign in
100 lines 3.3 kB history raw
1-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2-- SPDX-License-Identifier: Apache-2.0
5-- | Types and functions for working with source code locations.
6module Development.IDE.Types.Location
7 ( Location(..)
8 , noFilePath
9 , noRange
10 , Position(..)
11 , showPosition
12 , Range(..)
13 , Uri(..)
14 , NormalizedUri
15 , LSP.toNormalizedUri
16 , LSP.fromNormalizedUri
17 , NormalizedFilePath
18 , fromUri
19 , toNormalizedFilePath
20 , fromNormalizedFilePath
21 , filePathToUri
22 , filePathToUri'
23 , uriToFilePath'
24 ) where
26import Language.Haskell.LSP.Types (Location(..), Range(..), Position(..))
27import Control.DeepSeq
28import Data.Maybe as Maybe
29import Data.Hashable
30import Data.String
31import System.FilePath
32import System.Info.Extra
33import qualified Language.Haskell.LSP.Types as LSP
34import Language.Haskell.LSP.Types as LSP (
35 filePathToUri
36 , NormalizedUri(..)
37 , Uri(..)
38 , toNormalizedUri
39 , fromNormalizedUri
40 )
43-- | Newtype wrapper around FilePath that always has normalized slashes.
44newtype NormalizedFilePath = NormalizedFilePath FilePath
45 deriving (Eq, Ord, Show, Hashable, NFData)
47instance IsString NormalizedFilePath where
48 fromString = toNormalizedFilePath
50toNormalizedFilePath :: FilePath -> NormalizedFilePath
51toNormalizedFilePath "" = NormalizedFilePath ""
52toNormalizedFilePath fp = NormalizedFilePath $ normalise' fp
53 where
54 -- We do not use System.FilePath’s normalise here since that
55 -- also normalises things like the case of the drive letter
56 -- which NormalizedUri does not normalise so we get VFS lookup failures.
57 normalise' :: FilePath -> FilePath
58 normalise' = oneSlash . map (\c -> if isPathSeparator c then pathSeparator else c)
60 -- Allow double slashes as the very first element of the path for UNC drives on Windows
61 -- otherwise turn adjacent slashes into one. These slashes often arise from dodgy CPP
62 oneSlash :: FilePath -> FilePath
63 oneSlash (x:xs) | isWindows = x : f xs
64 oneSlash xs = f xs
66 f (x:y:xs) | isPathSeparator x, isPathSeparator y = f (x:xs)
67 f (x:xs) = x : f xs
68 f [] = []
71fromNormalizedFilePath :: NormalizedFilePath -> FilePath
72fromNormalizedFilePath (NormalizedFilePath fp) = fp
74-- | We use an empty string as a filepath when we don’t have a file.
75-- However, haskell-lsp doesn’t support that in uriToFilePath and given
76-- that it is not a valid filepath it does not make sense to upstream a fix.
77-- So we have our own wrapper here that supports empty filepaths.
78uriToFilePath' :: Uri -> Maybe FilePath
79uriToFilePath' uri
80 | uri == filePathToUri "" = Just ""
81 | otherwise = LSP.uriToFilePath uri
83filePathToUri' :: NormalizedFilePath -> NormalizedUri
84filePathToUri' = toNormalizedUri . filePathToUri . fromNormalizedFilePath
87fromUri :: LSP.NormalizedUri -> NormalizedFilePath
88fromUri = toNormalizedFilePath . fromMaybe noFilePath . uriToFilePath' . fromNormalizedUri
91noFilePath :: FilePath
92noFilePath = "<unknown>"
94-- A dummy range to use when range is unknown
95noRange :: Range
96noRange = Range (Position 0 0) (Position 100000 0)
99showPosition :: Position -> String
100showPosition Position{..} = show (_line + 1) ++ ":" ++ show (_character + 1)