packages feed

cgrep-8.0.0: src/Config.hs

--
-- Copyright (c) 2013-2023 Nicola Bonelli <nicola@larthia.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
--

{-# LANGUAGE DeriveGeneric #-}

module Config (
    Config(..)
  , dumpPalette
  , getConfig
) where

import Control.Monad ( MonadPlus(mzero), filterM, forM_ )
import System.Directory ( doesFileExist, getHomeDirectory )
import System.Console.ANSI
    ( Color(White, Red, Green, Yellow, Blue, Magenta, Cyan),
      ColorIntensity(Vivid),
      ConsoleIntensity(BoldIntensity),
      ConsoleLayer(Foreground),
      SGR(SetColor, SetConsoleIntensity), setSGRCode )

import System.Console.ANSI.Types
    ( SGR(SetPaletteColor, SetColor, SetConsoleIntensity),
      xterm6LevelRGB,
      Color(White, Red, Green, Yellow, Blue, Magenta, Cyan),
      ColorIntensity(Vivid),
      ConsoleIntensity(BoldIntensity),
      ConsoleLayer(Foreground) )

import qualified Data.Yaml  as Y
import Data.Aeson ( (.!=), (.:?), FromJSON(parseJSON) )
import Data.Maybe ( fromMaybe, mapMaybe )

import GHC.Generics ( Generic )
import CGrep.FileType ( FileType )

import Data.List.Split ( splitOn )
import qualified Data.ByteString as B
import System.FilePath ((</>))
import Data.ByteString.RawFilePath (RawFilePath)
import qualified Data.ByteString.Char8 as C

import Data.List.Extra (notNull)
import CGrep.FileKind (FileKind)
import Text.Read (readMaybe)

cgreprc :: FilePath
cgreprc = "cgreprc"


data Config = Config
  {   configFileTypes  :: [FileType]
  ,   configFileKinds  :: [FileKind]
  ,   configPruneDirs  :: [RawFilePath]
  ,   configColors     :: Bool
  ,   configColorFile  :: [SGR]
  ,   configColorMatch :: [SGR]
  ,   configFileLine   :: Bool
  ,   configJobs       :: Maybe Int
  } deriving stock (Show, Read)


defaultConfig :: Config
defaultConfig = Config
  {   configFileTypes   = []
  ,   configFileKinds   = []
  ,   configPruneDirs   = []
  ,   configColors      = False
  ,   configColorFile   = [SetConsoleIntensity BoldIntensity, SetColor Foreground Vivid Blue]
  ,   configColorMatch  = [SetConsoleIntensity BoldIntensity]
  ,   configFileLine    = False
  ,   configJobs        = Nothing
  }


mkConfig :: YamlConfig -> Config
mkConfig YamlConfig{..} =
   let configFileTypes  = mapMaybe readMaybe yamlFileTypes
       configFileKinds  = mapMaybe readMaybe yamlFileKinds
       configPruneDirs  = C.pack <$> yamlPruneDirs
       configColors     = yamlColors
       configColorFile  = fromMaybe [] (yamlColorFileName >>= readColor)
       configColorMatch = fromMaybe [] (yamlColorMatch >>= readColor)
       configFileLine   = yamlFileLine
       configJobs       = yamlJobs
    in Config {..}


data YamlConfig = YamlConfig
  {   yamlFileTypes     :: [String]
  ,   yamlFileKinds     :: [String]
  ,   yamlPruneDirs     :: [String]
  ,   yamlColors        :: Bool
  ,   yamlColorFileName :: Maybe String
  ,   yamlColorMatch    :: Maybe String
  ,   yamlFileLine      :: Bool
  ,   yamlJobs          :: Maybe Int
  } deriving stock (Show, Generic)


instance Y.FromJSON YamlConfig where
 parseJSON (Y.Object v) =
    YamlConfig <$> v .:? "file_types"       .!= []
               <*> v .:? "file_kinds"       .!= []
               <*> v .:? "prune_dirs"       .!= []
               <*> v .:? "colors"           .!= False
               <*> v .:? "color_filename"   .!= Nothing
               <*> v .:? "color_match"      .!= Nothing
               <*> v .:? "file_line"        .!= False
               <*> v .:? "threads"          .!= Nothing
 parseJSON _ = mzero


getConfig :: IO (Config, Maybe FilePath)
getConfig = do
    home  <- getHomeDirectory
    confs <- filterM doesFileExist [cgreprc, "." <> cgreprc, home </> "." <> cgreprc, "/etc" </> cgreprc]
    if notNull confs
        then do
            conf <- Y.decodeFileEither (head confs)
            case conf of
                Left  e -> errorWithoutStackTrace $ Y.prettyPrintParseException e
                Right yconf -> return (mkConfig yconf, Just (head confs))
        else return (defaultConfig, Nothing)


readColor :: String -> Maybe [SGR]
readColor "Bold"      =  Just [SetConsoleIntensity BoldIntensity]
readColor "Red"       =  Just [SetConsoleIntensity BoldIntensity, SetColor Foreground Vivid Red]
readColor "Green"     =  Just [SetConsoleIntensity BoldIntensity, SetColor Foreground Vivid Green]
readColor "Yellow"    =  Just [SetConsoleIntensity BoldIntensity, SetColor Foreground Vivid Yellow]
readColor "Blue"      =  Just [SetConsoleIntensity BoldIntensity, SetColor Foreground Vivid Blue]
readColor "Magenta"   =  Just [SetConsoleIntensity BoldIntensity, SetColor Foreground Vivid Magenta]
readColor "Cyan"      =  Just [SetConsoleIntensity BoldIntensity, SetColor Foreground Vivid Cyan]
readColor "White"     =  Just [SetConsoleIntensity BoldIntensity, SetColor Foreground Vivid White]
readColor "Orange"    =  Just [SetConsoleIntensity BoldIntensity, SetPaletteColor Foreground $ xterm6LevelRGB 5 2 0]
readColor "Acqua"     =  Just [SetConsoleIntensity BoldIntensity, SetPaletteColor Foreground $ xterm6LevelRGB 2 5 4]
readColor xs          = case splitOn ":" xs of
                          [r, g, b] -> Just [SetConsoleIntensity BoldIntensity, SetPaletteColor Foreground $ xterm6LevelRGB (read r) (read g) (read b)]
                          _      -> Nothing


dumpPalette :: IO ()
dumpPalette = do
  let palette = [(r, g, b) | r <- [0..5], g <- [0..5], b <- [0..5]]
  forM_ palette $ \(r, g, b) -> do
    putStrLn $ setSGRCode [SetConsoleIntensity BoldIntensity, SetPaletteColor Foreground $ xterm6LevelRGB r g b] <> "COLOR " <> show r <> ":" <> show g <> ":" <> show b <> setSGRCode []