diff options
| -rw-r--r-- | README.md | 54 | ||||
| -rw-r--r-- | daffm.cabal | 1 | ||||
| -rw-r--r-- | exe/Main.hs | 64 | ||||
| -rw-r--r-- | lib/Daffm.hs | 26 | ||||
| -rw-r--r-- | lib/Daffm/Args.hs | 44 | ||||
| -rw-r--r-- | lib/Daffm/Types.hs | 7 | ||||
| -rw-r--r-- | notes.org | 1 |
7 files changed, 119 insertions, 78 deletions
@@ -1,5 +1,8 @@ # Daffm -Dumb as fuck file manager is a minimal tui file manager +Dumb as fuck file manager is a minimal tui file manager with the goal of not being a file manager. +At its core, it only provides a directory browser, providing ways to conviniently run shell commands to manage your files via keybinds and command line input. + +(documentation wip)  @@ -9,12 +12,11 @@ Dumb as fuck file manager is a minimal tui file manager ## Config -Configuration is managed in toml. -By default it will try to load `$XDG_CONFIG_HOME/daffm/config.toml`. +Configuration is written in toml. By default it will try to load `$XDG_CONFIG_HOME/daffm/config.toml`. You can load config in a different path using `daffm -c <path-to-config>`. You can also store alternate configs in `$XDG_CONFIG_HOME/daffm/config.custom-thing.toml` and load it as `daffm -c @custom-thing`. -Heres an example config for reference: +Here's an example config for reference: ```toml # `opener` runs when opening a file or selections @@ -32,17 +34,37 @@ gdl = "cd ~/Downloads" gdc = "cd ~/Documents" gp = "cd ~/Pictures" -rn = "!!echo '%F' | vidir -v -" # Uses vidir (moreutils) to rename selected files/directories +# File management +rn = ["!!clear; echo '%F' | vidir -v -", "selection-clear"] # Uses vidir (moreutils) to rename current or selected files md = "cmdline-set !mkdir -p " # Prefills cmdline mf = "cmdline-set !touch " -dd = "!rm -rfi %f" -sdd = "!sudo rm -rfi %f" -cp = "cmdline-set !cp -f % %" +dd = "!!clear; rm -rfIv %f" +sdd = "!!clear; sudo rm -rfIv %f" +cc = ["!!cp % %.dup", "selection-clear"] +cp = ["!!cp -irv %s -t %d", "selection-clear"] +mv = ["!!mv -iv %s -t %d", "selection-clear"] -# Copes file to clipboard -"<space>yy" = """! -xclip -selection clipboard -t $(file --mime-type '%' -bL) -i '%' +# Copy absolute file path to clipboard +YY = "!echo -n % | xclip -selection clipboard" +# Copy relative file path to clipboard (Relative to DAFFM_PATH_RELATIVE_TO or cwd) +yy = """shell +relpath=$(realpath -s --relative-to="${DAFFM_PATH_RELATIVE_TO:-$PWD}" %) +echo -n "$relpath" | xclip -selection clipboard +""" +# Copy entire file to clipboard +yf = """shell +xclip -selection clipboard -t $(file --mime-type % -bL) -i % """ + +# View image inside terminal +"<space>p" = "!!clear; chafa -f kitty %" + +# Poor man's marks (mark directory by creating a binding) +# m1 marks current directory and <space>1 jumps to that directory +m1 = """command-shell echo "<daffm>map <space>1 cd %d" """ +m2 = """command-shell echo "<daffm>map <space>2 cd %d" """ +m3 = """command-shell echo "<daffm>map <space>3 cd %d" """ +m4 = """command-shell echo "<daffm>map <space>4 cd %d" """ ``` The substituions (%,%f,%s,%F,%S) are replaced with absolute file paths @@ -61,13 +83,23 @@ q = "quit" rr = "reload" "!" = "cmdline-set !" ":" = "cmdline-enter" + +# Search in directory +"/" = "cmdline-set search " +n = "search-next" +N = "search-prev" + +# Navigation (j/k for up/down) l = "open" h = "back" "<cr>" = "open" "<bs>" = "back" + +# Selection v = "selection-toggle" # select/unselect files "<tab>" = "selection-toggle" C = "selection-clear" + "~" = "cd ~" gh = "cd ~" # Go home "$" = "$SHELL" # drop to shell diff --git a/daffm.cabal b/daffm.cabal index 7d677cd..e8e9abe 100644 --- a/daffm.cabal +++ b/daffm.cabal @@ -64,6 +64,7 @@ library lib-daffm Daffm.Action.Commands Daffm.Action.Core Daffm.Action.Keymap + Daffm.Args Daffm.Attrs Daffm.Configuration Daffm.Event diff --git a/exe/Main.hs b/exe/Main.hs index e150569..6a85858 100644 --- a/exe/Main.hs +++ b/exe/Main.hs @@ -1,71 +1,21 @@ module Main where -import qualified Brick.Main as M -import Control.Exception (throwIO) -import Control.Monad (void) import qualified Daffm +import qualified Daffm.Args as Args import Daffm.Configuration (loadConfigFile) +import Daffm.Types import Data.Maybe (fromMaybe) import qualified Data.Text as Text import System.Directory (getCurrentDirectory) import System.Environment (getArgs) -data Args = Args - { argsDirOrFile :: Maybe Text.Text, - argsConfigFile :: Maybe FilePath, - argsHelp :: Bool - } - deriving (Show) - main :: IO () -main = do - args <- getArgs >>= parseArgs - evaluate args +main = getArgs >>= Args.parseArgs >>= evaluateArgs -evaluate :: Args -> IO () -evaluate (Args {argsHelp = True}) = putStrLn helpMenuContents -evaluate (Args {argsDirOrFile, argsConfigFile}) = do +evaluateArgs :: Args -> IO () +evaluateArgs (Args {argsHelp = True}) = putStrLn Args.helpMenuContents +evaluateArgs (Args {argsDirOrFile, argsConfigFile}) = do cwd <- getCurrentDirectory config <- loadConfigFile argsConfigFile let dir = fromMaybe (Text.pack cwd) argsDirOrFile - initialState <- Daffm.loadDirToState dir $ Daffm.mkEmptyAppState config - void $ M.defaultMain Daffm.app initialState - -parseArgs :: [String] -> IO Args -parseArgs rawArgs = case parsedArgs of - Left e -> throwIO $ userError e - Right v -> pure v - where - parsedArgs = parse rawArgs (Args {argsDirOrFile = Nothing, argsConfigFile = Nothing, argsHelp = False}) - parse :: [String] -> Args -> Either String Args - parse [] args = Right args - parse ("-h" : _) args = Right $ args {argsHelp = True} - parse ("--help" : _) args = Right $ args {argsHelp = True} - parse ["-c"] _ = Left "Missing value for -c arg" - parse ("-c" : config : rest) args = parse rest $ args {argsConfigFile = Just config} - parse ["--config"] _ = Left "Missing value for --config arg" - parse ("--config" : config : rest) args = parse rest $ args {argsConfigFile = Just config} - parse (flag@('-' : _) : _) _ = Left $ "Invalid flag " <> flag - parse (dir : rest) args = parse rest $ args {argsDirOrFile = Just $ Text.pack dir} - -helpMenuContents :: String -helpMenuContents = - unlines - [ "daffm - Dumb as-fuck file manager", - "", - "Usage: daffm [options] [dir]", - "", - "Arguments:", - " [dir]", - " Directory or file path to load. Defaults to current working directory", - "", - "Options:", - " -c, --config <CONFIG-PATH>", - " Load toml config from file", - " If path is prefixed with @, will use alternate config", - " Ex: -c @foo will load $XDG_CONFIG_HOME/daffm/config.foo.toml", - " Default: $XDG_CONFIG_HOME/daffm/config.toml", - "", - " -h, --help", - " This help menu" - ] + Daffm.initApp dir config diff --git a/lib/Daffm.hs b/lib/Daffm.hs index afdba11..a4ced9f 100644 --- a/lib/Daffm.hs +++ b/lib/Daffm.hs @@ -1,18 +1,24 @@ -module Daffm (app, loadDirToState, mkEmptyAppState) where +module Daffm (initApp, loadDirToState, mkEmptyAppState) where -import qualified Brick.Main as M +import qualified Brick.Main as B +import Control.Monad (void) import Daffm.Attrs (appAttrMap) import Daffm.Event (appEvent) import Daffm.State (loadDirToState, mkEmptyAppState) -import Daffm.Types (AppState (..), FocusTarget) +import Daffm.Types (AppState (..), Configuration, FilePathText, FocusTarget) import Daffm.View (appView) -app :: M.App AppState e FocusTarget +app :: B.App AppState e FocusTarget app = - M.App - { M.appDraw = appView, - M.appChooseCursor = M.showFirstCursor, - M.appHandleEvent = appEvent, - M.appStartEvent = pure (), - M.appAttrMap = const appAttrMap + B.App + { B.appDraw = appView, + B.appChooseCursor = B.showFirstCursor, + B.appHandleEvent = appEvent, + B.appStartEvent = pure (), + B.appAttrMap = const appAttrMap } + +initApp :: FilePathText -> Configuration -> IO () +initApp dir config = do + initialState <- loadDirToState dir $ mkEmptyAppState config + void $ B.defaultMain app initialState diff --git a/lib/Daffm/Args.hs b/lib/Daffm/Args.hs new file mode 100644 index 0000000..aeaead7 --- /dev/null +++ b/lib/Daffm/Args.hs @@ -0,0 +1,44 @@ +module Daffm.Args where + +import Control.Exception (throwIO) +import Daffm.Types +import qualified Data.Text as Text + +parseArgs :: [String] -> IO Args +parseArgs rawArgs = case parsedArgs of + Left e -> throwIO $ userError e + Right v -> pure v + where + parsedArgs = parse rawArgs (Args {argsDirOrFile = Nothing, argsConfigFile = Nothing, argsHelp = False}) + parse :: [String] -> Args -> Either String Args + parse [] args = Right args + parse ("-h" : _) args = Right $ args {argsHelp = True} + parse ("--help" : _) args = Right $ args {argsHelp = True} + parse ["-c"] _ = Left "Missing value for -c arg" + parse ("-c" : config : rest) args = parse rest $ args {argsConfigFile = Just config} + parse ["--config"] _ = Left "Missing value for --config arg" + parse ("--config" : config : rest) args = parse rest $ args {argsConfigFile = Just config} + parse (flag@('-' : _) : _) _ = Left $ "Invalid flag " <> flag + parse (dir : rest) args = parse rest $ args {argsDirOrFile = Just $ Text.pack dir} + +helpMenuContents :: String +helpMenuContents = + unlines + [ "daffm - Dumb as-fuck file manager", + "", + "Usage: daffm [options] [dir]", + "", + "Arguments:", + " [dir]", + " Directory or file path to load. Defaults to current working directory", + "", + "Options:", + " -c, --config <CONFIG-PATH>", + " Load toml config from file", + " If path is prefixed with @, will use alternate config", + " Ex: -c @foo will load $XDG_CONFIG_HOME/daffm/config.foo.toml", + " Default: $XDG_CONFIG_HOME/daffm/config.toml", + "", + " -h, --help", + " This help menu" + ] diff --git a/lib/Daffm/Types.hs b/lib/Daffm/Types.hs index b916c79..3fd7086 100644 --- a/lib/Daffm/Types.hs +++ b/lib/Daffm/Types.hs @@ -103,6 +103,13 @@ instance Semigroup Configuration where configTheme = configTheme a <> configTheme b } +data Args = Args + { argsDirOrFile :: Maybe Text.Text, + argsConfigFile :: Maybe FilePath, + argsHelp :: Bool + } + deriving (Show) + defaultConfiguration :: Configuration defaultConfiguration = Configuration @@ -32,6 +32,7 @@ - [X] cd into dir symlinks - [X] Command: map - [ ] theme from config +- [ ] shorten/trim from left in header for long paths - [ ] cmdline tab completion - [ ] Allow escaping % in commands - [ ] Cmdline history |
