aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2025-10-08 12:51:02 +0530
committerAkshay Nair <phenax5@gmail.com>2025-10-08 13:10:49 +0530
commit4e8e81b05afa4ba56d64ba714c78ba307f936076 (patch)
tree3d481ce541ea8d5b46cb9e3debcaf1db8a112415
parente173e1f105e72e06c6a3206b9b94f4f1da63b00f (diff)
downloaddaffm-4e8e81b05afa4ba56d64ba714c78ba307f936076.tar.gz
daffm-4e8e81b05afa4ba56d64ba714c78ba307f936076.zip
Refactor args parsing to module + docs update
-rw-r--r--README.md54
-rw-r--r--daffm.cabal1
-rw-r--r--exe/Main.hs64
-rw-r--r--lib/Daffm.hs26
-rw-r--r--lib/Daffm/Args.hs44
-rw-r--r--lib/Daffm/Types.hs7
-rw-r--r--notes.org1
7 files changed, 119 insertions, 78 deletions
diff --git a/README.md b/README.md
index 0647cb9..4654b65 100644
--- a/README.md
+++ b/README.md
@@ -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)
![screenshot](./media/screenshot.jpg)
@@ -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
diff --git a/notes.org b/notes.org
index 31dac02..8f746d3 100644
--- a/notes.org
+++ b/notes.org
@@ -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