@@ -18,25 +18,31 @@ module Ide.Plugin.Pragmas
18
18
import Control.Lens hiding (List )
19
19
import Control.Monad.IO.Class (MonadIO (liftIO ))
20
20
import Control.Monad.Trans.Class (lift )
21
+ import Data.Char (isAlphaNum )
21
22
import Data.List.Extra (nubOrdOn )
22
23
import qualified Data.Map as M
23
- import Data.Maybe (mapMaybe )
24
+ import Data.Maybe (fromMaybe ,
25
+ listToMaybe ,
26
+ mapMaybe )
24
27
import qualified Data.Text as T
28
+ import qualified Data.Text.Utf16.Rope.Mixed as Rope
25
29
import Development.IDE hiding (line )
26
30
import Development.IDE.Core.Compile (sourceParser ,
27
31
sourceTypecheck )
28
32
import Development.IDE.Core.PluginUtils
29
33
import Development.IDE.GHC.Compat
30
34
import Development.IDE.Plugin.Completions (ghcideCompletionsPluginPriority )
31
35
import Development.IDE.Plugin.Completions.Logic (getCompletionPrefix )
32
- import Development.IDE.Plugin.Completions.Types (PosPrefixInfo (.. ))
36
+ import Development.IDE.Plugin.Completions.Types (PosPrefixInfo (.. ),
37
+ prefixText )
33
38
import qualified Development.IDE.Spans.Pragmas as Pragmas
34
39
import Ide.Plugin.Error
35
40
import Ide.Types
36
41
import qualified Language.LSP.Protocol.Lens as L
37
42
import qualified Language.LSP.Protocol.Message as LSP
38
43
import qualified Language.LSP.Protocol.Types as LSP
39
44
import qualified Language.LSP.Server as LSP
45
+ import qualified Language.LSP.VFS as VFS
40
46
import qualified Text.Fuzzy as Fuzzy
41
47
42
48
-- ---------------------------------------------------------------------
@@ -193,30 +199,32 @@ allPragmas =
193
199
194
200
-- ---------------------------------------------------------------------
195
201
flags :: [T. Text ]
196
- flags = map ( T. pack . stripLeading ' - ' ) $ flagsForCompletion False
202
+ flags = map T. pack $ flagsForCompletion False
197
203
198
204
completion :: PluginMethodHandler IdeState 'LSP.Method_TextDocumentCompletion
199
205
completion _ide _ complParams = do
200
206
let (LSP. TextDocumentIdentifier uri) = complParams ^. L. textDocument
201
- position = complParams ^. L. position
207
+ cursorPos @ ( Position l c) = complParams ^. L. position
202
208
contents <- lift $ LSP. getVirtualFile $ toNormalizedUri uri
203
209
fmap LSP. InL $ case (contents, uriToFilePath' uri) of
204
210
(Just cnts, Just _path) ->
205
- pure $ result $ getCompletionPrefix position cnts
211
+ pure $ result $ getCompletionPrefix cursorPos cnts
206
212
where
207
213
result pfix
208
214
| " {-# language" `T.isPrefixOf` line
209
- = map buildCompletion
210
- ( Fuzzy. simpleFilter (prefixText pfix) allPragmas)
215
+ = map mkLanguagePragmaCompl $
216
+ Fuzzy. simpleFilter (prefixText pfix) allPragmas
211
217
| " {-# options_ghc" `T.isPrefixOf` line
212
- = map buildCompletion
213
- (Fuzzy. simpleFilter (prefixText pfix) flags)
218
+ = let flagPrefix = getGhcOptionPrefix cursorPos cnts
219
+ prefixLength = fromIntegral $ T. length flagPrefix
220
+ prefixRange = LSP. Range (Position l (c - prefixLength)) cursorPos
221
+ in map (mkGhcOptionCompl prefixRange) $ Fuzzy. simpleFilter flagPrefix flags
214
222
| " {-#" `T.isPrefixOf` line
215
223
= [ mkPragmaCompl (a <> suffix) b c
216
224
| (a, b, c, w) <- validPragmas, w == NewLine
217
225
]
218
226
| -- Do not suggest any pragmas any of these conditions:
219
- -- 1. Current line is a an import
227
+ -- 1. Current line is an import
220
228
-- 2. There is a module name right before the current word.
221
229
-- Something like `Text.la` shouldn't suggest adding the
222
230
-- 'LANGUAGE' pragma.
@@ -239,7 +247,7 @@ completion _ide _ complParams = do
239
247
module_ = prefixScope pfix
240
248
word = prefixText pfix
241
249
-- Not completely correct, may fail if more than one "{-#" exist
242
- -- , we can ignore it since it rarely happen .
250
+ -- , we can ignore it since it rarely happens .
243
251
prefix
244
252
| " {-# " `T.isInfixOf` line = " "
245
253
| " {-#" `T.isInfixOf` line = " "
@@ -293,19 +301,43 @@ mkPragmaCompl insertText label detail =
293
301
Nothing Nothing Nothing Nothing Nothing (Just insertText) (Just LSP. InsertTextFormat_Snippet )
294
302
Nothing Nothing Nothing Nothing Nothing Nothing Nothing
295
303
296
-
297
- stripLeading :: Char -> String -> String
298
- stripLeading _ [] = []
299
- stripLeading c (s: ss)
300
- | s == c = ss
301
- | otherwise = s: ss
302
-
303
-
304
- buildCompletion :: T. Text -> LSP. CompletionItem
305
- buildCompletion label =
304
+ getGhcOptionPrefix :: Position -> VFS. VirtualFile -> T. Text
305
+ getGhcOptionPrefix (Position l c) (VFS. VirtualFile _ _ ropetext) =
306
+ fromMaybe " " $ do
307
+ let lastMaybe = listToMaybe . reverse
308
+
309
+ -- grab the entire line the cursor is at
310
+ curLine <- listToMaybe
311
+ $ Rope. lines
312
+ $ fst $ Rope. splitAtLine 1
313
+ $ snd $ Rope. splitAtLine (fromIntegral l) ropetext
314
+ let beforePos = T. take (fromIntegral c) curLine
315
+ -- the word getting typed, after previous space and before cursor
316
+ curWord <-
317
+ if | T. null beforePos -> Just " "
318
+ | T. last beforePos == ' ' -> Just " " -- don't count abc as the curword in 'abc '
319
+ | otherwise -> lastMaybe (T. words beforePos)
320
+ pure $ T. takeWhileEnd isGhcOptionChar curWord
321
+
322
+ -- | Is this character contained in some GHC flag? Based on:
323
+ -- GHCi> nub . sort . concat $ GHC.Driver.Session.flagsForCompletion False
324
+ -- "#-.01234589=ABCDEFGHIJKLMNOPQRSTUVWX_abcdefghijklmnopqrstuvwxyz"
325
+ isGhcOptionChar :: Char -> Bool
326
+ isGhcOptionChar c = isAlphaNum c || c `elem` (" #-.=_" :: String )
327
+
328
+ mkLanguagePragmaCompl :: T. Text -> LSP. CompletionItem
329
+ mkLanguagePragmaCompl label =
306
330
LSP. CompletionItem label Nothing (Just LSP. CompletionItemKind_Keyword ) Nothing Nothing
307
331
Nothing Nothing Nothing Nothing Nothing Nothing Nothing
308
332
Nothing Nothing Nothing Nothing Nothing Nothing Nothing
309
333
334
+ mkGhcOptionCompl :: Range -> T. Text -> LSP. CompletionItem
335
+ mkGhcOptionCompl editRange completedFlag =
336
+ LSP. CompletionItem completedFlag Nothing (Just LSP. CompletionItemKind_Keyword ) Nothing Nothing
337
+ Nothing Nothing Nothing Nothing Nothing Nothing Nothing
338
+ Nothing (Just insertCompleteFlag) Nothing Nothing Nothing Nothing Nothing
339
+ where
340
+ insertCompleteFlag = LSP. InL $ LSP. TextEdit editRange completedFlag
341
+
310
342
311
343
0 commit comments