lingo 0.4.0.0 → 0.5.0.0
raw patch · 6 files changed
+157/−121 lines, 6 filesdep +directorydep −aesondep −template-haskelldep ~textsetup-changednew-component:exe:generatePVP ok
version bump matches the API change (PVP)
Dependencies added: directory
Dependencies removed: aeson, template-haskell
Dependency ranges changed: text
API changes (from Hackage documentation)
- Data.Languages: [languageId] :: Language -> Integer
- Data.Languages: [languageKey] :: Language -> LanguageKey
- Data.Languages: languageName :: Language -> Text
- Data.Languages.Templates: Language :: Integer -> LanguageKey -> [String] -> [String] -> Language
- Data.Languages.Templates: [languageExtensions] :: Language -> [String]
- Data.Languages.Templates: [languageFileNames] :: Language -> [String]
- Data.Languages.Templates: [languageId] :: Language -> Integer
- Data.Languages.Templates: [languageKey] :: Language -> LanguageKey
- Data.Languages.Templates: data Language
- Data.Languages.Templates: generateLanguageMap :: DecsQ
- Data.Languages.Templates: instance Data.Aeson.Types.FromJSON.FromJSON Data.Languages.Templates.Language
- Data.Languages.Templates: instance GHC.Classes.Eq Data.Languages.Templates.Language
- Data.Languages.Templates: instance GHC.Show.Show Data.Languages.Templates.Language
- Data.Languages.Templates: instance Language.Haskell.TH.Syntax.Lift Data.Languages.Templates.Language
- Data.Languages.Templates: languageName :: Language -> Text
- Data.Languages.Templates: type LanguageKey = String
+ Data.Languages: [languageID] :: Language -> Integer
+ Data.Languages: [languageName] :: Language -> Text
- Data.Languages: Language :: Integer -> LanguageKey -> [String] -> [String] -> Language
+ Data.Languages: Language :: Integer -> Text -> [Text] -> [Text] -> Language
- Data.Languages: [languageExtensions] :: Language -> [String]
+ Data.Languages: [languageExtensions] :: Language -> [Text]
- Data.Languages: [languageFileNames] :: Language -> [String]
+ Data.Languages: [languageFileNames] :: Language -> [Text]
- Data.Languages: languagesByExtension :: Map String [LanguageKey]
+ Data.Languages: languagesByExtension :: Map Text [LanguageKey]
- Data.Languages: languagesByFileName :: Map String [LanguageKey]
+ Data.Languages: languagesByFileName :: Map Text [LanguageKey]
- Data.Languages: type LanguageKey = String
+ Data.Languages: type LanguageKey = Text
Files
- ChangeLog.md +4/−0
- Setup.hs +0/−2
- app/Generate.hs +108/−0
- lingo.cabal +27/−14
- src/Data/Languages.hs +18/−25
- src/Data/Languages/Templates.hs +0/−80
ChangeLog.md view
@@ -1,3 +1,7 @@+# 0.5.0.0++Revert to API provided by the 0.3 versions.+ # 0.4.0.0 Rewrite to use Template Haskell splices instead of a custom Setup.hs.
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
+ app/Generate.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC+import Debug.Trace+import System.Directory+import System.FilePath ((</>))+import qualified Data.Map.Strict as Map+import Data.Text (Text)+import Data.Text.Encoding (encodeUtf8)+import qualified Data.Yaml as Y+import Data.Yaml (FromJSON (..), (.!=), (.:), (.:?))++main :: IO ()+main = do+ dir <- getCurrentDirectory+ let yamlFile = dir </> "languages.yml"+ yaml <- B.readFile yamlFile+ B.writeFile (dir </> "src" </> "Gen_Languages.hs") (contents yaml)+ pure ()++contents :: B.ByteString -> B.ByteString+contents yaml =+ "module Gen_Languages where\n\+ \\n\+ \import Data.ByteString (ByteString)\n\+ \import Data.Text (Text)\n\+ \import qualified Data.Map.Strict as Map\n\+ \\n\+ \-- | Type synonym for linguist's language name key.\n\+ \type LanguageKey = Text\n\+ \\n\+ \-- | Identifies a programming language.\n\+ \data Language\n\+ \ = Language\n\+ \ { languageID :: Integer\n\+ \ , languageName :: Text\n\+ \ , languageExtensions :: [Text]\n\+ \ , languageFileNames :: [Text]\n\+ \ } deriving (Eq, Show)\n\+ \\n\+ \-- | Complete map of programming languages known to linguist.\n\+ \languages :: Map.Map LanguageKey Language\n\+ \languages = Map.fromList\+ \ [\n "+ <>+ either (BC.pack . show) (B.intercalate ",\n ") langs+ <>+ " ]\n\+ \\n\+ \-- | Map of languages by file extension.\n\+ \languagesByExtension :: Map.Map Text [LanguageKey]\n\+ \languagesByExtension = Map.fromList\+ \ [\n "+ <>+ either (BC.pack . show) (B.intercalate ",\n ") langsByExt+ <>+ " ]\n\+ \\n\+ \-- | Map of languages by filename.\n\+ \languagesByFileName :: Map.Map Text [LanguageKey]\n\+ \languagesByFileName = Map.fromList\+ \ [\n "+ <>+ either (BC.pack . show) (B.intercalate ",\n ") langsByFileName+ <>+ " ]\n\+ \"++ where+ langs = Map.foldrWithKey (\k v xs -> "(\"" <> encodeUtf8 k <> "\", " <> BC.pack (show v { languageName = k }) <> ")" : xs) mempty <$> languages+ langsByExt = Map.foldrWithKey (\k vs xs -> "(\"" <> encodeUtf8 k <> "\", [" <> showLanguages vs <> "])" : xs) mempty <$> languagesByExtension+ langsByFileName = Map.foldrWithKey (\k vs xs -> "(\"" <> encodeUtf8 k <> "\", [" <> showLanguages vs <> "])" : xs) mempty <$> languagesByFileName++ showLanguages = BC.intercalate ", " . fmap (wrap . encodeUtf8 . languageName)+ wrap x = "\"" <> x <> "\""++ languages :: Either Y.ParseException (Map.Map Text Language)+ languages = Y.decodeEither' yaml++ languagesByExtension :: Either Y.ParseException (Map.Map Text [Language])+ languagesByExtension = Map.foldrWithKey (buildMap languageExtensions) mempty <$> languages++ languagesByFileName :: Either Y.ParseException (Map.Map Text [Language])+ languagesByFileName = Map.foldrWithKey (buildMap languageFileNames) mempty <$> languages++ buildMap :: (Language -> [Text]) -> Text -> Language -> Map.Map Text [Language] -> Map.Map Text [Language]+ buildMap f k l m = foldr (\ext b -> Map.insertWith (<>) ext (pure lang) b) m (f lang)+ where lang = l { languageName = k }++data Language+ = Language+ { languageID :: Integer+ , languageName :: Text+ , languageExtensions :: [Text]+ , languageFileNames :: [Text]+ } deriving (Eq, Show)++instance FromJSON Language where+ parseJSON (Y.Object v) =+ Language <$>+ v .: "language_id" <*>+ v .:? "language_name" .!= mempty <*>+ v .:? "extensions" .!= mempty <*>+ v .:? "filenames" .!= mempty+ parseJSON _ = fail "Expected Object for Language value"
lingo.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.4 build-type: Simple name: lingo-version: 0.4.0.0+version: 0.5.0.0 synopsis: File extension based programming language detection description: Lingo uses github/linguist's language registry to enable fast detection of a file path's programming langauge based on extension or filename. homepage: https://github.com/tclem/lingo-haskell@@ -11,30 +11,43 @@ maintainer: timothy.clem@gmail.com category: Data extra-source-files: README.md+ , languages.yml , ChangeLog.md-data-files: languages.yml -tested-with: GHC == 8.6.5- , GHC == 8.8.1- , GHC == 8.10.1+tested-with: GHC == 8.6.5+ GHC == 8.8.1+ GHC == 8.10.1 +common haskell+ default-language: Haskell2010+ default-extensions: OverloadedStrings+ library- exposed-modules: Data.Languages- , Data.Languages.Templates- autogen-modules: Paths_lingo- other-modules: Paths_lingo+ import: haskell+ exposed-modules: Data.Languages+ other-modules: Gen_Languages+ autogen-modules: Gen_Languages build-depends: base >= 4.12 && < 5- , aeson >= 1.4 && <2 , bytestring ^>= 0.10.8.2 , containers ^>= 0.6.0.1 , filepath ^>= 1.4.2.1 , raw-strings-qq ^>= 1.1- , text ^>= 1.2.3.2- , template-haskell >= 2.14.0.0 && < 2.17.0.0+ , text ^>= 1.2.3.1 , yaml ^>= 0.11.1.2 hs-source-dirs: src- default-language: Haskell2010- default-extensions: OverloadedStrings++executable generate+ import: haskell+ hs-source-dirs: app+ main-is: Generate.hs+ build-depends: base >= 4.12 && < 5+ , bytestring ^>= 0.10.8.2+ , containers ^>= 0.6.0.1+ , directory+ , filepath ^>= 1.4.2.1+ , raw-strings-qq ^>= 1.1+ , text ^>= 1.2.3.1+ , yaml ^>= 0.11.1.2 test-suite test type: exitcode-stdio-1.0
src/Data/Languages.hs view
@@ -1,28 +1,21 @@-{-# LANGUAGE TemplateHaskell #-}- -- | Primary interface for looking up the programming language of a file or--- interacting with languages known to linguist--- (https://github.com/github/linguist).+-- interacting with languages known to linguist (https://github.com/github/linguist). module Data.Languages- ( languagesForPath,- languages,- languagesByExtension,- languagesByFileName,- LanguageKey,- Language (..),- languageName- )-where+ ( languagesForPath+ , languages+ , languagesByExtension+ , languagesByFileName+ , LanguageKey+ , Language(..)+ ) where -import Control.Applicative-import Data.Languages.Templates+import Control.Applicative import qualified Data.Map.Strict as Map-import Data.Maybe-import Data.Text (Text)+import Data.Maybe+import Data.Text (Text) import qualified Data.Text as Text-import System.FilePath.Posix--$(generateLanguageMap)+import Gen_Languages+import System.FilePath.Posix -- | Find the set of possible languages for a given file path. --@@ -32,8 +25,8 @@ where languageForFileName = languageFor (takeFileName path) languagesByFileName languageForExtension = languageFor (takeExtension path) languagesByExtension- languageFor :: String -> Map.Map String [LanguageKey] -> [Language]- languageFor k =- foldMap (maybeToList . flip Map.lookup languages)- . fromMaybe []- . Map.lookup k+ languageFor :: String -> Map.Map Text [LanguageKey] -> [Language]+ languageFor k+ = foldMap (maybeToList . flip Map.lookup languages)+ . fromMaybe []+ . Map.lookup (Text.pack k)
− src/Data/Languages/Templates.hs
@@ -1,80 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveLift #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeApplications #-}--module Data.Languages.Templates- ( Language (..),- LanguageKey,- generateLanguageMap,- languageName,- )-where--import Data.Aeson-import Data.ByteString (ByteString)-import qualified Data.Map.Strict as Map-import Data.Text (Text)-import qualified Data.Text as Text-import Data.Yaml-import GHC.Generics (Generic)-import Language.Haskell.TH-import Language.Haskell.TH.Syntax-#ifndef LANGUAGES_YAML_PATH-import Paths_lingo-#endif---- | Type synonym for linguist's language name key.-type LanguageKey = String---- | Identifies a programming language.-data Language = Language- { languageId :: Integer,- languageKey :: LanguageKey,- languageExtensions :: [String],- languageFileNames :: [String]- }- deriving (Eq, Show, Lift)--languageName :: Language -> Text-languageName = Text.pack . languageKey--instance FromJSON Language where- parseJSON = withObject "Language" $ \l ->- Language- <$> l .: "language_id"- <*> pure "unspecified" -- this is set later in map iteration- <*> l .:? "extensions" .!= []- <*> l .:? "filenames" .!= []--languagesYamlPath :: IO String-#ifdef LANGUAGES_YAML_PATH-languagesYamlPath = pure LANGUAGES_YAML_PATH-#else-languagesYamlPath = getDataFileName "languages.yml"-#endif--generateLanguageMap :: DecsQ-generateLanguageMap = do- langYaml <- runIO languagesYamlPath- langs <- runIO (decodeFileThrow @IO @(Map.Map LanguageKey Language) langYaml)- let normalizedLangs = Map.mapWithKey (\name lang -> lang {languageKey = name}) langs-- byExtension = Map.foldr (process languageExtensions) mempty normalizedLangs- byFileName = Map.foldr (process languageFileNames) mempty normalizedLangs-- process :: (Language -> [String]) -> Language -> Map.Map String [LanguageKey] -> Map.Map String [LanguageKey]- process selector lang acc = foldr (\ext -> Map.insertWith mappend ext [languageKey lang]) acc (selector lang)-- [d|- languages :: Map.Map LanguageKey Language- languages = Map.fromDistinctAscList $(lift (Map.toAscList normalizedLangs))-- languagesByExtension :: Map.Map String [LanguageKey]- languagesByExtension = Map.fromDistinctAscList $(lift (Map.toAscList byExtension))-- languagesByFileName :: Map.Map String [LanguageKey]- languagesByFileName = Map.fromDistinctAscList $(lift (Map.toAscList byFileName))- |]