{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}

{-# HLINT ignore "Redundant bracket" #-}

module Ide.Plugin.Cabal.Completion.Data where

import           Data.Map                                       (Map)
import qualified Data.Map                                       as Map
import qualified Data.Text                                      as T
import           Development.IDE.GHC.Compat.Core                (flagsForCompletion)
import           Distribution.CabalSpecVersion                  (CabalSpecVersion (CabalSpecV2_2),
                                                                 showCabalSpecVersion)
import           Ide.Plugin.Cabal.Completion.Completer.FilePath
import           Ide.Plugin.Cabal.Completion.Completer.Module
import           Ide.Plugin.Cabal.Completion.Completer.Paths
import           Ide.Plugin.Cabal.Completion.Completer.Simple
import           Ide.Plugin.Cabal.Completion.Completer.Types    (Completer)
import           Ide.Plugin.Cabal.Completion.Types
import           Ide.Plugin.Cabal.LicenseSuggest                (licenseNames)

-- ----------------------------------------------------------------
-- Completion Data
-- ----------------------------------------------------------------

-- | Keyword for cabal version; required to be the top line in a cabal file
cabalVersionKeyword :: Map KeyWordName Completer
cabalVersionKeyword :: Map Text Completer
cabalVersionKeyword =
  Text -> Completer -> Map Text Completer
forall k a. k -> a -> Map k a
Map.singleton Text
"cabal-version:" (Completer -> Map Text Completer)
-> Completer -> Map Text Completer
forall a b. (a -> b) -> a -> b
$
    [Text] -> Completer
constantCompleter ([Text] -> Completer) -> [Text] -> Completer
forall a b. (a -> b) -> a -> b
$
      -- We only suggest cabal versions newer than 2.2
      -- since we don't recommend using older ones.
      (CabalSpecVersion -> Text) -> [CabalSpecVersion] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Text
T.pack (String -> Text)
-> (CabalSpecVersion -> String) -> CabalSpecVersion -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CabalSpecVersion -> String
showCabalSpecVersion) [CabalSpecVersion
CabalSpecV2_2 .. CabalSpecVersion
forall a. Bounded a => a
maxBound]

-- | Top level keywords of a cabal file.
--
-- TODO: we could add descriptions of field values and
-- then show them when inside the field's context
cabalKeywords :: Map KeyWordName Completer
cabalKeywords :: Map Text Completer
cabalKeywords =
  [(Text, Completer)] -> Map Text Completer
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
    [ (Text
"name:", Completer
nameCompleter),
      (Text
"version:", Completer
noopCompleter),
      (Text
"build-type:", [Text] -> Completer
constantCompleter [Text
"Simple", Text
"Custom", Text
"Configure", Text
"Make"]),
      (Text
"license:", [Text] -> Map Text Double -> Completer
weightedConstantCompleter [Text]
licenseNames Map Text Double
weightedLicenseNames),
      (Text
"license-file:", Completer
filePathCompleter),
      (Text
"license-files:", Completer
filePathCompleter),
      (Text
"copyright:", Completer
noopCompleter),
      (Text
"author:", Completer
noopCompleter),
      (Text
"maintainer:", Completer
noopCompleter), -- email address, use git config?
      (Text
"stability:", Completer
noopCompleter),
      (Text
"homepage:", Completer
noopCompleter),
      (Text
"bug-reports:", Completer
noopCompleter),
      (Text
"package-url:", Completer
noopCompleter),
      (Text
"synopsis:", Completer
noopCompleter),
      (Text
"description:", Completer
noopCompleter),
      (Text
"category:", Completer
noopCompleter),
      (Text
"tested-with:", [Text] -> Completer
constantCompleter [Text
"GHC"]),
      (Text
"data-files:", Completer
filePathCompleter),
      (Text
"data-dir:", Completer
directoryCompleter),
      (Text
"extra-source-files:", Completer
filePathCompleter),
      (Text
"extra-doc-files:", Completer
filePathCompleter),
      (Text
"extra-tmp-files:", Completer
filePathCompleter)
    ]

