@@ -26,27 +26,21 @@ module Language.LSP.Types.Uri
26
26
where
27
27
28
28
import Control.DeepSeq
29
- import qualified Data.Aeson as A
30
- import Data.Binary (Binary , Get , get , put )
31
- import Data.ByteString.Short (ShortByteString )
32
- import qualified Data.ByteString.Short as BS
29
+ import qualified Data.Aeson as A
30
+ import Data.Binary (Binary , Get , get , put )
33
31
import Data.Hashable
34
- import Data.List (stripPrefix )
35
- import Data.String (IsString (fromString ))
36
- import Data.Text (Text )
37
- import qualified Data.Text as T
38
- import qualified Data.Text.Encoding as T
39
- import Data.Text.Encoding.Error (UnicodeException )
32
+ import Data.List (stripPrefix )
33
+ import Data.String (IsString (fromString ))
34
+ import Data.Text (Text )
35
+ import qualified Data.Text as T
40
36
import GHC.Generics
41
- import GHC.Stack (HasCallStack )
42
- import Network.URI hiding (authority )
43
- import Safe (tailMay )
44
- import qualified System.FilePath as FP
45
- import qualified System.FilePath.Posix as FPP
46
- import qualified System.FilePath.Windows as FPW
37
+ import Network.URI hiding (authority )
38
+ import Safe (tailMay )
39
+ import qualified System.FilePath as FP
40
+ import qualified System.FilePath.Posix as FPP
41
+ import qualified System.FilePath.Windows as FPW
47
42
import qualified System.Info
48
43
49
-
50
44
newtype Uri = Uri { getUri :: Text }
51
45
deriving (Eq ,Ord ,Read ,Show ,Generic ,A.FromJSON ,A.ToJSON ,Hashable ,A.ToJSONKey ,A.FromJSONKey )
52
46
@@ -164,32 +158,39 @@ platformAdjustToUriPath systemOS srcPath
164
158
FPP. addTrailingPathSeparator (init drv)
165
159
| otherwise = drv
166
160
167
- -- | A file path that is already normalized. It is stored as an UTF-8 encoded 'ShortByteString'
168
- --
169
- -- The 'NormalizedUri' is cached to avoided
170
- -- repeated normalisation when we need to compute them (which is a lot).
171
- --
172
- -- This is one of the most performance critical parts of ghcide, do not
173
- -- modify it without profiling.
174
- data NormalizedFilePath = NormalizedFilePath ! NormalizedUri {- # UNPACK #-} !ShortByteString
161
+ {-| A file path that is already normalized.
162
+
163
+ The 'NormalizedUri' is cached to avoided
164
+ repeated normalisation when we need to compute them (which is a lot).
165
+
166
+ This is one of the most performance critical parts of HLS, do not
167
+ modify it without profiling.
168
+
169
+ == Adoption Plan of OsPath
170
+
171
+ Currently we store 'Text'. We may change it to OsPath in the future if
172
+ the following steps are executed.
173
+
174
+ 1. In the client codebase, use 'osPathToNormalizedFilePath' and 'normalizedFilePathToOsPath' instead of 'fromNormalizedFilePath'
175
+ and 'toNormalizedFilePath'. For HLS, we could wait until GHC 9.6 becomes the oldest
176
+ GHC we support, then change 'FilePath' to OsPath everywhere in the codebase.
177
+ 2. Deprecate and remove 'fromNormalizedFilePath' and 'toNormalizedFilePath'.
178
+ 3. Change 'Text' to OsPath and benchmark it to make sure performance doesn't go down. Don't forget to check Windows,
179
+ as OsPath on Windows uses UTF-16, which may consume more memory.
180
+
181
+ See [#453](https://github.com/haskell/lsp/pull/453) and [#446](https://github.com/haskell/lsp/pull/446)
182
+ for more discussions on this topic.
183
+ -}
184
+ data NormalizedFilePath = NormalizedFilePath ! NormalizedUri {- # UNPACK #-} !Text
175
185
deriving (Generic , Eq , Ord )
176
186
177
187
instance NFData NormalizedFilePath
178
188
179
189
instance Binary NormalizedFilePath where
180
190
put (NormalizedFilePath _ fp) = put fp
181
191
get = do
182
- v <- Data.Binary. get :: Get ShortByteString
183
- case decodeFilePath v of
184
- Left e -> fail (show e)
185
- Right v' ->
186
- return (NormalizedFilePath (internalNormalizedFilePathToUri v') v)
187
-
188
- encodeFilePath :: String -> ShortByteString
189
- encodeFilePath = BS. toShort . T. encodeUtf8 . T. pack
190
-
191
- decodeFilePath :: ShortByteString -> Either UnicodeException String
192
- decodeFilePath = fmap T. unpack . T. decodeUtf8' . BS. fromShort
192
+ v <- Data.Binary. get :: Get Text
193
+ return (NormalizedFilePath (internalNormalizedFilePathToUri (T. unpack v)) v)
193
194
194
195
-- | Internal helper that takes a file path that is assumed to
195
196
-- already be normalized to a URI. It is up to the caller
@@ -213,24 +214,20 @@ instance IsString NormalizedFilePath where
213
214
fromString = toNormalizedFilePath
214
215
215
216
toNormalizedFilePath :: FilePath -> NormalizedFilePath
216
- toNormalizedFilePath fp = NormalizedFilePath nuri . encodeFilePath $ nfp
217
+ toNormalizedFilePath fp = NormalizedFilePath nuri . T. pack $ nfp
217
218
where
218
219
nfp = FP. normalise fp
219
220
nuri = internalNormalizedFilePathToUri nfp
220
221
221
222
-- | Extracts 'FilePath' from 'NormalizedFilePath'.
222
- -- The function is total. The 'HasCallStack' constraint is added for debugging purpose only.
223
- fromNormalizedFilePath :: HasCallStack => NormalizedFilePath -> FilePath
224
- fromNormalizedFilePath (NormalizedFilePath _ fp) =
225
- case decodeFilePath fp of
226
- Left e -> error $ show e
227
- Right x -> x
223
+ fromNormalizedFilePath :: NormalizedFilePath -> FilePath
224
+ fromNormalizedFilePath (NormalizedFilePath _ fp) = T. unpack fp
228
225
229
226
normalizedFilePathToUri :: NormalizedFilePath -> NormalizedUri
230
227
normalizedFilePathToUri (NormalizedFilePath uri _) = uri
231
228
232
229
uriToNormalizedFilePath :: NormalizedUri -> Maybe NormalizedFilePath
233
- uriToNormalizedFilePath nuri = fmap (NormalizedFilePath nuri . encodeFilePath ) mbFilePath
230
+ uriToNormalizedFilePath nuri = fmap (NormalizedFilePath nuri . T. pack ) mbFilePath
234
231
where mbFilePath = platformAwareUriToFilePath System.Info. os (fromNormalizedUri nuri)
235
232
236
233
emptyNormalizedUri :: NormalizedUri
0 commit comments