hbro 1.1.1.0 → 1.1.2.0
raw patch · 7 files changed
+98/−84 lines, 7 filesdep ~zeromq3-haskell
Dependency ranges changed: zeromq3-haskell
Files
- Hbro/Boot.hs +20/−33
- Hbro/Core.hs +2/−5
- Hbro/IPC.hs +2/−2
- Hbro/Options.hs +52/−21
- LICENSE +1/−1
- README.rst +19/−20
- hbro.cabal +2/−2
Hbro/Boot.hs view
@@ -11,7 +11,7 @@ import qualified Hbro.IPC as IPC import qualified Hbro.Keys as Key import Hbro.Notification-import Hbro.Options (CliOptions)+import Hbro.Options (CliOptions, OptionsReader(..)) import qualified Hbro.Options as Options import Hbro.Util import qualified Hbro.Webkit.WebSettings as WS@@ -24,6 +24,7 @@ import Control.Monad import Control.Monad.Base import Control.Monad.Error hiding(when)+import Control.Monad.Reader hiding(when) import Control.Monad.Trans.Control import Data.Default@@ -46,13 +47,9 @@ import Prelude hiding(init) -import System.Directory-import System.Environment.XDG.BaseDir import System.Exit-import System.FilePath import System.Glib.Signals import System.Posix.Files-import System.Posix.Process import System.Posix.Signals import System.ZMQ3 (Rep(..)) import qualified System.ZMQ3 as ZMQ@@ -75,30 +72,30 @@ hbro' :: (K (), CliOptions) -> IO () hbro' (customSetup, options) = do- config <- initConfig options- gui <- initGUI- ipc <- initIPC- void $ installHandler sigINT (Catch onInterrupt) Nothing- (result, logs) <- runK options config gui ipc $ main customSetup + config <- runReaderT initConfig options+ gui <- runReaderT initGUI options++ (result, logs) <- withIPC options $ \ipc -> runK options config gui ipc $ main customSetup+ either print return result unless (options^.Options.quiet) . unless (null logs) $ putStrLn logs unless (options^.Options.quiet) $ putStrLn "Exiting..." -- {{{ Initialization-initConfig :: (MonadBase IO m) => CliOptions -> m (Config K)-initConfig options = do- let config = id+initConfig :: (MonadBase IO m, OptionsReader m) => m (Config K)+initConfig = do+ options <- readOptions id+ return $ id . (options^.Options.quiet ? set verbosity Quiet ?? id) . (options^.Options.verbose ? set verbosity Verbose ?? id) $ def- return config -initGUI :: (MonadBase IO m) => m (GUI K)+initGUI :: (MonadBase IO m, OptionsReader m) => m (GUI K) initGUI = do- file <- io (getUserConfigDir "hbro" >/> "ui.xml")+ file <- Options.getUIFile fallback <- io $ getDataFileName "examples/ui.xml" file' <- io $ firstReadableOf [file, fallback]@@ -115,19 +112,12 @@ isReadable ? return (Just x) ?? firstReadableOf y -initIPC :: (MonadBase IO m) => m IPC-initIPC = io $ do- theContext <- ZMQ.init 1- socket <- ZMQ.socket theContext Rep- ZMQ.bind socket =<< getSocketURI- return $ IPC theContext socket---getSocketURI :: (MonadBase IO m) => m String-getSocketURI = do- dir <- io getTemporaryDirectory- pid <- io getProcessID- return $ "ipc://" ++ dir </> "hbro." ++ show pid+withIPC :: (MonadBaseControl IO m) => CliOptions -> (IPC -> m a) -> m a+withIPC options f = restoreM =<< (liftBaseWith $ \runInIO -> do+ ZMQ.withContext $ \c -> do+ ZMQ.withSocket c Rep $ \s -> do+ io . ZMQ.bind s =<< runReaderT Options.getSocketURI options+ runInIO $ f (IPC c s)) -- }}} @@ -176,11 +166,8 @@ io GTK.mainGUI -- Clean & close- void . (`IPC.sendCommand` "QUIT") =<< getSocketURI+ void . (`IPC.sendCommand` "QUIT") =<< Options.getSocketURI io $ takeMVar threadSync-- io . ZMQ.close =<< readIPC IPC.receiver- io . ZMQ.term =<< readIPC IPC.context -- | IPC thread that listens to commands from external world.
Hbro/Core.hs view
@@ -58,9 +58,6 @@ newtype K a = K { unKT :: ErrorT HError (WriterT String (ReaderT CliOptions (ReaderT (IORef (Config K)) (ReaderT (GUI K) (ReaderT IPC (ReaderT (IORef Keys.Status) IO)))))) a} deriving (Applicative, Functor, Monad, MonadBase IO, MonadError HError, MonadWriter String) -{-instance MonadBase IO K where- liftBase = K . lift . lift . lift . lift . lift . lift-}- instance MonadBaseControl IO K where newtype StM K a = StK { unStK :: StM (ErrorT HError (WriterT String (ReaderT CliOptions (ReaderT (IORef (Config K)) (ReaderT (GUI K) (ReaderT IPC (ReaderT (IORef Keys.Status) IO))))))) a } liftBaseWith f = K . liftBaseWith $ \runInBase -> f $ liftM StK . runInBase . unKT@@ -167,8 +164,8 @@ ("C-<End>", scroll Vertical (Absolute 100)), ("M-<Home>", goHome), -- Copy/paste- ("C-c", getURI >>= Clipboard.insert . show), -- >> notify 5000 "URI copied to clipboard"),- ("M-c", getTitle >>= Clipboard.insert), -- >> notify 5000 "Page title copied to clipboard"),+ ("C-c", getURI >>= Clipboard.insert . show >> notify 5000 "URI copied to clipboard"),+ ("M-c", getTitle >>= Clipboard.insert >> notify 5000 "Page title copied to clipboard"), ("C-v", Clipboard.with $ parseURIReference >=> load), ("M-v", Clipboard.with $ \uri -> spawn "hbro" [uri]), -- Display
Hbro/IPC.hs view
@@ -6,7 +6,7 @@ -- import Hbro.Error import Hbro.Util -import Control.Lens hiding(Context, Rep)+import Control.Lens hiding(Context) import Control.Monad.Base -- import Control.Monad.Error hiding(mapM_) -- import Control.Monad.Writer@@ -22,7 +22,7 @@ -- import System.Posix.Types -- import System.Process-import System.ZMQ3 hiding(close, init, message, receive, send, socket)+import System.ZMQ3 hiding(close, context, init, message, receive, send, socket) import qualified System.ZMQ3 as ZMQ (receive, send) -- }}}
Hbro/Options.hs view
@@ -4,6 +4,7 @@ CliOptions(), OptionsReader(..), startURI,+ socketPath, help, quiet, verbose,@@ -15,7 +16,9 @@ dyreDebug, usage, get,- getStartURI)+ getStartURI,+ getSocketURI,+ getUIFile) where -- {{{ Imports@@ -28,6 +31,8 @@ import Data.Default import Data.Functor+import Data.List+import Data.Maybe import Network.URI as N @@ -36,13 +41,17 @@ import System.Console.GetOpt import System.Directory import System.Environment+import System.Environment.XDG.BaseDir import System.FilePath+import System.Posix.Process -- }}} -- {{{ Types -- | Available commandline options (cf @hbro -h@). data CliOptions = CliOptions { _startURI :: Maybe String,+ _socketPath :: Maybe FilePath,+ _UIFile :: Maybe FilePath, _help :: Bool, _quiet :: Bool, _verbose :: Bool,@@ -57,21 +66,25 @@ makeLenses ''CliOptions instance Show CliOptions where- show opts =- (maybe "" ("URI=" ++) $ view startURI opts)- ++ (view help opts ? " HELP" ?? "")- ++ (view quiet opts ? " QUIET" ?? "")- ++ (view verbose opts ? " VERBOSE" ?? "")- ++ (view version opts ? " VERSION" ?? "")- ++ (view vanilla opts ? " VANILLA" ?? "")- ++ (view recompile opts ? " RECOMPILE" ?? "")- ++ (view denyReconf opts ? " DENY_RECONFIGURATION" ?? "")- ++ (view forceReconf opts ? " FORCE_RECONFIGURATION" ?? "")- ++ (view dyreDebug opts ? " DYRE_DEBUG" ?? "")+ show opts = intercalate " " $ catMaybes [+ return . ("URI=" ++) =<< view startURI opts,+ return . ("SOCKET=" ++) =<< view socketPath opts,+ return . ("UI_FILE=" ++) =<< view uIFile opts,+ view help opts ? Just "HELP" ?? Nothing,+ view quiet opts ? Just "QUIET" ?? Nothing,+ view verbose opts ? Just "VERBOSE" ?? Nothing,+ view version opts ? Just "VERSION" ?? Nothing,+ view vanilla opts ? Just "VANILLA" ?? Nothing,+ view recompile opts ? Just "RECOMPILE" ?? Nothing,+ view denyReconf opts ? Just "DENY_RECONFIGURATION" ?? Nothing,+ view forceReconf opts ? Just "FORCE_RECONFIGURATION" ?? Nothing,+ view dyreDebug opts ? Just "DYRE_DEBUG" ?? Nothing] instance Default CliOptions where def = CliOptions { _startURI = Nothing,+ _socketPath = Nothing,+ _UIFile = Nothing, _help = False, _quiet = False, _verbose = False,@@ -96,15 +109,17 @@ description :: [OptDescr (CliOptions -> CliOptions)] description = [- Option ['h'] ["help"] (NoArg (\o -> o { _help = True })) "Print this help.",- Option ['q'] ["quiet"] (NoArg (\o -> o { _quiet = True })) "Do not print any log.",- Option ['v'] ["verbose"] (NoArg (\o -> o { _verbose = True })) "Print detailed logs.",- Option ['V'] ["version"] (NoArg (\o -> o { _version = True })) "Print version.",- Option ['1'] ["vanilla"] (NoArg (\o -> o { _vanilla = True })) "Do not read custom configuration file.",- Option ['r'] ["recompile"] (NoArg (\o -> o { _recompile = True })) "Only recompile configuration.",- Option [] ["deny-reconf"] (NoArg id) "Do not recompile configuration even if it has changed.",- Option [] ["force-reconf"] (NoArg id) "Recompile configuration before starting the program.",- Option [] ["dyre-debug"] (NoArg id) "Use './cache/' as the cache directory and ./ as the configuration directory. Useful to debug the program."]+ Option ['h'] ["help"] (NoArg (set help True)) "Print this help",+ Option ['q'] ["quiet"] (NoArg (set quiet True)) "Do not print any log",+ Option ['v'] ["verbose"] (NoArg (set verbose True)) "Print detailed logs",+ Option ['V'] ["version"] (NoArg (set version True)) "Print version",+ Option ['1'] ["vanilla"] (NoArg (set vanilla True)) "Do not read custom configuration file",+ Option ['r'] ["recompile"] (NoArg (set recompile True)) "Only recompile configuration",+ Option ['s'] ["socket"] (ReqArg (\v -> set socketPath (Just v)) "PATH") "Where to open IPC socket",+ Option ['u'] ["ui"] (ReqArg (\v -> set uIFile (Just v)) "PATH") "Path to UI descriptor (XML file)",+ Option [] ["force-reconf"] (NoArg id) "Recompile configuration before starting the program",+ Option [] ["deny-reconf"] (NoArg id) "Do not recompile configuration even if it has changed",+ Option [] ["dyre-debug"] (NoArg id) "Use './cache/' as the cache directory and ./ as the configuration directory. Useful to debug the program"] -- | Usage text (cf @hbro -h@) usage :: String@@ -130,3 +145,19 @@ True -> io getCurrentDirectory >>= return . N.parseURIReference . ("file://" ++) . (</> uri) _ -> return $ N.parseURIReference uri _ -> return Nothing+++-- | Return socket URI used by this instance+getSocketURI :: (MonadBase IO m, OptionsReader m) => m String+getSocketURI = maybe getDefaultSocketURI (return . ("ipc://" ++)) =<< readOptions socketPath+ where+ getDefaultSocketURI = do+ dir <- io getTemporaryDirectory+ pid <- io getProcessID+ return $ "ipc://" ++ dir </> "hbro." ++ show pid++-- | Return UI descriptor (XML file) used to build the GUI+getUIFile :: (MonadBase IO m, OptionsReader m) => m FilePath+getUIFile = maybe getDefaultUIFile return =<< readOptions uIFile+ where+ getDefaultUIFile = io (getUserConfigDir "hbro" >/> "ui.xml")
LICENSE view
@@ -1,7 +1,7 @@ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 -Copyright (C) 2011 koral <koral at mailoo dot org>+Copyright (C) koral <koral at mailoo dot org> Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long
README.rst view
@@ -12,19 +12,20 @@ ----------------- `Do one thing well`_- Browsing is about retrieving, presenting and traversing web resources. Not about providing tabs, bookmarks, history, download management, adblocking, passwords saving, self-updating, ... There already exists standalone applications for most extra features one may think of, please reuse them. *Hbro* can be configured to call external programs for any task.+ A web browser is **not** a {window|bookmarks|history|download|passwords|package} manager, let alone an operating system.+ A web browser retrieves, renders and traverses web pages, period. `Keep It Simple, Stupid`_- *Hbro* is written with simplicity in mind, and without obsession for performance, features or release frequency. It should not take time to start-up, consume much RAM or crash. Simplicity provides lightweightness, scalability, stability and maintainability. Its code is easy to understand (well, as long as you speak Haskell...) to encourage users to hack it.+ The program should be written with simplicity in mind, and without obsession for performance, features or release frequency. It should not take time to start-up, consume much RAM or crash. Its code should be easy to understand (well, as long as you speak Haskell...) to encourage users to hack it. Simplicity provides lightness, scalability, stability and maintainability. Extensible- Targets are advanced users who have various expectations ; to be sure everyone is happy, *hbro* is configured using a programming language, and offers an interprocess interface. As he who can do the most can do the least, the default configuration should be suitable for users that cannot afford or don't want to spend (waste ?) their time in tweaks.+ Configuration system should allow users to implement extra features. External programs should be able to query/order *hbro*. -Keyboard driven- Special attention is given to allow keyboard control of the browser whenever possible.+Good defaults+ A default configuration, suitable for users that cannot afford or don't want to spend (waste ?) their time in tweaks, should be provided. -Free software- Hbro is distributed under the `Do-What-The-Fuck-You-Want-To public licence`_, which has a pretty self-explanatory name.+Keyboard driven+ Keyboard control should be made as much convenient, with as little mouse intervention, as possible. Components and libraries used@@ -52,28 +53,27 @@ Configuration ------------- -By default, a pretty limited configuration file (see ``Hbro/Main.hs``) is used to build *hbro*. You can create your own at ``~/.config/hbro/hbro.hs`` to override it. Several extensions are provided with the * hbro-contrib_ * package, including a featured and self-explanatory example of configuration file.+By default, a minimal configuration file (see ``Hbro/Main.hs``) is used to build *hbro*. You can create your own at ``~/.config/hbro/hbro.hs`` to override it. Several extensions are provided with the * hbro-contrib_ * package, including a well-commented example of configuration file. Known bugs and limitations -------------------------- -Patches or suggestions are welcome to deal with the following issues. See package description for contact address.+Unfortunately, many problems/limitations are inherited from the *Haskell* binding for *webkit*/*gtk*. Until fixed in upstream, nothing can be done on *hbro* to work around them. Here's a summary of them: -The browser crashes on loading some webpages, and on enabling javascript/flash- The demo webkit browser provided with haskell's binding crashes likewise, which suggests a problem in the haskell binding for webkit-gtk. Unfortunately, not much can be done on *hbro* itself to fix it.+- segfaults when loading some webpages or enabling javascript/flash;+- no proxy configuration;+- no cookies management;+- javascript's ``window.open`` requests open in the same window instead of spawning a new one;+- toggling to source mode reloads current webpage (which may be undesired) -.. Javascript's window.open requests open in the same window instead of spawning a new one.- This is due to this webkit's bug.+Patches or suggestions are welcome to deal with the following issues. -When toggling to source mode, current webpage is reloaded- This is an undesired behavior since the webpage may have changed after reloading; webkit's API allows to get the content of the DOM but only inside the body tag; it is also possible to store the HTML source as it is downloaded, but then any further change in the DOM (for example triggered by javascript functions) wouldn't be visible. -No cookies management available- The Haskell binding is missing some necessary functions that make it impossible to act on cookies management.+License+------- -Configuring a proxy is impossible- This feature would make use of to the webkit_get_default_session_ function. Unfortunately, Webkit's Haskell binding doesn't provide such function for now.+*hbro* is distributed under the `Do-What-The-Fuck-You-Want-To public licence`_, which has a pretty self-explanatory name. .. _hackage: http://hackage.haskell.org/package/hbro@@ -85,5 +85,4 @@ .. _GTK+: http://www.gtk.org/ .. _ZeroMQ: http://www.zeromq.org/ .. _Dyre: https://github.com/willdonnelly/dyre-.. _webkit_get_default_session: http://webkitgtk.org/reference/webkitgtk/stable/webkitgtk-Global-functions.html .. _hbro-contrib: http://hackage.haskell.org/package/hbro-contrib
hbro.cabal view
@@ -1,5 +1,5 @@ Name: hbro-Version: 1.1.1.0+Version: 1.1.2.0 Synopsis: Minimal KISS compliant browser -- Description: Homepage: http://projects.haskell.org/hbro/@@ -46,7 +46,7 @@ unix, webkit, xdg-basedir,- zeromq3-haskell+ zeromq3-haskell >= 0.2 Exposed-modules: Hbro, Hbro.Boot,