-- | Map, containing all stanzas in a cabal file as keys
--  and lists of their possible nested keywords as values.
stanzaKeywordMap :: Map StanzaType (Map KeyWordName Completer)
stanzaKeywordMap :: Map Text (Map Text Completer)
stanzaKeywordMap =
  [(Text, Map Text Completer)] -> Map Text (Map Text Completer)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
    [ (Text
"library", Map Text Completer
libraryFields Map Text Completer -> Map Text Completer -> Map Text Completer
forall a. Semigroup a => a -> a -> a
<> Map Text Completer
libExecTestBenchCommons),
      (Text
"executable", Map Text Completer
executableFields Map Text Completer -> Map Text Completer -> Map Text Completer
forall a. Semigroup a => a -> a -> a
<> Map Text Completer
libExecTestBenchCommons),
      (Text
"test-suite", Map Text Completer
testSuiteFields Map Text Completer -> Map Text Completer -> Map Text Completer
forall a. Semigroup a => a -> a -> a
<> Map Text Completer
libExecTestBenchCommons),
      (Text
"benchmark", Map Text Completer
benchmarkFields Map Text Completer -> Map Text Completer -> Map Text Completer
forall a. Semigroup a => a -> a -> a
<> Map Text Completer
libExecTestBenchCommons),
      (Text
"foreign-library", Map Text Completer
foreignLibraryFields Map Text Completer -> Map Text Completer -> Map Text Completer
forall a. Semigroup a => a -> a -> a
<> Map Text Completer
libExecTestBenchCommons),
      (Text
"flag", Map Text Completer
flagFields),
      (Text
"source-repository", Map Text Completer
sourceRepositoryFields)
    ]

libraryFields :: Map KeyWordName Completer
libraryFields :: Map Text Completer
libraryFields =
  [(Text, Completer)] -> Map Text Completer
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
    [ (Text
"exposed-modules:", (Maybe Text -> GenericPackageDescription -> [String]) -> Completer
modulesCompleter Maybe Text -> GenericPackageDescription -> [String]
sourceDirsExtractionLibrary),
      (Text
"virtual-modules:", Completer
noopCompleter),
      (Text
"exposed:", [Text] -> Completer
constantCompleter [Text
"True", Text
"False"]),
      (Text
"visibility:", [Text] -> Completer
constantCompleter [Text
"private", Text
"public"]),
      (Text
"reexported-modules:", Completer
noopCompleter),
      (Text
"signatures:", Completer
noopCompleter),
      (Text
"other-modules:", (Maybe Text -> GenericPackageDescription -> [String]) -> Completer
modulesCompleter Maybe Text -> GenericPackageDescription -> [String]
sourceDirsExtractionLibrary)
    ]

executableFields :: Map KeyWordName Completer
executableFields :: Map Text Completer
executableFields =
  [(Text, Completer)] -> Map Text Completer
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
    [ (Text
"main-is:", (Maybe Text -> GenericPackageDescription -> [String]) -> Completer
mainIsCompleter Maybe Text -> GenericPackageDescription -> [String]
sourceDirsExtractionExecutable),
      (Text
"scope:", [Text] -> Completer
constantCompleter [Text
"public", Text
"private"]),
      (Text
"other-modules:", (Maybe Text -> GenericPackageDescription -> [String]) -> Completer
modulesCompleter Maybe Text -> GenericPackageDescription -> [String]
sourceDirsExtractionExecutable)
    ]

testSuiteFields :: Map KeyWordName Completer
testSuiteFields :: Map Text Completer
testSuiteFields =
  [(Text, Completer)] -> Map Text Completer
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
    [ (Text
"type:", [Text] -> Completer
constantCompleter [Text
"exitcode-stdio-1.0", Text
"detailed-0.9"]),
      (Text
"main-is:", (Maybe Text -> GenericPackageDescription -> [String]) -> Completer
mainIsCompleter Maybe Text -> GenericPackageDescription -> [String]
sourceDirsExtractionTestSuite),
      (Text
"other-modules:", (Maybe Text -> GenericPackageDescription -> [String]) -> Completer
modulesCompleter Maybe Text -> GenericPackageDescription -> [String]
sourceDirsExtractionTestSuite)
    ]

benchmarkFields :: Map KeyWordName Completer
benchmarkFields :: Map Text Completer
benchmarkFields =
  [(Text, Completer)] -> Map Text Completer
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
    [ (Text
"type:", Completer
noopCompleter),
      (Text
"main-is:", (Maybe Text -> GenericPackageDescription -> [String]) -> Completer
mainIsCompleter Maybe Text -> GenericPackageDescription -> [String]
sourceDirsExtractionBenchmark),
      (Text
"other-modules:", (Maybe Text -> GenericPackageDescription -> [String]) -> Completer
modulesCompleter Maybe Text -> GenericPackageDescription -> [String]
sourceDirsExtractionBenchmark)
    ]

