aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/Daffm.hs74
-rw-r--r--lib/Daffm/Attrs.hs22
-rw-r--r--lib/Daffm/Types.hs8
-rw-r--r--lib/Daffm/View.hs75
4 files changed, 127 insertions, 52 deletions
diff --git a/lib/Daffm.hs b/lib/Daffm.hs
index 39a43d0..5bd0830 100644
--- a/lib/Daffm.hs
+++ b/lib/Daffm.hs
@@ -2,11 +2,12 @@ module Daffm where
import qualified Brick.Main as M
import qualified Brick.Types as T
+import qualified Brick.Widgets.Edit as Editor
import qualified Brick.Widgets.List as L
import Control.Monad (forM)
-import Control.Monad.State (MonadIO (liftIO), get, gets, modify)
+import Control.Monad.State (MonadIO (liftIO), MonadState, get, gets, modify, put)
import Daffm.Attrs (appAttrMap)
-import Daffm.Types (AppState (..), FileInfo (..), FileType (..))
+import Daffm.Types (AppState (..), FileInfo (..), FileType (..), FocusTarget (FocusCmdline, FocusMain))
import Daffm.View (appView)
import Data.Char (toLower)
import Data.List (sortBy)
@@ -18,48 +19,52 @@ import System.Directory (listDirectory, makeAbsolute, setCurrentDirectory)
import System.FilePath (takeDirectory)
import qualified System.PosixCompat as Posix
-openSelectedFile :: T.EventM () AppState ()
+type AppEvent = T.EventM FocusTarget AppState
+
+modifyM :: (MonadState s m) => (s -> m s) -> m ()
+modifyM f = get >>= f >>= put
+
+openSelectedFile :: AppEvent ()
openSelectedFile = do
- state <- get
- let indexM = L.listSelected . stateFiles $ state
- let files = L.listElements . stateFiles $ state
- let fileM = indexM >>= (files !?)
- case fileM of
- Just (FileInfo {filePath, fileType = Directory}) -> do
- let parentDir = stateCwd state
- nextState <- liftIO $ loadDirInAppState filePath parentDir state
- modify (const nextState)
- pure ()
+ AppState {stateFiles, stateCwd} <- get
+ let indexM = L.listSelected stateFiles
+ let files = L.listElements stateFiles
+ case indexM >>= (files !?) of
+ Just (FileInfo {filePath, fileType = Directory}) ->
+ modifyM (liftIO . loadDirInAppState filePath stateCwd)
Just (FileInfo {filePath, fileType}) -> do
liftIO . putStrLn $ "Opening " <> show fileType <> ": " <> filePath
pure ()
Nothing -> pure ()
pure ()
-goBackToParentDir :: T.EventM () AppState ()
+goBackToParentDir :: AppEvent ()
goBackToParentDir = do
- state <- get
- let dir = stateParentDir state
- let parentDir = takeDirectory dir
- nextState <- liftIO $ loadDirInAppState dir parentDir state
- modify (const nextState)
+ dir <- gets stateParentDir
+ modifyM (liftIO . loadDirInAppState dir (takeDirectory dir))
-appEvent :: T.BrickEvent () e -> T.EventM () AppState ()
-appEvent (T.VtyEvent e) =
- case e of
- V.EvKey V.KEsc [] -> M.halt
- V.EvKey (V.KChar 'q') [] -> M.halt
- V.EvKey (V.KChar 'l') [] -> openSelectedFile
- V.EvKey (V.KChar 'h') [] -> goBackToParentDir
- V.EvKey V.KEnter [] -> openSelectedFile
- V.EvKey V.KBS [] -> goBackToParentDir
- ev -> do
+appEvent :: T.BrickEvent FocusTarget e -> AppEvent ()
+appEvent brickevent@(T.VtyEvent event) = do
+ focusTarget <- gets stateFocusTarget
+ case (focusTarget, event) of
+ (_, V.EvKey V.KEsc []) -> modify (\st -> st {stateFocusTarget = FocusMain})
+ (_, V.EvKey (V.KChar ':') []) -> modify (\st -> st {stateFocusTarget = FocusCmdline})
+ (FocusMain, V.EvKey (V.KChar 'q') []) -> M.halt
+ (FocusMain, V.EvKey (V.KChar 'l') []) -> openSelectedFile
+ (FocusMain, V.EvKey (V.KChar 'h') []) -> goBackToParentDir
+ (FocusMain, V.EvKey V.KEnter []) -> openSelectedFile
+ (FocusMain, V.EvKey V.KBS []) -> goBackToParentDir
+ (FocusMain, _) -> do
files <- gets stateFiles
- newFiles <- T.nestEventM' files (L.handleListEventVi L.handleListEvent ev)
+ newFiles <- T.nestEventM' files (L.handleListEventVi L.handleListEvent event)
modify (\appState -> appState {stateFiles = newFiles})
+ (FocusCmdline, _) -> do
+ editor <- gets stateCmdlineEditor
+ newEditor <- T.nestEventM' editor (Editor.handleEditorEvent brickevent)
+ modify (\appState -> appState {stateCmdlineEditor = newEditor})
appEvent _ = pure ()
-app :: M.App AppState e ()
+app :: M.App AppState e FocusTarget
app =
M.App
{ M.appDraw = appView,
@@ -112,7 +117,7 @@ loadDirInAppState dir parentDir appState = do
files <- listFilesInDir dir
pure $
appState
- { stateFiles = L.list () (Vec.fromList files) 1,
+ { stateFiles = L.list FocusMain (Vec.fromList files) 1,
stateCwd = dir,
stateParentDir = parentDir
}
@@ -120,7 +125,10 @@ loadDirInAppState dir parentDir appState = do
mkEmptyAppState :: AppState
mkEmptyAppState =
AppState
- { stateFiles = L.list () (Vec.fromList []) 1,
+ { stateFiles = L.list FocusMain (Vec.fromList []) 1,
+ stateCmdlineEditor = Editor.editor FocusCmdline Nothing "",
+ stateFocusTarget = FocusMain,
+ -- stateFocusRing = focusRing [FocusMain, FocusCmdline],
stateCwd = "",
stateParentDir = ""
}
diff --git a/lib/Daffm/Attrs.hs b/lib/Daffm/Attrs.hs
index 93a4163..77f9ee6 100644
--- a/lib/Daffm/Attrs.hs
+++ b/lib/Daffm/Attrs.hs
@@ -1,17 +1,31 @@
module Daffm.Attrs where
import qualified Brick.AttrMap as A
-import Brick.Util (fg)
+import Brick.Util (bg, fg)
+import Brick.Widgets.List (listAttr, listSelectedAttr)
import qualified Brick.Widgets.List as L
import qualified Graphics.Vty as V
-selectedFileAttr :: A.AttrName
-selectedFileAttr = A.attrName "selected-file"
+fileAttr :: A.AttrName
+fileAttr = listAttr <> A.attrName "file"
+
+fileSelectedAttr :: A.AttrName
+fileSelectedAttr = listSelectedAttr <> fileAttr
+
+directoryAttr :: A.AttrName
+directoryAttr = listAttr <> A.attrName "directory"
+
+directorySelectedAttr :: A.AttrName
+directorySelectedAttr = listSelectedAttr <> directoryAttr
appAttrMap :: A.AttrMap
appAttrMap =
A.attrMap
V.defAttr
[ (L.listAttr, fg V.white),
- (selectedFileAttr, fg V.cyan)
+ (listSelectedAttr, bg V.black),
+ (directoryAttr, fg V.brightCyan),
+ (directorySelectedAttr, fg V.brightCyan),
+ (fileAttr, fg V.white),
+ (fileSelectedAttr, fg V.white)
]
diff --git a/lib/Daffm/Types.hs b/lib/Daffm/Types.hs
index 2a8e97d..5462851 100644
--- a/lib/Daffm/Types.hs
+++ b/lib/Daffm/Types.hs
@@ -1,5 +1,6 @@
module Daffm.Types where
+import qualified Brick.Widgets.Edit as Editor
import qualified Brick.Widgets.List as L
import System.Posix.Types (FileOffset)
@@ -21,8 +22,13 @@ data FileInfo = FileInfo
}
deriving (Show)
+data FocusTarget = FocusCmdline | FocusMain deriving (Show, Eq, Ord)
+
data AppState = AppState
- { stateFiles :: L.List () FileInfo,
+ { stateFiles :: L.List FocusTarget FileInfo,
+ stateCmdlineEditor :: Editor.Editor String FocusTarget,
+ stateFocusTarget :: FocusTarget,
+ -- stateFocusRing :: FocusRing FocusTarget,
stateCwd :: FilePath,
stateParentDir :: FilePath
}
diff --git a/lib/Daffm/View.hs b/lib/Daffm/View.hs
index 02529ac..db26a7d 100644
--- a/lib/Daffm/View.hs
+++ b/lib/Daffm/View.hs
@@ -1,25 +1,72 @@
module Daffm.View where
import Brick.Types (Widget)
-import Brick.Widgets.Core (str, vBox, vLimit, withAttr, (<+>))
+import Brick.Widgets.Core (Padding (Max, Pad), TextWidth (textWidth), hBox, hLimit, padLeft, padRight, str, vBox, vLimit, withAttr, (<+>))
+import Brick.Widgets.Edit (renderEditor)
import qualified Brick.Widgets.List as L
-import Daffm.Attrs (selectedFileAttr)
-import Daffm.Types (AppState (..), FileInfo (..))
+import Daffm.Attrs (directoryAttr, directorySelectedAttr, fileAttr, fileSelectedAttr)
+import Daffm.Types (AppState (..), FileInfo (..), FileType (..), FocusTarget (..))
+import Data.Int (Int64)
import qualified Data.Vector as Vec
+import Text.Printf (printf)
-appView :: AppState -> [Widget ()]
-appView (AppState {stateFiles, stateCwd}) = [ui]
+appView :: AppState -> [Widget FocusTarget]
+appView appState@(AppState {stateFiles, stateCwd}) = [ui]
where
+ ui :: Widget FocusTarget
ui = vBox [vLimit 1 header, box, vLimit 1 cmdline]
header = str stateCwd
- cmdline = str "Item " <+> cur <+> str " of " <+> total
- cur = case L.listSelected stateFiles of
- Nothing -> str "-"
- Just i -> str (show (i + 1))
- total = str $ show $ Vec.length $ L.listElements stateFiles
+ cmdline = cmdlineView appState
+ box :: Widget FocusTarget
box = L.renderList fileItemView True stateFiles
-fileItemView :: Bool -> FileInfo -> Widget ()
-fileItemView sel (FileInfo {fileName, fileSize, fileType}) =
- let wrap w = if sel then withAttr selectedFileAttr w else w
- in wrap (str fileName) <+> str (" : " <> show fileSize <> " | " <> show fileType)
+fixedColumnsStr :: Int -> Widget n -> Widget n
+fixedColumnsStr w s = hLimit w $ padRight Max s
+
+fileItemView :: Bool -> FileInfo -> Widget FocusTarget
+fileItemView sel fileInfo@(FileInfo {fileSize, fileType}) =
+ hBox
+ [ fixedColumnsStr 5 (fileTypeView fileType),
+ fixedColumnsStr 7 (fileSizeView fileSize),
+ fileNameView sel fileInfo
+ ]
+ where
+ fileSizeView = str . prettyFileSize . fromIntegral
+ fileTypeView = str . showFileType
+ showFileType Directory = "dir"
+ showFileType SymbolicLink = "link"
+ showFileType UnixSocket = "sock"
+ showFileType NamedPipe = "pipe"
+ showFileType CharacterDevice = "cdev"
+ showFileType BlockDevice = "bdev"
+ showFileType RegularFile = "file"
+
+fileNameView :: Bool -> FileInfo -> Widget FocusTarget
+fileNameView True (FileInfo {fileName, fileType = Directory}) = withAttr directorySelectedAttr $ str $ fileName <> "/"
+fileNameView False (FileInfo {fileName, fileType = Directory}) = withAttr directoryAttr $ str $ fileName <> "/"
+fileNameView True (FileInfo {fileName}) = withAttr fileSelectedAttr $ str fileName
+fileNameView False (FileInfo {fileName}) = withAttr fileAttr $ str fileName
+
+cmdlineView :: AppState -> Widget FocusTarget
+cmdlineView (AppState {stateFocusTarget = FocusCmdline, stateCmdlineEditor}) =
+ str ":" <+> renderEditor (str . unlines) True stateCmdlineEditor
+cmdlineView (AppState {stateFiles}) =
+ hBox [str ":", padLeft Max $ padRight (Pad 1) posIndicator]
+ where
+ posIndicator = str $ cur <> "/" <> total
+ cur = case L.listSelected stateFiles of
+ Nothing -> "-"
+ Just n -> show (n + 1)
+ total = show $ Vec.length $ L.listElements stateFiles
+
+prettyFileSize :: Int64 -> String
+prettyFileSize i
+ | i >= 2 ^ (40 :: Int64) = format (i `divBy` (2 ** 40)) <> "T"
+ | i >= 2 ^ (30 :: Int64) = format (i `divBy` (2 ** 30)) <> "G"
+ | i >= 2 ^ (20 :: Int64) = format (i `divBy` (2 ** 20)) <> "M"
+ | i >= 2 ^ (10 :: Int64) = format (i `divBy` (2 ** 10)) <> "K"
+ | otherwise = show i
+ where
+ format = printf "%0.1f"
+ divBy :: Int64 -> Double -> Double
+ divBy a b = (fromIntegral a :: Double) / b