@@ -34,20 +34,24 @@ import qualified Text.Fuzzy.Parallel as Fuzzy
34
34
data Log
35
35
= LogFilePathCompleterIOError FilePath IOError
36
36
| LogFileSplitError Position
37
+ | LogUnknownKeyWordInContextError KeyWordName
38
+ | LogUnknownStanzaNameInContextError StanzaName
37
39
deriving (Show )
38
40
39
41
instance Pretty Log where
40
42
pretty = \ case
41
43
LogFilePathCompleterIOError fp ioErr ->
42
44
" Filepath:" <+> viaShow fp <+> viaShow ioErr
43
- LogFileSplitError pos -> " Position: " <+> viaShow pos
44
-
45
-
45
+ LogFileSplitError pos -> " Position:" <+> viaShow pos
46
+ LogUnknownKeyWordInContextError kw ->
47
+ " Lookup failed for:" <+> viaShow kw
48
+ LogUnknownStanzaNameInContextError sn ->
49
+ " Lookup failed for:" <+> viaShow sn
46
50
47
51
{- | Takes information needed to build possible completion items
48
52
and returns the list of possible completion items
49
53
-}
50
- type Completer = Recorder (WithPriority Log ) -> CabalCompletionContext -> IO [CabalCompletionItem ]
54
+ type Completer = Recorder (WithPriority Log ) -> CabalPrefixInfo -> IO [CabalCompletionItem ]
51
55
52
56
-- | Contains information needed for a completion action
53
57
data CabalCompletionItem = CabalCompletionItem
@@ -81,11 +85,11 @@ data StanzaContext
81
85
-}
82
86
data KeyWordContext
83
87
= -- | Key word context, where a keyword
84
- -- occurs right before the current position,
85
- -- with no value associated to it
88
+ -- occurs right before the current word
89
+ -- to be completed
86
90
KeyWord KeyWordName
87
91
| -- | Keyword context where no keyword occurs
88
- -- right before the current position
92
+ -- right before the current word to be completed
89
93
None
90
94
deriving (Eq , Show , Read )
91
95
@@ -113,7 +117,7 @@ type StanzaName = T.Text
113
117
necessary to complete filepaths and other values
114
118
in a cabal file.
115
119
-}
116
- data CabalCompletionContext = CabalCompletionContext
120
+ data CabalPrefixInfo = CabalPrefixInfo
117
121
{ completionPrefix :: T. Text
118
122
-- ^ text prefix to complete
119
123
, completionSuffix :: Maybe T. Text
@@ -123,7 +127,7 @@ data CabalCompletionContext = CabalCompletionContext
123
127
-- ^ the current position of the cursor in the file
124
128
, completionRange :: Range
125
129
-- ^ range where completion is to be inserted
126
- , completionCabalFileDir :: FilePath
130
+ , completionWorkingDir :: FilePath
127
131
-- ^ filepath of the handled cabal file
128
132
}
129
133
deriving (Eq , Show )
@@ -138,43 +142,46 @@ data CabalCompletionContext = CabalCompletionContext
138
142
contextToCompleter :: Context -> Completer
139
143
-- if we are in the top level of the cabal file and not in a keyword context,
140
144
-- we can write any top level keywords or a stanza declaration
141
- contextToCompleter (TopLevel , None ) =
145
+ contextToCompleter (TopLevel , None ) =
142
146
constantCompleter $
143
147
Map. keys (cabalVersionKeyword <> cabalKeywords) ++ Map. keys stanzaKeywordMap
144
148
-- if we are in a keyword context in the top level,
145
149
-- we look up that keyword in the top level context and can complete its possible values
146
150
contextToCompleter (TopLevel , KeyWord kw) =
147
151
case Map. lookup kw (cabalVersionKeyword <> cabalKeywords) of
148
- Nothing -> noopCompleter
152
+ Nothing -> \ recorder b -> do
153
+ logWith recorder Warning $ LogUnknownKeyWordInContextError kw
154
+ noopCompleter recorder b
149
155
Just l -> l
150
156
-- if we are in a stanza and not in a keyword context,
151
157
-- we can write any of the stanza's keywords or a stanza declaration
152
- contextToCompleter (Stanza s, None ) =
158
+ contextToCompleter (Stanza s, None ) =
153
159
case Map. lookup s stanzaKeywordMap of
154
- Nothing -> noopCompleter
160
+ Nothing -> \ recorder b -> do
161
+ logWith recorder Warning $ LogUnknownStanzaNameInContextError s
162
+ noopCompleter recorder b
155
163
Just l -> constantCompleter $ Map. keys l ++ Map. keys stanzaKeywordMap
156
164
-- if we are in a stanza's keyword's context we can complete possible values of that keyword
157
- contextToCompleter (Stanza s, KeyWord kw) =
165
+ contextToCompleter (Stanza s, KeyWord kw) =
158
166
case Map. lookup s stanzaKeywordMap of
159
- Nothing -> noopCompleter
167
+ Nothing -> \ recorder b -> do
168
+ logWith recorder Warning $ LogUnknownStanzaNameInContextError s
169
+ noopCompleter recorder b
160
170
Just m -> case Map. lookup kw m of
161
- Nothing -> noopCompleter
171
+ Nothing -> \ recorder b -> do
172
+ logWith recorder Warning $ LogUnknownKeyWordInContextError kw
173
+ noopCompleter recorder b
162
174
Just l -> l
163
175
164
- {- | Takes information about the current cursor position,
165
- the handled cabal file and a set of possible keywords
166
- and creates completion suggestions that fit the current input
167
- from the given list
168
- -}
169
- mkCompletionItems :: [CabalCompletionItem ] -> [LSP. CompletionItem ]
170
- mkCompletionItems l = map buildCompletion l
171
176
172
- {- | Takes a position and a list of lines (representing a file)
173
- and returns the context of the current position
174
- can return Nothing if an error occurs
177
+
178
+ {- | Takes prefix info about the previously written text
179
+ and a rope (representing a file), returns the corresponding context.
180
+
181
+ Can return Nothing if an error occurs.
175
182
TODO: first line can only have cabal-version: keyword
176
183
-}
177
- getContext :: MonadIO m => Recorder (WithPriority Log ) -> CabalCompletionContext -> Rope -> MaybeT m Context
184
+ getContext :: MonadIO m => Recorder (WithPriority Log ) -> CabalPrefixInfo -> Rope -> MaybeT m Context
178
185
getContext recorder ctx ls =
179
186
case prevLinesM of
180
187
Just prevLines -> do
@@ -206,11 +213,12 @@ getContext recorder ctx ls =
206
213
-- Helper Functions
207
214
-- ----------------------------------------------------------------
208
215
209
- {- | Takes a position, a list of lines (representing a file)
210
- and a map of keywords and returns a keyword context if the
211
- previously written keyword matches one in the map
216
+ {- | Takes prefix info about the previously written text,
217
+ a list of lines (representing a file) and a map of
218
+ keywords and returns a keyword context if the
219
+ previously written keyword matches one in the map.
212
220
-}
213
- getKeyWordContext :: CabalCompletionContext -> [T. Text ] -> Map KeyWordName a -> Maybe KeyWordContext
221
+ getKeyWordContext :: CabalPrefixInfo -> [T. Text ] -> Map KeyWordName a -> Maybe KeyWordContext
214
222
getKeyWordContext ctx ls keywords = do
215
223
case lastNonEmptyLineM of
216
224
Nothing -> Just None
@@ -251,21 +259,21 @@ currentLevel (cur : xs)
251
259
stanza = List. find (`T.isPrefixOf` cur) (Map. keys stanzaKeywordMap)
252
260
253
261
{- | Returns a CabalCompletionItem with the given starting position
254
- and text to be inserted,
255
- where the displayed text is the same as the inserted text.
262
+ and text to be inserted, where the displayed text is the same as the
263
+ inserted text.
256
264
-}
257
265
makeSimpleCabalCompletionItem :: Range -> T. Text -> CabalCompletionItem
258
266
makeSimpleCabalCompletionItem r txt = CabalCompletionItem txt Nothing r
259
267
260
268
{- | Returns a CabalCompletionItem with the given starting position,
261
- text to be inserted and text to be displayed in the completion suggestion
269
+ text to be inserted and text to be displayed in the completion suggestion.
262
270
-}
263
- makeCabalCompletionItem :: Range -> T. Text -> T. Text -> CabalCompletionItem
264
- makeCabalCompletionItem r insertTxt displayTxt =
271
+ mkCabalCompletionItem :: Range -> T. Text -> T. Text -> CabalCompletionItem
272
+ mkCabalCompletionItem r insertTxt displayTxt =
265
273
CabalCompletionItem insertTxt (Just displayTxt) r
266
274
267
275
{- | Get all lines before the given cursor position in the given file
268
- and reverse their order to traverse backwards starting from the current position
276
+ and reverse their order to traverse backwards starting from the given position.
269
277
-}
270
278
splitAtPosition :: Position -> Rope -> Maybe [T. Text ]
271
279
splitAtPosition pos ls = do
@@ -280,7 +288,7 @@ splitAtPosition pos ls = do
280
288
}
281
289
282
290
-- | Takes a line of text and removes the last partially
283
- -- written text to be completed
291
+ -- written word to be completed
284
292
stripPartiallyWritten :: T. Text -> T. Text
285
293
stripPartiallyWritten = T. dropWhileEnd (\ y -> (y /= ' ' ) && (y /= ' :' ))
286
294
@@ -297,21 +305,22 @@ stripPartiallyWritten = T.dropWhileEnd (\y -> (y /= ' ') && (y /= ':'))
297
305
be used for file path completions to be written to the cabal file.
298
306
-}
299
307
308
+
300
309
{- | Takes information about the current file's file path,
301
310
the current cursor position in the file
302
311
and its contents; and builds a CabalCompletionItem
303
312
with the prefix up to that cursor position,
304
313
checks whether a suffix needs to be completed,
305
314
and calculates the range in the document in which to complete.
306
315
-}
307
- getCabalCompletionContext :: FilePath -> VFS. PosPrefixInfo -> CabalCompletionContext
308
- getCabalCompletionContext dir prefixInfo =
309
- CabalCompletionContext
316
+ getCabalPrefixInfo :: FilePath -> VFS. PosPrefixInfo -> CabalPrefixInfo
317
+ getCabalPrefixInfo dir prefixInfo =
318
+ CabalPrefixInfo
310
319
{ completionPrefix = filepathPrefix
311
320
, completionSuffix = Just suffix
312
321
, completionCursorPosition = VFS. cursorPos prefixInfo
313
322
, completionRange = Range completionStart completionEnd
314
- , completionCabalFileDir = dir
323
+ , completionWorkingDir = dir
315
324
}
316
325
where
317
326
completionEnd = VFS. cursorPos prefixInfo
@@ -334,8 +343,8 @@ getCabalCompletionContext dir prefixInfo =
334
343
-- otherwise we parse until a space occurs
335
344
stopConditionChars = apostropheOrSpaceSeparator : [' ,' , ' :' ]
336
345
337
- buildCompletion :: CabalCompletionItem -> LSP. CompletionItem
338
- buildCompletion completionItem =
346
+ mkCompletionItem :: CabalCompletionItem -> LSP. CompletionItem
347
+ mkCompletionItem completionItem =
339
348
LSP. CompletionItem
340
349
{ Compls. _label = toDisplay
341
350
, Compls. _labelDetails = Nothing
@@ -395,7 +404,7 @@ filePathCompleter recorder ctx = do
395
404
( \ compl' -> do
396
405
let compl = Fuzzy. original compl'
397
406
fullFilePath <- makeFullFilePath suffix compl complInfo
398
- pure $ makeCabalCompletionItem (completionRange ctx) fullFilePath fullFilePath
407
+ pure $ mkCabalCompletionItem (completionRange ctx) fullFilePath fullFilePath
399
408
)
400
409
where
401
410
-- Takes a suffix, a completed path and a pathCompletionInfo and
@@ -422,7 +431,7 @@ directoryCompleter recorder ctx = do
422
431
( \ compl' -> do
423
432
let compl = Fuzzy. original compl'
424
433
fullDirPath <- makeFullDirPath compl complInfo
425
- pure $ makeCabalCompletionItem (completionRange ctx) fullDirPath fullDirPath
434
+ pure $ mkCabalCompletionItem (completionRange ctx) fullDirPath fullDirPath
426
435
)
427
436
where
428
437
-- Takes a directory and PathCompletionInfo and
@@ -460,17 +469,17 @@ listDirectoryCompletions recorder complInfo = do
460
469
filepaths <- listFileCompletions recorder complInfo
461
470
filterM (doesDirectoryExist . mkDirFromCWD complInfo) filepaths
462
471
463
- pathCompletionInfoFromCompletionContext :: CabalCompletionContext -> PathCompletionInfo
472
+ pathCompletionInfoFromCompletionContext :: CabalPrefixInfo -> PathCompletionInfo
464
473
pathCompletionInfoFromCompletionContext ctx =
465
474
PathCompletionInfo
466
475
{ partialFileName = dirNamePrefix
467
476
, partialFileDir = Posix. addTrailingPathSeparator $ Posix. takeDirectory prefix
468
- , cabalFileDir = dir
477
+ , workingDir = dir
469
478
}
470
479
where
471
480
prefix = T. unpack $ completionPrefix ctx
472
481
dirNamePrefix = T. pack $ Posix. takeFileName prefix
473
- dir = Posix. takeDirectory $ completionCabalFileDir ctx
482
+ dir = Posix. takeDirectory $ completionWorkingDir ctx
474
483
475
484
{- | Returns the directory, the currently handled cabal file is in.
476
485
@@ -480,9 +489,11 @@ pathCompletionInfoFromCompletionContext ctx =
480
489
mkCompletionDirectory :: PathCompletionInfo -> FilePath
481
490
mkCompletionDirectory complInfo =
482
491
FP. addTrailingPathSeparator $
483
- cabalFileDir complInfo FP. </> (FP. normalise $ partialFileDir complInfo)
492
+ workingDir complInfo FP. </> (FP. normalise $ partialFileDir complInfo)
484
493
485
- {- | Returns the complete filepath for the given filepath.
494
+ {- | Returns the complete filepath for the given filepath,
495
+ by combining the current working directory of the cabal file
496
+ with the given partly written file path.
486
497
487
498
Since this is used for completions we use posix separators here.
488
499
See Note [Using correct file path separators].
@@ -512,7 +523,7 @@ data PathCompletionInfo = PathCompletionInfo
512
523
-- ^ partly written start of next part of path
513
524
, partialFileDir :: FilePath
514
525
-- ^ written part of path
515
- , cabalFileDir :: FilePath
526
+ , workingDir :: FilePath
516
527
-- ^ current working directory of the handled file
517
528
}
518
529
deriving (Eq , Show , Read )
0 commit comments