1
1
{-# LANGUAGE RecordWildCards #-}
2
2
3
- module Unison.LSP.FileAnalysis where
3
+ module Unison.LSP.FileAnalysis
4
+ ( checkFileByUri ,
5
+ checkFileContents ,
6
+ getFileAnalysis ,
7
+ ppedForFile ,
8
+ getFileSummary ,
9
+ ppedForFileHelper ,
10
+ fileAnalysisWorker ,
11
+ getFileDefLocations ,
12
+ getFileNames ,
13
+ )
14
+ where
4
15
5
16
import Control.Lens
6
17
import Control.Monad.Reader
@@ -76,14 +87,20 @@ import Unison.Var qualified as Var
76
87
import UnliftIO.STM
77
88
import Witherable
78
89
79
- -- | Lex, parse, and typecheck a file.
80
- checkFile :: (HasUri d Uri ) => d -> Lsp (Maybe FileAnalysis )
81
- checkFile doc = runMaybeT do
82
- pp <- lift getCurrentProjectPath
90
+ -- | Lex, parse, and typecheck a file using a VFS URI
91
+ checkFileByUri :: (HasUri d Uri , Lspish m ) => d -> m (Maybe FileAnalysis )
92
+ checkFileByUri doc = runMaybeT do
83
93
let fileUri = doc ^. uri
84
94
(fileVersion, contents) <- VFS. getFileContents fileUri
95
+ let sourceName = getUri $ fileUri
96
+ checkFileContents fileUri sourceName fileVersion contents
97
+
98
+ -- | Lex, parse, and typecheck a file.
99
+ -- This is split off for easier testing without needing to mock the VFS.
100
+ checkFileContents :: (Lspish m ) => Uri -> Text -> FileVersion -> Text -> MaybeT m FileAnalysis
101
+ checkFileContents fileUri sourceName fileVersion contents = do
102
+ pp <- lift getCurrentProjectPath
85
103
parseNames <- lift getCurrentNames
86
- let sourceName = getUri $ doc ^. uri
87
104
let lexedSource@ (srcText, tokens) = (contents, L. lexer (Text. unpack sourceName) (Text. unpack contents))
88
105
let ambientAbilities = []
89
106
cb <- asks codebase
@@ -131,8 +148,8 @@ checkFile doc = runMaybeT do
131
148
_ -> mempty
132
149
pure (localBindings, typecheckingNotes, Just parsedFile, maybeTypecheckedFile)
133
150
134
- filePPED <- lift $ ppedForFileHelper parsedFile typecheckedFile
135
- (errDiagnostics, codeActions) <- lift $ analyseFile fileUri srcText filePPED notes
151
+ filePPED <- ppedForFileHelper parsedFile typecheckedFile
152
+ (errDiagnostics, codeActions) <- analyseFile fileUri srcText filePPED notes
136
153
let codeActionRanges =
137
154
codeActions
138
155
& foldMap (\ (RangedCodeAction {_codeActionRanges, _codeAction}) -> (,_codeAction) <$> _codeActionRanges)
@@ -143,7 +160,7 @@ checkFile doc = runMaybeT do
143
160
let tokenMap = getTokenMap tokens
144
161
conflictWarningDiagnostics <-
145
162
fold <$> for fileSummary \ fs ->
146
- lift $ computeConflictWarningDiagnostics fileUri fs
163
+ computeConflictWarningDiagnostics fileUri fs
147
164
let diagnosticRanges =
148
165
(errDiagnostics <> conflictWarningDiagnostics <> unusedBindingDiagnostics)
149
166
& fmap (\ d -> (d ^. range, d))
@@ -183,7 +200,7 @@ fileAnalysisWorker = forever do
183
200
pure dirty
184
201
freshlyCheckedFiles <-
185
202
Map. fromList <$> forMaybe (toList dirtyFileIDs) \ docUri -> runMaybeT do
186
- fileInfo <- MaybeT (checkFile $ TextDocumentIdentifier docUri)
203
+ fileInfo <- MaybeT (checkFileByUri $ TextDocumentIdentifier docUri)
187
204
pure (docUri, fileInfo)
188
205
Debug. debugM Debug. LSP " Freshly Typechecked " (Map. toList freshlyCheckedFiles)
189
206
-- Overwrite any files we successfully checked
@@ -198,15 +215,15 @@ fileAnalysisWorker = forever do
198
215
for freshlyCheckedFiles \ (FileAnalysis {fileUri, fileVersion, diagnostics}) -> do
199
216
reportDiagnostics fileUri (Just fileVersion) $ fold diagnostics
200
217
201
- analyseFile :: (Foldable f ) => Uri -> Text -> PPED. PrettyPrintEnvDecl -> f (Note Symbol Ann ) -> Lsp ([Diagnostic ], [RangedCodeAction ])
218
+ analyseFile :: (Lspish m ) => ( Foldable f ) => Uri -> Text -> PPED. PrettyPrintEnvDecl -> f (Note Symbol Ann ) -> m ([Diagnostic ], [RangedCodeAction ])
202
219
analyseFile fileUri srcText pped notes = do
203
220
let ppe = PPED. suffixifiedPPE pped
204
221
(noteDiags, noteActions) <- analyseNotes fileUri ppe (Text. unpack srcText) notes
205
222
pure (noteDiags, noteActions)
206
223
207
224
-- | Returns diagnostics which show a warning diagnostic when editing a term that's conflicted in the
208
225
-- codebase.
209
- computeConflictWarningDiagnostics :: Uri -> FileSummary -> Lsp [Diagnostic ]
226
+ computeConflictWarningDiagnostics :: ( Lspish m ) => Uri -> FileSummary -> m [Diagnostic ]
210
227
computeConflictWarningDiagnostics fileUri fileSummary@ FileSummary {fileNames} = do
211
228
let defLocations = fileDefLocations fileSummary
212
229
conflictedNames <- Names. conflicts <$> getCurrentNames
@@ -249,11 +266,11 @@ getTokenMap tokens =
249
266
)
250
267
& fold
251
268
252
- analyseNotes :: ( Foldable f ) => Uri -> PrettyPrintEnv -> String -> f (Note Symbol Ann ) -> Lsp ([Diagnostic ], [RangedCodeAction ])
269
+ analyseNotes :: forall m f . ( Lspish m , Foldable f ) => Uri -> PrettyPrintEnv -> String -> f (Note Symbol Ann ) -> m ([Diagnostic ], [RangedCodeAction ])
253
270
analyseNotes fileUri ppe src notes = do
254
271
foldMapM go notes
255
272
where
256
- go :: Note Symbol Ann -> Lsp ([Diagnostic ], [RangedCodeAction ])
273
+ go :: Note Symbol Ann -> m ([Diagnostic ], [RangedCodeAction ])
257
274
go note = case note of
258
275
Result. TypeError errNote@ (Context. ErrorNote {cause}) -> do
259
276
let typeErr = TypeError. typeErrorFromNote errNote
@@ -421,7 +438,7 @@ toRangeMap :: (Foldable f) => f (Range, a) -> IntervalMap Position [a]
421
438
toRangeMap vs =
422
439
IM. fromListWith (<>) (toList vs <&> \ (r, a) -> (rangeToInterval r, [a]))
423
440
424
- getFileAnalysis :: Uri -> MaybeT Lsp FileAnalysis
441
+ getFileAnalysis :: ( Lspish m ) => Uri -> MaybeT m FileAnalysis
425
442
getFileAnalysis uri = do
426
443
checkedFilesV <- asks checkedFilesVar
427
444
-- Try to get the file analysis, if there's a var, then read it, waiting if necessary
@@ -456,20 +473,20 @@ getFileNames fileUri = do
456
473
FileAnalysis {typecheckedFile = tf, parsedFile = pf} <- getFileAnalysis fileUri
457
474
hoistMaybe (fmap UF. typecheckedToNames tf <|> fmap UF. toNames pf)
458
475
459
- getFileSummary :: Uri -> MaybeT Lsp FileSummary
476
+ getFileSummary :: ( Lspish m ) => Uri -> MaybeT m FileSummary
460
477
getFileSummary uri = do
461
478
FileAnalysis {fileSummary} <- getFileAnalysis uri
462
479
MaybeT . pure $ fileSummary
463
480
464
481
-- TODO memoize per file
465
- ppedForFile :: Uri -> Lsp PPED. PrettyPrintEnvDecl
482
+ ppedForFile :: ( Lspish m ) => Uri -> m PPED. PrettyPrintEnvDecl
466
483
ppedForFile fileUri = do
467
484
runMaybeT (getFileAnalysis fileUri) >>= \ case
468
485
Just (FileAnalysis {typecheckedFile = tf, parsedFile = uf}) ->
469
486
ppedForFileHelper uf tf
470
487
_ -> ppedForFileHelper Nothing Nothing
471
488
472
- ppedForFileHelper :: Maybe (UF. UnisonFile Symbol a ) -> Maybe (UF. TypecheckedUnisonFile Symbol a ) -> Lsp PPED. PrettyPrintEnvDecl
489
+ ppedForFileHelper :: ( Lspish m ) => Maybe (UF. UnisonFile Symbol a ) -> Maybe (UF. TypecheckedUnisonFile Symbol a ) -> m PPED. PrettyPrintEnvDecl
473
490
ppedForFileHelper uf tf = do
474
491
codebasePPED <- currentPPED
475
492
hashLen <- asks codebase >>= \ codebase -> liftIO (Codebase. runTransaction codebase Codebase. hashLength)
0 commit comments