From 7245fc097567ad6b5493b2e97f599547d7535ec3 Mon Sep 17 00:00:00 2001 From: Jens Nolte <jens@nightmarestudio.de> Date: Tue, 18 Feb 2020 16:11:21 +0100 Subject: [PATCH] Allow configuration of blocks from cli This reverses the control flow between 'Cli' and 'Server' --- app/Main.hs | 4 +-- src/QBar/Cli.hs | 70 ++++++++++++++++++++++----------------- src/QBar/ControlSocket.hs | 21 ++++++------ src/QBar/Core.hs | 6 ++++ src/QBar/DefaultConfig.hs | 4 +-- src/QBar/Server.hs | 14 ++------ 6 files changed, 61 insertions(+), 58 deletions(-) diff --git a/app/Main.hs b/app/Main.hs index 6a8109f..1aa42b0 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -1,8 +1,6 @@ module Main where import QBar.Cli -import QBar.DefaultConfig -import QBar.Server main :: IO () -main = parseOptions >>= runQBar generateDefaultBarConfig \ No newline at end of file +main = runQBar \ No newline at end of file diff --git a/src/QBar/Cli.hs b/src/QBar/Cli.hs index 986afc3..d23996a 100644 --- a/src/QBar/Cli.hs +++ b/src/QBar/Cli.hs @@ -2,47 +2,55 @@ module QBar.Cli where +import QBar.ControlSocket +import QBar.Core +import QBar.DefaultConfig +import QBar.Server import QBar.Theme -import qualified Data.Text as T -import qualified Data.Text.Lazy as TL +import Control.Monad (join, sequence_) +import qualified Data.Text.Lazy as T import Options.Applicative -data BarCommand = BarServerCommand | SetThemeCommand Text | ConnectSocket +-- |Entry point. +runQBar :: IO () +runQBar = join parseMain -barCommandParser :: Parser BarCommand -barCommandParser = hsubparser ( - command "server" (info (pure BarServerCommand) (progDesc "Start a new qbar server. Should be called by swaybar, i3bar or or another i3bar-protocol compatible host process.")) <> - command "connect" (info (pure ConnectSocket) (progDesc "Run blocks on this process but display them on the qbar server.")) <> - command "theme" (info themeCommandParser (progDesc "Change the theme of the running qbar server.")) <> - command "default" (info (pure $ SetThemeCommand "default") (progDesc "Shortcut for 'qbar theme default'.")) <> - command "rainbow" (info (pure $ SetThemeCommand "rainbow") (progDesc "Shortcut for 'qbar theme rainbow'.")) - ) - -themeCommandParser :: Parser BarCommand -themeCommandParser = SetThemeCommand <$> strArgument (metavar "THEME" <> completeWith (map TL.unpack themeNames)) +parseMain :: IO (IO ()) +parseMain = customExecParser parserPrefs parser + where + parser :: ParserInfo (IO ()) + parser = info (mainParser <**> helper) + (fullDesc <> header "qbar - queezles {i3,sway}bar infrastructure") -data MainOptions = MainOptions { - verbose :: Bool, - indicator :: Bool, - socketLocation :: Maybe T.Text, - barCommand :: BarCommand -} + parserPrefs :: ParserPrefs + parserPrefs = prefs showHelpOnEmpty -mainOptionsParser :: Parser MainOptions -mainOptionsParser = do +mainParser :: Parser (IO ()) +mainParser = do verbose <- switch $ long "verbose" <> short 'v' <> help "Print more diagnostic output to stderr (including a copy of every bar update)." indicator <- switch $ long "indicator" <> short 'i' <> help "Show render indicator." socketLocation <- optional $ strOption $ long "socket" <> short 's' <> metavar "SOCKET" <> help "Control socket location. By default determined by WAYLAND_SOCKET location." barCommand <- barCommandParser - return MainOptions {verbose, indicator, socketLocation, barCommand} + return (barCommand MainOptions {verbose, indicator, socketLocation}) -parser :: ParserInfo MainOptions -parser = info (mainOptionsParser <**> helper) - (fullDesc <> header "qbar - queezles {i3,sway}bar infrastructure") - -parserPrefs :: ParserPrefs -parserPrefs = prefs showHelpOnEmpty +barCommandParser :: Parser (MainOptions -> IO ()) +barCommandParser = hsubparser ( + command "server" (info (runBarServer <$> barConfigurationParser) (progDesc "Start a new qbar server. Should be called by swaybar, i3bar or or another i3bar-protocol compatible host process.")) <> + command "connect" (info (sendBlockStream <$> barConfigurationParser) (progDesc "Run blocks on this process but display them on the qbar server.")) <> + command "theme" (info themeCommandParser (progDesc "Change the theme of the running qbar server.")) <> + command "default" (info (pure $ sendIpc . SetTheme $ "default") (progDesc "Shortcut for 'qbar theme default'.")) <> + command "rainbow" (info (pure $ sendIpc . SetTheme $ "rainbow") (progDesc "Shortcut for 'qbar theme rainbow'.")) + ) -parseOptions :: IO MainOptions -parseOptions = customExecParser parserPrefs parser \ No newline at end of file +themeCommandParser :: Parser (MainOptions -> IO ()) +themeCommandParser = sendIpc . SetTheme <$> strArgument (metavar "THEME" <> completeWith (map T.unpack themeNames)) + +barConfigurationParser :: Parser (BarIO ()) +barConfigurationParser = do + blocks <- many $ hsubparser ( + command "default" (info (pure defaultBarConfig) (progDesc "Load default set of blocks.")) + ) + pure $ case blocks of + [] -> defaultBarConfig + l -> sequence_ l diff --git a/src/QBar/ControlSocket.hs b/src/QBar/ControlSocket.hs index 8faa26a..632d486 100644 --- a/src/QBar/ControlSocket.hs +++ b/src/QBar/ControlSocket.hs @@ -9,7 +9,6 @@ module QBar.ControlSocket where import QBar.BlockOutput -import QBar.Cli (MainOptions(..)) import QBar.Core import QBar.Host import QBar.Util @@ -27,8 +26,7 @@ import System.IO import Data.Either (either) import Data.Maybe (maybe) import Data.Text.Lazy (Text, pack) -import qualified Data.Text as T -import qualified Data.Text.Lazy as TL +import qualified Data.Text.Lazy as T import Network.Socket import Pipes import Pipes.Concurrent as PC (Output, spawn', unbounded, fromInput, send, atomically) @@ -110,12 +108,15 @@ instance IsStream BlockStream where type Down BlockStream = BlockEvent toStreamType = BlockStreamType streamHandler _ = do - (cache, updateC, seal) <- newCache' + (cache, updateCacheC, sealCache) <- newCache' (eventOutput, eventInput, eventSeal) <- liftIO $ spawn' unbounded bar <- askBar addBlock cache prefix <- liftIO $ (<> "_") <$> randomIdentifier - return (updateBarP bar >-> attachHandlerP eventOutput prefix >-> updateC, fromInput eventInput, seal >> atomically eventSeal) + let blockConsumer = updateBarP bar >-> attachHandlerP eventOutput prefix >-> updateCacheC + let eventProducer = fromInput eventInput + let seal = sealCache >> atomically eventSeal >> updateBar' bar + return (blockConsumer, eventProducer, seal) where attachHandlerP :: Output BlockEvent -> Text -> Pipe [BlockOutput] [BlockState] IO () attachHandlerP eventOutput prefix = attachHandlerP' @@ -145,7 +146,7 @@ instance IsStream BlockStream where data Request = Command Command | StartStream StreamType -data Command = SetTheme TL.Text +data Command = SetTheme T.Text deriving Show data CommandResult = Success | Error Text @@ -189,8 +190,8 @@ $(deriveJSON defaultOptions ''CommandResult) $(deriveJSON defaultOptions ''StreamType) $(deriveJSON defaultOptions ''BlockStream) -sendIpc :: MainOptions -> Command -> IO () -sendIpc options@MainOptions{verbose} command = do +sendIpc :: Command -> MainOptions -> IO () +sendIpc command options@MainOptions{verbose} = do let request = Command command sock <- connectIpcSocket options runEffect $ encode request >-> toSocket sock @@ -206,8 +207,8 @@ sendIpc options@MainOptions{verbose} command = do showResponse Success = when verbose $ hPutStrLn stderr "Success" showResponse (Error message) = hPrint stderr message -sendBlockStream :: MainOptions -> BarIO () -> IO () -sendBlockStream = runBarHost . streamClient BlockStream +sendBlockStream :: BarIO () -> MainOptions -> IO () +sendBlockStream loadBlocks options = runBarHost (streamClient BlockStream options) loadBlocks listenUnixSocketAsync :: MainOptions -> Bar -> CommandHandler -> IO (Async ()) diff --git a/src/QBar/Core.hs b/src/QBar/Core.hs index b25a1e6..46bd95c 100644 --- a/src/QBar/Core.hs +++ b/src/QBar/Core.hs @@ -33,6 +33,12 @@ import System.Process.Typed (Process, shell, setStdin, setStdout, getStdout, closed, createPipe, readProcessStdout, startProcess, stopProcess) +data MainOptions = MainOptions { + verbose :: Bool, + indicator :: Bool, + socketLocation :: Maybe T.Text +} + data BlockEvent = Click { name :: T.Text, button :: Int diff --git a/src/QBar/DefaultConfig.hs b/src/QBar/DefaultConfig.hs index d47cb72..ee42174 100644 --- a/src/QBar/DefaultConfig.hs +++ b/src/QBar/DefaultConfig.hs @@ -11,8 +11,8 @@ import Control.Lens blockLocation :: String -> FilePath blockLocation name = "~/.config/qbar/blocks/" <> name -generateDefaultBarConfig :: BarIO () -generateDefaultBarConfig = do +defaultBarConfig :: BarIO () +defaultBarConfig = do systemInfoInterval <- sharedInterval 10 let todo = systemInfoInterval (blockScript $ blockLocation "todo") diff --git a/src/QBar/Server.hs b/src/QBar/Server.hs index 899d3ca..d36cbf0 100644 --- a/src/QBar/Server.hs +++ b/src/QBar/Server.hs @@ -5,7 +5,6 @@ module QBar.Server where import QBar.BlockOutput import QBar.Core -import QBar.Cli import QBar.ControlSocket import QBar.Host import QBar.Pango @@ -117,8 +116,8 @@ swayBarOutput options@MainOptions{indicator} = do pangoBlockName = _blockName } -runBarServer :: MainOptions -> BarIO () -> IO () -runBarServer options = runBarHost barServer +runBarServer :: BarIO () -> MainOptions -> IO () +runBarServer loadBlocks options = runBarHost barServer loadBlocks where barServer :: BarIO (Consumer [BlockOutput] IO (), Producer BlockEvent IO ()) barServer = do @@ -190,12 +189,3 @@ runBarServer options = runBarHost barServer Right theme -> do setTheme' theme return Success - - --- |Entry point. -runQBar :: BarIO () -> MainOptions -> IO () -runQBar barConfiguration options@MainOptions{barCommand} = runCommand barCommand - where - runCommand BarServerCommand = runBarServer options barConfiguration - runCommand ConnectSocket = sendBlockStream options barConfiguration - runCommand (SetThemeCommand themeName) = sendIpc options $ SetTheme themeName -- GitLab