From 7fc70c52f322d451e8295a12a6fbaf869a2d9a2b Mon Sep 17 00:00:00 2001 From: Akshay Nair Date: Thu, 2 Oct 2025 23:09:36 +0530 Subject: Add cmdline editor, focus switch + styling --- lib/Daffm/Attrs.hs | 22 +++++++++++++--- lib/Daffm/Types.hs | 8 +++++- lib/Daffm/View.hs | 75 ++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 86 insertions(+), 19 deletions(-) (limited to 'lib/Daffm') 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 -- cgit v1.3.1