@@ -20,26 +20,20 @@ import qualified Data.ByteString as BS
2020import Data.Hashable
2121import Data.HashMap.Strict (HashMap )
2222import qualified Data.HashMap.Strict as HashMap
23- import qualified Data.List as List
24- import qualified Data.List.Extra as Extra
2523import qualified Data.List.NonEmpty as NE
26- import Data.Map (Map )
27- import qualified Data.Map as Map
28- import qualified Data.Text as T
2924import qualified Data.Text.Encoding as Encoding
3025import qualified Data.Text.Utf16.Rope as Rope
3126import Data.Typeable
32- import Debug.Trace
3327import Development.IDE as D
3428import Development.IDE.Core.Shake (restartShakeSession )
3529import qualified Development.IDE.Core.Shake as Shake
3630import Development.IDE.Graph (alwaysRerun )
3731import Distribution.Compat.Lens ((^.) )
3832import GHC.Generics
33+ import Ide.Plugin.Cabal.Completions
3934import qualified Ide.Plugin.Cabal.Diagnostics as Diagnostics
4035import qualified Ide.Plugin.Cabal.LicenseSuggest as LicenseSuggest
4136import qualified Ide.Plugin.Cabal.Parse as Parse
42- import Ide.Plugin.Config (Config )
4337import Ide.Types
4438import qualified Language.LSP.Server as LSP
4539import Language.LSP.Types
@@ -48,7 +42,6 @@ import qualified Language.LSP.Types as LSP
4842import qualified Language.LSP.Types.Lens as JL
4943import Language.LSP.VFS (VirtualFile )
5044import qualified Language.LSP.VFS as VFS
51- import qualified Text.Fuzzy.Parallel as Fuzzy
5245
5346
5447data Log
@@ -288,7 +281,7 @@ completion _ide _ complParams = do
288281 result :: Maybe VFS. PosPrefixInfo -> VirtualFile -> J. List CompletionItem
289282 result Nothing _ = J. List []
290283 result (Just pfix) cnts
291- | pos ^. JL. line == 0 = case traceShowId $ context of
284+ | pos ^. JL. line == 0 = case context of
292285 Just (_, kw)
293286 | KeyWord _ <- kw -> J. List $ map buildCompletion $ snd cabalVersionKeyword
294287 _ -> J. List [buildCompletion (fst cabalVersionKeyword)]
@@ -297,272 +290,3 @@ completion _ide _ complParams = do
297290 where
298291 pos = VFS. cursorPos pfix
299292 context = getContext pos (Rope. lines $ cnts ^. VFS. file_text)
300-
301- -- | Takes a context and returns all possible completions within that context
302- getCompletionsForContext :: Context -> [T. Text ]
303- -- if we are in the top level of the cabal file and not in a keyword context,
304- -- we can write any toplevel keywords or a stanza declaration
305- getCompletionsForContext (TopLevel , None ) =
306- Map. keys cabalKeywords ++ Map. keys stanzaKeywordMap
307- -- if we are in a keyword context in the toplevel,
308- -- we look up that keyword in the toplevel context and can complete its possible values
309- getCompletionsForContext (TopLevel , KeyWord kw) =
310- case Map. lookup kw cabalKeywords of
311- Nothing -> []
312- Just l -> l
313- -- if we are in a stanza and not in a keyword context,
314- -- we can write any of the stanza's keywords or a stanza declaration
315- getCompletionsForContext (Stanza s, None ) =
316- case Map. lookup s stanzaKeywordMap of
317- Nothing -> []
318- Just l -> Map. keys l ++ Map. keys stanzaKeywordMap
319- -- if we are in a stanza's keyword's context we can complete possible values of that keyword
320- getCompletionsForContext (Stanza s, KeyWord kw) =
321- case Map. lookup s stanzaKeywordMap of
322- Nothing -> []
323- Just m -> case Map. lookup kw m of
324- Nothing -> []
325- Just l -> l
326-
327- -- | Takes a position and a list of lines (representing a file)
328- -- and returns the context of the current position
329- -- can return Nothing if an error occurs
330- getContext :: Position -> [T. Text ] -> Maybe Context
331- getContext pos ls =
332- case lvlContext of
333- TopLevel -> do
334- kwContext <- getKeyWordContext pos ls (uncurry Map. insert cabalVersionKeyword cabalKeywords)
335- pure (TopLevel , kwContext)
336- Stanza s ->
337- case Map. lookup (traceShowId s) stanzaKeywordMap of
338- Nothing -> do
339- pure (Stanza s, None )
340- Just m -> do
341- kwContext <- getKeyWordContext pos ls m
342- pure (Stanza s, kwContext)
343- where
344- lvlContext = findCurrentLevel (getPreviousLines pos ls)
345-
346- -- | Takes a position, a list of lines (representing a file) and a map of keywords as keys
347- -- and returns a keyword context if there is a keyword from the map before the current position
348- -- in the given line list
349- getKeyWordContext :: Position -> [T. Text ] -> Map T. Text a -> Maybe KeyWordContext
350- getKeyWordContext pos ls keywords = do
351- curLine <- fmap T. stripStart currentLine
352- case List. find (`T.isPrefixOf` curLine) (Map. keys keywords) of
353- Nothing -> Just None
354- Just kw -> Just $ KeyWord kw
355- where
356- currentLine = ls Extra. !? (fromIntegral $ pos ^. JL. line)
357-
358- -- | Takes info about the current cursor position and a set of possible keywords
359- -- and creates completion suggestions that fit the current input from the given list
360- makeCompletionItems :: VFS. PosPrefixInfo -> [T. Text ] -> [CompletionItem ]
361- makeCompletionItems pfix l =
362- map
363- (buildCompletion . Fuzzy. original)
364- (Fuzzy. simpleFilter 1000 10 (VFS. prefixText pfix) l)
365-
366- -- | Parse the given set of lines (starting before current cursor position
367- -- up to the start of the file) to find the nearest stanza declaration,
368- -- if none is found we are in the top level
369- findCurrentLevel :: [T. Text ] -> LevelContext
370- findCurrentLevel [] = TopLevel
371- findCurrentLevel (cur : xs)
372- | Just s <- stanza = Stanza s
373- | otherwise = findCurrentLevel xs
374- where
375- stanza = List. find (`T.isPrefixOf` cur) (Map. keys stanzaKeywordMap)
376-
377- -- | Get all lines before the given cursor position in the given file
378- -- and reverse them since we want to traverse starting from our current position
379- getPreviousLines :: Position -> [T. Text ] -> [T. Text ]
380- getPreviousLines pos ls = reverse $ take (fromIntegral currentLine) ls
381- where
382- currentLine = pos ^. JL. line
383-
384- -- | The context a cursor can be in within a cabal file,
385- -- we can be in stanzas or the toplevel,
386- -- and additionally we can be in a context where we have already written a keyword
387- -- but no value for it yet
388- type Context = (LevelContext , KeyWordContext )
389-
390- data LevelContext
391- = TopLevel
392- -- ^ Top level context in a cabal file such as 'author'
393- | Stanza T. Text
394- -- ^ Nested context in a cabal file, such as 'library', which has nested keywords, specific to the stanza
395- deriving (Eq , Show )
396-
397- -- | Keyword context in cabal file
398- data KeyWordContext
399- = KeyWord T. Text
400- -- ^ We are in a line with the given keyword before our cursor
401- | None
402- -- ^ We are in a line with no keyword context
403- deriving (Eq , Show )
404-
405- -- | Keyword for cabal version required to be the top line in a cabal file
406- cabalVersionKeyword :: (T. Text ,[T. Text ])
407- cabalVersionKeyword = (" cabal-version:" , [" 2.0" , " 2.2" , " 2.4" , " 3.0" ])
408-
409-
410- -- todo: we could add file path completion for file path fields
411- -- we could add descriptions of field values and then show them when inside the field's context
412- -- | Top level keywords of a cabal file
413- cabalKeywords :: Map T. Text [T. Text ]
414- cabalKeywords =
415- Map. fromList [
416- (" name:" , [] ),
417- (" version:" , [] ),
418- (" build-type:" , [" Simple" , " Custom" ]),
419- (" license:" , [" NONE" ]),
420- (" license-file:" , [] ),
421- (" license-files:" ,[] ),
422- (" copyright:" , [] ),
423- (" author:" , [] ),
424- (" maintainer:" ,[] ),
425- (" stability:" ,[] ),
426- (" homepage:" ,[] ),
427- (" bug-reports:" ,[] ),
428- (" package-url:" ,[] ),
429- (" synopsis:" ,[] ),
430- (" description:" ,[] ),
431- (" category:" ,[] ),
432- (" tested-with:" ,[" GHC" ]),
433- (" data-files:" , [] ),
434- (" data-dir:" , [] ),
435- (" data-dir:" , [] ),
436- (" extra-source-files:" , [] ),
437- (" extra-doc-files:" , [] ),
438- (" extra-tmp-files:" , [] )
439- ]
440-
441- -- | Map, containing all stanzas in a cabal file as keys and lists of their possible nested keywords as values
442- stanzaKeywordMap :: Map T. Text (Map T. Text [T. Text ])
443- stanzaKeywordMap =
444- Map. fromList
445- [ ( " library" ,
446- Map. fromList $
447- [ (" exposed-modules:" , [] ),
448- (" virtual-modules:" , [] ),
449- (" exposed:" , [" True" , " False" ]),
450- (" visibility:" , [" private" , " public" ]),
451- (" reexported-modules:" , [] ),
452- (" signatures:" , [] )
453- ]
454- ++ libExecTestBenchCommons
455- ),
456- ( " executable" ,
457- Map. fromList $
458- [ (" main-is:" , [] ),
459- (" scope:" , [" public" , " private" ])
460- ]
461- ++ libExecTestBenchCommons
462- ),
463- ( " test-suite" ,
464- Map. fromList $
465- [ (" type:" , [" exitcode-stdio-1.0" ]),
466- (" main-is:" , [] )
467- ]
468- ++ libExecTestBenchCommons
469- ),
470- ( " benchmark" ,
471- Map. fromList $
472- [ (" type:" , [] ),
473- (" main-is:" , [] )
474- ]
475- ++ libExecTestBenchCommons
476- ),
477- ( " foreign-library" ,
478- Map. fromList
479- [ (" type:" , [] ),
480- (" options:" , [] ),
481- (" mod-def-file:" , [] ),
482- (" lib-def-file:" , [] ),
483- (" lib-version-info:" , [] ),
484- (" lib-version-linux:" , [] )
485- ]
486- ),
487- ( " flag" ,
488- Map. fromList
489- [ (" description:" , [] ),
490- (" default:" , [" True" , " False" ]),
491- (" manual:" , [" False" , " True" ]),
492- (" lib-def-file:" , [] ),
493- (" lib-version-info:" , [] ),
494- (" lib-version-linux:" , [] )
495- ]
496- )
497- ]
498- where
499- libExecTestBenchCommons =
500- [ (" build-depends:" , [] ),
501- (" other-modules:" , [] ),
502- (" hs-source-dir:" , [" ." ]),
503- (" hs-source-dirs:" , [" ." ]),
504- (" default-extensions:" , [] ),
505- (" other-extensions:" , [] ),
506- (" default-language:" , [] ),
507- (" build-tool-depends:" , [] ),
508- (" buildable:" , [" True" , " False" ]),
509- -- todo maybe there is a list of possible ghc options somewhere
510- (" ghc-options:" , [] ),
511- (" ghc-prof-options:" , [] ),
512- (" ghc-shared-options:" , [] ),
513- (" ghcjs-options:" , [] ),
514- (" ghcjs-prof-options:" , [] ),
515- (" ghcjs-shared-options:" , [] ),
516- (" includes:" , [] ),
517- (" install-includes:" , [] ),
518- (" include-dirs:" , [] ),
519- (" c-sources:" , [] ),
520- (" cxx-sources:" , [] ),
521- (" asm-sources:" , [] ),
522- (" cmm-sources:" , [] ),
523- (" js-sources:" , [] ),
524- (" extra-libraries:" , [] ),
525- (" extra-ghci-libraries:" , [] ),
526- (" extra-bundled-libraries:" , [] ),
527- (" extra-lib-dirs:" , [] ),
528- (" cc-options:" , [] ),
529- (" cpp-options:" , [] ),
530- (" cxx-options:" , [] ),
531- (" cmm-options:" , [] ),
532- (" asm-options:" , [] ),
533- (" ld-options:" , [] ),
534- (" pkgconfig-depends:" , [] ),
535- (" frameworks:" , [] ),
536- (" extra-framework-dirs:" , [] ),
537- (" mixins:" , [] )
538- ]
539-
540- -- cabalFlagKeywords :: [(T.Text, T.Text)]
541- -- cabalFlagKeywords =
542- -- [
543- -- ("flag", "name"),
544- -- ("description:", "freeform"),
545- -- ("default:", "boolean"),
546- -- ("manual:", "boolean")
547- -- ]
548-
549- -- cabalStanzaKeywords :: [(T.Text, T.Text)]
550- -- cabalStanzaKeywords =
551- -- [
552- -- ("common", "name"),
553- -- ("import:", "token-list")
554- -- ]
555-
556- -- cabalSourceRepoKeywords :: [(T.Text, T.Text)]
557- -- cabalSourceRepoKeywords =
558- -- [
559- -- ("source-repository", ""),
560- -- ("type:", "token"),
561- -- ("location:", "URL")
562- -- ]
563-
564- buildCompletion :: T. Text -> J. CompletionItem
565- buildCompletion label =
566- J. CompletionItem label (Just J. CiKeyword ) Nothing Nothing
567- Nothing Nothing Nothing Nothing Nothing Nothing Nothing
568- Nothing Nothing Nothing Nothing Nothing Nothing
0 commit comments