{-# OPTIONS_GHC -Wall #-} {-# LANGUAGE OverloadedStrings, FlexibleInstances #-} module UI.FileBrowser (State, drawUI, handleEvent, theMap) where import Brick import Brick.Widgets.Border import Brick.Widgets.Center import Brick.Widgets.List import Brick.Widgets.FileBrowser import Control.Exception (displayException, try) import Control.Monad.IO.Class import Lens.Micro.Platform import Parser import States import StateManagement import Recents import Runners import UI.BrickHelpers import qualified UI.Attributes as A import qualified Graphics.Vty as V theMap :: AttrMap theMap = applyAttrMappings [ (listSelectedFocusedAttr, V.black `on` V.yellow) , (fileBrowserCurrentDirectoryAttr, V.white `on` V.blue) , (fileBrowserSelectionInfoAttr, V.white `on` V.blue) , (fileBrowserDirectoryAttr, fg V.blue) , (fileBrowserBlockDeviceAttr, fg V.magenta) , (fileBrowserCharacterDeviceAttr, fg V.green) , (fileBrowserNamedPipeAttr, fg V.yellow) , (fileBrowserSymbolicLinkAttr, fg V.cyan) , (fileBrowserUnixSocketAttr, fg V.red) , (fileBrowserSelectedAttr, V.white `on` V.magenta) ] A.theMap drawUI :: FBS -> [Widget Name] drawUI FBS{_fb=b, _exception'=exc} = [drawException exc, center $ ui <=> help] where ui = hCenter $ vLimit 15 $ hLimit 50 $ borderWithLabel (txt "Choose a file") $ renderFileBrowser True b help = padTop (Pad 1) $ vBox [ hCenter $ txt "Up/Down: select, h: toggle show hidden files" , hCenter $ txt "/: search, Ctrl-C or Esc: cancel search" , hCenter $ txt "Enter: change directory or select file" , hCenter $ txt "Esc or q: quit" ] handleEvent :: GlobalState -> FBS -> BrickEvent Name Event -> EventM Name (Next GlobalState) handleEvent gs s@FBS{_fb=b, _exception'=excep} (VtyEvent ev) = let update = updateFBS gs continue' = continue . update halt' = continue . popState in case (excep, ev) of (Just _, _) -> continue' $ s & exception' .~ Nothing (_, e) -> case e of V.EvKey V.KEsc [] | not (fileBrowserIsSearching b) -> halt' gs V.EvKey (V.KChar 'q') [] | not (fileBrowserIsSearching b) -> halt' gs V.EvKey (V.KChar 'h') [] | not (fileBrowserIsSearching b) -> let s' = s & showHidden %~ not in continue' $ s' & fb .~ setFileBrowserEntryFilter (Just (entryFilter (s' ^. showHidden))) b _ -> do b' <- handleFileBrowserEvent ev b let s' = s & fb .~ b' case ev of V.EvKey V.KEnter [] -> case fileBrowserSelection b' of [] -> continue' s' [fileInfo] -> do let fp = fileInfoFilePath fileInfo fileOrExc <- liftIO (try (readFile fp) :: IO (Either IOError String)) case fileOrExc of Left exc -> continue' (s' & exception' ?~ displayException exc) Right file -> case parseCards file of Left parseError -> continue' (s & exception' ?~ parseError) Right result -> continue =<< liftIO (do addRecent fp gs' <- refreshRecents' gs return (gs' `goToState` parameterState (gs'^.parameters) fp result)) _ -> halt' gs _ -> continue' s' handleEvent gs _ _ = continue gs