foreignLibraryFields :: Map KeyWordName Completer
foreignLibraryFields :: Map Text Completer
foreignLibraryFields =
  [(Text, Completer)] -> Map Text Completer
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
    [ (Text
"type:", [Text] -> Completer
constantCompleter [Text
"native-static", Text
"native-shared"]),
      (Text
"options:", [Text] -> Completer
constantCompleter [Text
"standalone"]),
      (Text
"mod-def-file:", Completer
filePathCompleter),
      (Text
"lib-version-info:", Completer
noopCompleter),
      (Text
"lib-version-linux:", Completer
noopCompleter)
    ]

sourceRepositoryFields :: Map KeyWordName Completer
sourceRepositoryFields :: Map Text Completer
sourceRepositoryFields =
  [(Text, Completer)] -> Map Text Completer
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
    [ ( Text
"type:",
        [Text] -> Completer
constantCompleter
          [ Text
"darcs",
            Text
"git",
            Text
"svn",
            Text
"cvs",
            Text
"mercurial",
            Text
"hg",
            Text
"bazaar",
            Text
"bzr",
            Text
"arch",
            Text
"monotone"
          ]
      ),
      (Text
"location:", Completer
noopCompleter),
      (Text
"module:", Completer
noopCompleter),
      (Text
"branch:", Completer
noopCompleter),
      (Text
"tag:", Completer
noopCompleter),
      (Text
"subdir:", Completer
directoryCompleter)
    ]

flagFields :: Map KeyWordName Completer
flagFields :: Map Text Completer
flagFields =
  [(Text, Completer)] -> Map Text Completer
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
    [ (Text
"description:", Completer
noopCompleter),
      (Text
"default:", [Text] -> Completer
constantCompleter [Text
"True", Text
"False"]),
      (Text
"manual:", [Text] -> Completer
constantCompleter [Text
"False", Text
"True"]),
      (Text
"lib-def-file:", Completer
noopCompleter),
      (Text
"lib-version-info:", Completer
noopCompleter),
      (Text
"lib-version-linux:", Completer
noopCompleter)
    ]

libExecTestBenchCommons :: Map KeyWordName Completer
libExecTestBenchCommons :: Map Text Completer
libExecTestBenchCommons =
  [(Text, Completer)] -> Map Text Completer
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
    [ (Text
"build-depends:", Completer
noopCompleter),
      (Text
"hs-source-dirs:", Completer
directoryCompleter),
      (Text
"default-extensions:", Completer
noopCompleter),
      (Text
"other-extensions:", Completer
noopCompleter),
      (Text
"default-language:", [Text] -> Completer
constantCompleter [Text
"GHC2021", Text
"Haskell2010", Text
"Haskell98"]),
      (Text
"other-languages:", Completer
noopCompleter),
      (Text
"build-tool-depends:", Completer
noopCompleter),
      (Text
"buildable:", [Text] -> Completer
constantCompleter [Text
"True", Text
"False"]),
      (Text
"ghc-options:", [Text] -> Completer
constantCompleter [Text]
ghcOptions),
      (Text
"ghc-prof-options:", [Text] -> Completer
constantCompleter [Text]
ghcOptions),
      (Text
"ghc-shared-options:", [Text] -> Completer
constantCompleter [Text]
ghcOptions),
      (Text
"ghcjs-options:", [Text] -> Completer
constantCompleter [Text]
ghcOptions),
      (Text
"ghcjs-prof-options:", [Text] -> Completer
constantCompleter [Text]
ghcOptions),
      (Text
"ghcjs-shared-options:", [Text] -> Completer
constantCompleter [Text]
ghcOptions),
      (Text
"includes:", Completer
filePathCompleter),
      (Text
"install-includes:", Completer
filePathCompleter),
      (Text
"include-dirs:", Completer
directoryCompleter),
      (Text
"c-sources:", Completer
filePathCompleter),
      (Text
"cxx-sources:", Completer
filePathCompleter),
      (Text
"asm-sources:", Completer
filePathCompleter),
      (Text
"cmm-sources:", Completer
filePathCompleter),
      (Text
"js-sources:", Completer
filePathCompleter),
      (Text
"extra-libraries:", Completer
noopCompleter),
      (Text
"extra-ghci-libraries:", Completer
noopCompleter),
      (Text
"extra-bundled-libraries:", Completer
noopCompleter),
      (Text
"extra-lib-dirs:", Completer
directoryCompleter),
      (Text
"cc-options:", Completer
noopCompleter),
      (Text
"cpp-options:", Completer
noopCompleter),
      (Text
"cxx-options:", Completer
noopCompleter),
      (Text
"cmm-options:", Completer
noopCompleter),
      (Text
"asm-options:", Completer
noopCompleter),
      (Text
"ld-options:", Completer
noopCompleter),
      (Text
"pkgconfig-depends:", Completer
noopCompleter),
      (Text
"frameworks:", Completer
noopCompleter),
      (Text
"extra-framework-dirs:", Completer
directoryCompleter),
      (Text
"mixins:", Completer
noopCompleter)
    ]

