packages feed

hbro-1.2.0.0: library/Hbro/K.hs

{-# LANGUAGE TemplateHaskell, TypeFamilies #-}
module Hbro.K (
    KData,
    K,
    init,
    getHooks,
    resetKeyBindings,
) where

-- {{{
import Hbro.Clipboard as Clipboard
import Hbro.Config as Config
import Hbro.Core
import Hbro.Error
import Hbro.Gdk.KeyVal
import Hbro.Gui as Gui
import Hbro.Gui.NotificationBar
import Hbro.Gui.PromptBar as Prompt
-- import Hbro.IPC as IPC (Command(..))
import Hbro.IPC.Hooks as IPC
import Hbro.IPC.Signals as IPC
import Hbro.Keys as Keys
import Hbro.Keys.Model ((.|))
import Hbro.Keys.Monadic as Keys
import Hbro.Hooks as Hooks
import Hbro.Signals as Signals
import Hbro.Gui.PromptBar.Hooks
import Hbro.Prelude
import Hbro.WebView.Hooks as WebView
import Hbro.WebView.Signals as WebView

-- import Control.Lens.Getter
import Control.Lens.Lens
import Control.Lens.Setter
import Control.Lens.TH
import Control.Monad.Reader

import Data.Map as M hiding(foldl, map)

import Graphics.UI.Gtk.Gdk.EventM as Gdk
import Graphics.UI.Gtk.Windows.Window
import Graphics.UI.Gtk.WebKit.WebView

import Network.URI.Monadic

import qualified System.Glib.Attributes as G
-- }}}

data KData = KData
    { _config      :: TVar Config
    , _gui         :: GUI
    , _hooks       :: Hooks.Hooks KE
    , _signals     :: Signals.Signals
    }

type K  = ReaderT KData IO
type KE = ExceptT Text K

makeLensesWith ?? ''KData $ lensRules
    & lensField .~ (\name -> Just (tailSafe name ++ "L"))


instance HasConfig KData           where _config          = configL
instance HasGUI KData              where _gui             = guiL
instance Keys.HasHooks KE KData    where _hooks           = hooksL.keyHooksL
instance HasPromptHooks KE KData   where _promptHooks     = hooksL.promptHooksL
instance WebView.HasHooks KE KData where _hooks           = hooksL.webViewHooksL
instance HasNotificationBar KData  where _notificationbar = guiL.notificationBarL
instance HasPromptBar KData        where _promptbar       = guiL.promptBarL


init :: (BaseIO m) => GUI -> Hooks.Hooks KE -> Signals.Signals -> m KData
init ui hooks signals = io (KData <$> newTVarIO def <*> pure ui <*> pure hooks <*> pure signals)

getHooks :: (MonadReader KData m) => m (Hooks.Hooks KE)
getHooks = askL hooksL

-- {{{ Default configuration
-- instance Default (Signals.DownloadHook KE) where
    -- def = Signals.DownloadHook . const . const . const $ return ()

instance Default (Hooks.LinkClickedHook KE) where
    def = Hooks.LinkClickedHook f
            where f (LinkClicked uri Gdk.MiddleButton) = spawn "hbro" ["-u", show uri]
                  f (LinkClicked uri _               ) = load uri

instance Default (Hooks.LoadRequestedHook KE) where
    def = Hooks.LoadRequestedHook $ \(LoadRequested uri) -> load uri

instance Default (Hooks.NewWindowHook KE) where
    def = Hooks.NewWindowHook $ \(NewWindow uri) -> spawn "hbro" ["-u", show uri]

-- /!\ NetworkRequest's Haskell binding is missing the function "webkit_network_request_get_message", which makes it rather useless...
-- | Display content if webview can show the given MIME type, otherwise download it.
instance Default (Hooks.ResourceOpenedHook KE) where
    def = Hooks.ResourceOpenedHook $ \(ResourceOpened _uri mimetype) -> do
        return Hooks.Load <<| canRender mimetype |>> return Hooks.Download'

instance Default (Hooks.TitleChangedHook KE) where
    def = Hooks.TitleChangedHook (\(TitleChanged title) -> gAsync . (`G.set` [ windowTitle G.:= ("hbro | " ++ title)]) =<< Gui.get mainWindowL)


-- | List of default supported requests.
instance Default (IPC.Hooks KE) where
    def = IPC.Hooks . M.fromList . map (first IPC.Command) $ [
    -- Get information
        ("GET_URI",             \_arguments -> Right . tshow <$> getCurrentURI),
        ("GET_TITLE",           \_arguments -> Right <$> getPageTitle),
        ("GET_FAVICON_URI",     \_arguments -> Right . tshow <$> getFaviconURI),
        ("GET_LOAD_PROGRESS",   \_arguments -> Right . tshow <$> getLoadProgress),
    -- Trigger actions
        ("LOAD_URI",            \arguments -> case arguments of
            uri:_ -> parseURIReference uri >>= load >> (return $ Right "OK")
            _     -> return . Left $ "Argument needed."),
        ("STOP_LOADING",        \_arguments -> stopLoading       >> (return $ Right "OK")),
        ("RELOAD",              \_arguments -> reload            >> (return $ Right "OK")),
        ("RELOAD_BYPASS_CACHE", \_arguments -> reloadBypassCache >> (return $ Right "OK")),
        ("GO_BACK",             \_arguments -> goBack            >> (return $ Right "OK")),
        ("GO_FORWARD",          \_arguments -> goForward         >> (return $ Right "OK")),
        ("ZOOM_IN",             \_arguments -> zoomIn            >> (return $ Right "OK")),
        ("ZOOM_OUT",            \_arguments -> zoomOut           >> (return $ Right "OK"))]


resetKeyBindings :: (BaseIO m, MonadReader t m, Keys.HasHooks (ExceptT Text K) t) => m ()
resetKeyBindings = do
-- Browse
    Keys.bind (_Alt     .| _Left)   $ goBack
    Keys.bind (_Alt     .| _Right)  $ goForward
    Keys.bind (_Control .| _Escape) $ stopLoading
    Keys.bind _F5                   $ reload
    Keys.bind (_Control .| _r)      $ reload
    Keys.bind (_Control .| _F5)     $ reloadBypassCache
    Keys.bind (_Alt     .| _r)      $ reloadBypassCache
    Keys.bind (_Control .| _dead_circumflex) $ scrollH (Absolute 0)
    Keys.bind (_Control .| _dollar) $ scrollH (Absolute 100)
    Keys.bind (_Control .| _Home)   $ scrollV (Absolute 0)
    Keys.bind (_Control .| _End)    $ scrollV (Absolute 100)
    Keys.bind (_Alt     .| _Home)   $ goHome
-- Copy/paste
    Keys.bind (_Control .| _c)      $ getCurrentURI >>= Clipboard.write . tshow
    Keys.bind (_Alt     .| _c)      $ getPageTitle >>= Clipboard.write
    Keys.bind (_Control .| _v)      $ Clipboard.read >>= parseURIReference >>= load
    Keys.bind (_Alt     .| _v)      $ Clipboard.read >>= spawn "hbro" . ("-u":) . (:[]) . unpack
-- Display
    Keys.bind (_Control .| _plus)   $ zoomIn
    Keys.bind (_Control .| _minus)  $ zoomOut
    Keys.bind (_Control .| _b)      $ Gui.toggle =<< Gui.get statusBarL
    Keys.bind (_Alt     .| _b)      $ Gui.toggle =<< Gui.get notificationBarL
    Keys.bind (_Control .| _u)      $ toggleSourceMode >> reload
-- Prompt
    Keys.bind (_Control .| _o)      $ promptURI "Open URI" "" >>= load
    Keys.bind (_Alt     .| _o)      $ getCurrentURI >>= \uri -> promptURI "Open URI " (tshow uri) >>= load
-- Search
    Keys.bind _slash                $ void $ prompt' "Search " "" $ searchText_ CaseInsensitive Forward Wrap
    Keys.bind (_Control .| _f)      $ prompt "Search " "" >>= searchText_ CaseInsensitive Forward Wrap
    Keys.bind _question             $ void $ prompt' "Search " "" $ searchText_ CaseInsensitive Backward Wrap
    Keys.bind (_Control .| _n)      $ searchText_ CaseInsensitive Forward  Wrap =<< Prompt.getEntryValue
    Keys.bind (_Control .| _p)      $ searchText_ CaseInsensitive Backward Wrap =<< Prompt.getEntryValue
    Keys.bind (_Control .| _h)      $ gAsync . webViewUnMarkTextMatches =<< Gui.get webViewL
-- Misc
    -- Keys.bind (_Control .| _i)      $ openInspector
    Keys.bind (_Alt     .| _Print)  printPage
    Keys.bind (_Control .| _t)      $ spawn "hbro" []
    Keys.bind (_Control .| _w)      quit
-- }}}