diff --git a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Completions.hs b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Completions.hs index 3d5e3871109..bb0e2c3ea84 100644 --- a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Completions.hs +++ b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Completions.hs @@ -46,7 +46,7 @@ import qualified Text.Fuzzy.Parallel as Fuzzy -- ---------------------------------------------------------------- {- | Takes information about the completion status within the file - and finds the correct completer to be applied + and finds the correct completer to be applied. -} contextToCompleter :: Context -> Completer -- if we are in the top level of the cabal file and not in a keyword context, @@ -169,6 +169,9 @@ currentLevel (cur : xs) | otherwise -> Just (t, Just $ T.strip n) Nothing -> Nothing +{- | Creates a CompletionItem with the given text as the label + where the completion item kind is keyword. +-} mkDefaultCompletionItem :: T.Text -> LSP.CompletionItem mkDefaultCompletionItem label = LSP.CompletionItem { Compls._label = label @@ -223,7 +226,7 @@ splitAtPosition pos ls = do } {- | Takes a line of text and removes the last partially -written word to be completed +written word to be completed. -} stripPartiallyWritten :: T.Text -> T.Text stripPartiallyWritten = T.dropWhileEnd (\y -> (y /= ' ') && (y /= ':')) @@ -267,6 +270,7 @@ getCabalPrefixInfo fp prefixInfo = -- otherwise we parse until a space occurs stopConditionChars = apostropheOrSpaceSeparator : [',', ':'] +-- | Calculates how many spaces the currently completed item is indented. completionIndentation :: CabalPrefixInfo -> Int completionIndentation prefInfo = fromIntegral (pos ^. JL.character) - (T.length $ completionPrefix prefInfo) where @@ -293,6 +297,7 @@ constantCompleter completions _ cData = do range = completionRange prefInfo pure $ map (mkSimpleCompletionItem range . Fuzzy.original) scored +-- | Completer to be used for the name field's value nameCompleter :: Completer nameCompleter _ cData = do let scored = Fuzzy.simpleFilter 1000 10 (completionPrefix prefInfo) [completionFileName prefInfo] @@ -300,7 +305,7 @@ nameCompleter _ cData = do range = completionRange prefInfo pure $ map (mkSimpleCompletionItem range . Fuzzy.original) scored --- maps snippet triggerwords to match on with their completers +-- | Maps snippet triggerwords with their completers snippetCompleter :: Completer snippetCompleter _ cData = do let scored = Fuzzy.simpleFilter 1000 10 (completionPrefix prefInfo) $ Map.keys snippetMap @@ -408,6 +413,9 @@ filePathCompleter recorder cData = do ) {- | Completer to be used when module paths can be completed for the field. + + Takes an extraction function which extracts the source directories + to be used by the completer. -} modulesCompleter :: (GenericPackageDescription -> [FilePath]) -> Completer modulesCompleter extractionFunction recorder cData = do @@ -425,8 +433,10 @@ modulesCompleter extractionFunction recorder cData = do extras = shakeExtras (ideState cData) prefInfo = cabalPrefixInfo cData -exposedModuleExtraction :: GenericPackageDescription -> [FilePath] -exposedModuleExtraction gpd = +{- | Extracts the source directories of the library stanza. +-} +sourceDirsExtractionLibrary :: GenericPackageDescription -> [FilePath] +sourceDirsExtractionLibrary gpd = -- we use condLibrary to get the information contained in the library stanza -- since the library in PackageDescription is not populated by us case libM of @@ -436,9 +446,11 @@ exposedModuleExtraction gpd = where libM = condLibrary gpd -otherModulesExtractionExecutable :: Maybe T.Text -> GenericPackageDescription -> [FilePath] -otherModulesExtractionExecutable Nothing _ = [] -otherModulesExtractionExecutable (Just name) gpd +{- | Extracts the source directories of the executable stanza with the given name. +-} +sourceDirsExtractionExecutable :: Maybe T.Text -> GenericPackageDescription -> [FilePath] +sourceDirsExtractionExecutable Nothing _ = [] +sourceDirsExtractionExecutable (Just name) gpd | exeName executable == (mkUnqualComponentName $ T.unpack name) = map getSymbolicPath $ hsSourceDirs $ buildInfo executable | otherwise = [] where @@ -452,9 +464,11 @@ otherModulesExtractionExecutable (Just name) gpd ) execsM -otherModulesExtractionTestSuite :: Maybe T.Text -> GenericPackageDescription -> [FilePath] -otherModulesExtractionTestSuite Nothing _ = [] -otherModulesExtractionTestSuite (Just name) gpd +{- | Extracts the source directories of the test suite stanza with the given name. +-} +sourceDirsExtractionTestSuite :: Maybe T.Text -> GenericPackageDescription -> [FilePath] +sourceDirsExtractionTestSuite Nothing _ = [] +sourceDirsExtractionTestSuite (Just name) gpd | testName testSuite == (mkUnqualComponentName $ T.unpack name) = map getSymbolicPath $ hsSourceDirs $ testBuildInfo testSuite | otherwise = [] where @@ -468,9 +482,11 @@ otherModulesExtractionTestSuite (Just name) gpd ) testSuitesM -otherModulesExtractionBenchmark :: Maybe T.Text -> GenericPackageDescription -> [FilePath] -otherModulesExtractionBenchmark Nothing _ = [] -otherModulesExtractionBenchmark (Just name) gpd +{- | Extracts the source directories of benchmark stanza with the given name. +-} +sourceDirsExtractionBenchmark :: Maybe T.Text -> GenericPackageDescription -> [FilePath] +sourceDirsExtractionBenchmark Nothing _ = [] +sourceDirsExtractionBenchmark (Just name) gpd | benchmarkName bMark == (mkUnqualComponentName $ T.unpack name) = map getSymbolicPath $ hsSourceDirs $ benchmarkBuildInfo bMark | otherwise = [] where @@ -526,7 +542,7 @@ cabalVersionKeyword = cabalKeywords :: Map KeyWordName Completer cabalKeywords = Map.fromList - [ ("name:", nameCompleter) -- TODO: should complete to filename, needs meta info + [ ("name:", nameCompleter) , ("version:", noopCompleter) , ("build-type:", constantCompleter ["Simple", "Custom", "Configure", "Make"]) , ("license:", weightedConstantCompleter licenseNames weightedLicenseNames) @@ -557,13 +573,13 @@ stanzaKeywordMap = [ ( "library" , \_ -> Map.fromList $ - [ ("exposed-modules:", modulesCompleter exposedModuleExtraction) -- identifier list + [ ("exposed-modules:", modulesCompleter sourceDirsExtractionLibrary) -- identifier list , ("virtual-modules:", noopCompleter) , ("exposed:", constantCompleter ["True", "False"]) , ("visibility:", constantCompleter ["private", "public"]) , ("reexported-modules:", noopCompleter) -- export list, i.e. "orig-okg:Name as NewName" , ("signatures:", noopCompleter) -- list of signatures - , ("other-modules:", modulesCompleter exposedModuleExtraction) + , ("other-modules:", modulesCompleter sourceDirsExtractionLibrary) ] ++ libExecTestBenchCommons ) @@ -572,7 +588,7 @@ stanzaKeywordMap = , \n -> Map.fromList $ [ ("main-is:", filePathCompleter) , ("scope:", constantCompleter ["public", "private"]) - , ("other-modules:", modulesCompleter (otherModulesExtractionExecutable n)) + , ("other-modules:", modulesCompleter (sourceDirsExtractionExecutable n)) ] ++ libExecTestBenchCommons ) @@ -581,7 +597,7 @@ stanzaKeywordMap = , \n -> Map.fromList $ [ ("type:", constantCompleter ["exitcode-stdio-1.0", "detailed-0.9"]) , ("main-is:", filePathCompleter) - , ("other-modules:", modulesCompleter (otherModulesExtractionTestSuite n)) + , ("other-modules:", modulesCompleter (sourceDirsExtractionTestSuite n)) ] ++ libExecTestBenchCommons ) @@ -590,7 +606,7 @@ stanzaKeywordMap = , \n -> Map.fromList $ [ ("type:", noopCompleter) , ("main-is:", filePathCompleter) - , ("other-modules:", modulesCompleter (otherModulesExtractionBenchmark n)) + , ("other-modules:", modulesCompleter (sourceDirsExtractionBenchmark n)) ] ++ libExecTestBenchCommons ) diff --git a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/FilepathCompletions.hs b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/FilepathCompletions.hs index 7a4d47ffff4..c6cf0f69bd4 100644 --- a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/FilepathCompletions.hs +++ b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/FilepathCompletions.hs @@ -78,7 +78,7 @@ listFileCompletions recorder complInfo = do pure [] {- | Returns a list of all (and only) directories in the - directory described by path completion info + directory described by path completion info. -} listDirectoryCompletions :: Recorder (WithPriority Log) -> PathCompletionInfo -> IO [FilePath] listDirectoryCompletions recorder complInfo = do @@ -134,16 +134,19 @@ filePathsForExposedModules srcDirs recorder prefInfo = do fileExists <- doesFileExist (dir FP. path) pure $ not fileExists || FP.isExtensionOf ".hs" path - +{- | Takes a source dir path and a cabal file path and returns the complete source dir + path in exposed module syntax where the separators are '.' and the file ending is removed. +-} fpToExposedModulePath :: FilePath -> FilePath -> FilePath -fpToExposedModulePath srcDir fp' = T.unpack $ T.intercalate "." $ fmap T.pack $ FP.splitDirectories fp +fpToExposedModulePath srcDir cabalDir = T.unpack $ T.intercalate "." $ fmap T.pack $ FP.splitDirectories fp where - fp = fromMaybe fp' $ stripPrefix srcDir fp' + fp = fromMaybe cabalDir $ stripPrefix srcDir cabalDir +{- | Takes a path in the exposed module field and translates it to a filepath. +-} exposedModulePathToFp :: T.Text -> FilePath exposedModulePathToFp fp = T.unpack $ T.replace "." (T.singleton FP.pathSeparator) fp - {- | Returns the directory, the currently handled cabal file is in. We let System.FilePath handle the separator syntax since this is used diff --git a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Types.hs b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Types.hs index d33bb8a6c94..b82b8386b57 100644 --- a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Types.hs +++ b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Types.hs @@ -47,10 +47,15 @@ and returns the list of possible completion items -} type Completer = Recorder (WithPriority Log) -> CompleterData -> IO [CompletionItem] +{- | Contains information to be used by completers. +-} data CompleterData = CompleterData { ideState :: IdeState +-- ^ The ideState, which can be used to call the cabal parser results , cabalPrefixInfo :: CabalPrefixInfo +-- ^ Prefix info to be used for constructing completion items , stanzaName :: Maybe StanzaName +-- ^ The name of the stanza in which the completer is applied } {- | The context a cursor can be in within a cabal file,