-- | Contains a map of the most commonly used licenses, weighted by their popularity.
--
--  The data was extracted by Kleidukos from the alternative hackage frontend flora.pm.
weightedLicenseNames :: Map T.Text Double
weightedLicenseNames :: Map Text Double
weightedLicenseNames =
  (Int -> Double) -> Map Text Int -> Map Text Double
forall a b. (a -> b) -> Map Text a -> Map Text b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int -> Double
statisticsToWeight (Map Text Int -> Map Text Double)
-> Map Text Int -> Map Text Double
forall a b. (a -> b) -> a -> b
$
    [(Text, Int)] -> Map Text Int
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
      [ (Text
"BSD-3-Clause", Int
9955),
        (Text
"MIT", Int
3336),
        (Text
"GPL-3.0-only", Int
679),
        (Text
"LicenseRef-OtherLicense", Int
521),
        (Text
"Apache-2.0", Int
514),
        (Text
"LicenseRef-GPL", Int
443),
        (Text
"LicenseRef-PublicDomain", Int
318),
        (Text
"MPL-2.0", Int
288),
        (Text
"BSD-2-Clause", Int
174),
        (Text
"GPL-2.0-only", Int
160),
        (Text
"LicenseRef-LGPL", Int
146),
        (Text
"LGPL-2.1-only", Int
112),
        (Text
"LGPL-3.0-only", Int
100),
        (Text
"AGPL-3.0-only", Int
96),
        (Text
"ISC", Int
89),
        (Text
"LicenseRef-Apache", Int
45),
        (Text
"GPL-3.0-or-later", Int
43),
        (Text
"BSD-2-Clause-Patent", Int
33),
        (Text
"GPL-2.0-or-later", Int
21),
        (Text
"CC0-1.0", Int
16),
        (Text
"AGPL-3.0-or-later", Int
15),
        (Text
"LGPL-2.1-or-later", Int
12),
        (Text
"(BSD-2-Clause OR Apache-2.0)", Int
10),
        (Text
"(Apache-2.0 OR MPL-2.0)", Int
8),
        (Text
"LicenseRef-AGPL", Int
6),
        (Text
"(BSD-3-Clause OR Apache-2.0)", Int
4),
        (Text
"0BSD", Int
3),
        (Text
"BSD-4-Clause", Int
3),
        (Text
"LGPL-3.0-or-later", Int
3),
        (Text
"LicenseRef-LGPL-2", Int
2),
        (Text
"GPL-2.0-or-later AND BSD-3-Clause", Int
2),
        (Text
"NONE", Int
2),
        (Text
"Zlib", Int
2),
        (Text
"(Apache-2.0 OR BSD-3-Clause)", Int
2),
        (Text
"BSD-3-Clause AND GPL-2.0-or-later", Int
2),
        (Text
"BSD-3-Clause AND GPL-3.0-or-later", Int
2)
      ]
  where
    -- Add weights to each usage value from above, the weights are chosen
    -- arbitrarily in order for completions to prioritize which licenses to
    -- suggest in a sensible way
    statisticsToWeight :: Int -> Double
    statisticsToWeight :: Int -> Double
statisticsToWeight Int
stat
      | Int
stat Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
10 = Double
0.1
      | Int
stat Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
20 = Double
0.3
      | Int
stat Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
50 = Double
0.4
      | Int
stat Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
100 = Double
0.5
      | Int
stat Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
500 = Double
0.6
      | Int
stat Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
650 = Double
0.7
      | Bool
otherwise = Double
0.9

ghcOptions :: [T.Text]
ghcOptions :: [Text]
ghcOptions = (String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
T.pack ([String] -> [Text]) -> [String] -> [Text]
forall a b. (a -> b) -> a -> b
$ Bool -> [String]
flagsForCompletion Bool
False