aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Araps <dylan.araps@gmail.com>2026-02-28 21:52:26 +0200
committerDylan Araps <dylan.araps@gmail.com>2026-02-28 21:52:26 +0200
commit67a1c24a8661fdcbc48f72f7b65521772065d305 (patch)
tree33c1fbfe2452c23773de046b1127f4920aa5a49f
parent4fb29c95c61256f78e4b501a3c550b4c92a92a4e (diff)
dfm: add ranger style bulk rename
Also the ability to embed scripts within dfm.
-rw-r--r--README.txt6
-rwxr-xr-xbin/embed32
-rw-r--r--config_cmd.h.in33
-rw-r--r--config_key.h.in1
-rwxr-xr-xscript/bulk-rename47
-rwxr-xr-xscript/opener_ext (renamed from example/opener_ext)0
-rwxr-xr-xscript/opener_mime (renamed from example/opener_mime)0
7 files changed, 115 insertions, 4 deletions
diff --git a/README.txt b/README.txt
index 50a13ae..0971a58 100644
--- a/README.txt
+++ b/README.txt
@@ -26,7 +26,7 @@ Initial Announcement: https://dylan.gr/1772192922
* UTF8 support (minus grapheme clusters and other unruly things)
* Multiple view modes (name, size, permissions, mtime, ...)
* Multiple sort modes (name, extension, size, mtime, reverse, ...)
-* No temporary file usage
+* Ranger-style bulk rename
* Incremental as-you-type search
* Bookmarks
* Vim-like keybindings
@@ -161,7 +161,7 @@ environment, default values are derived from the config.h.in file.
bind act_cd_bookmark_[0-9] to the keys of your choosing)
- DFM_OPENER (Opener script to use when opening files. This could be
- xdg-open or a custom script (see the examples/ directory))
+ xdg-open or a custom script (see the script/ directory))
- DFM_TRASH (Program to use when trashing files)
@@ -228,7 +228,7 @@ All is the sum of the other view modes and gives an idea of what is shown:
-rwxr-xr-x 16m 4.0K .git/
-rwxr-xr-x 2h 4.0K bin/
--rwxr-xr-x 4d 4.0K example/
+-rwxr-xr-x 4d 4.0K script/
-rwxr-xr-x 32m 4.0K lib/
-rwxr-xr-x 16h 4.0K platform/
-rw-r--r-- 16m 0B .config_macro.h
diff --git a/bin/embed b/bin/embed
new file mode 100755
index 0000000..5efe6d8
--- /dev/null
+++ b/bin/embed
@@ -0,0 +1,32 @@
+#!/bin/sed -f
+#
+# Convert input to 32bit hex encoded utf8.
+#
+# Copyright (c) 2026 Dylan Araps
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+/^[[:space:]]*#/d
+s/\\/\\\\/g
+s/"/\\"/g
+s/$/\\n/
+s/^/"/
+s/$/"/
+
diff --git a/config_cmd.h.in b/config_cmd.h.in
index 5891957..3802760 100644
--- a/config_cmd.h.in
+++ b/config_cmd.h.in
@@ -25,7 +25,31 @@
// CMD_FILE_CURSOR = Ignore marks and add the name under the cursor to input.
// CMD_EXEC_MARK = Skip interactive prompt only if marks exist..
// CMD_EXEC_ROOT = Skip interactive prompt even if root.
-//
+!!
+## Shell cript can be embedded within dfm by using the embed command.
+## The script will be run in $SHELL as the argument following '-c'.
+##
+## FM_CMD(cmd_bulk_rename,
+## .prompt = CUT_NULL,
+## .left = CUT($(embed script/bulk-rename)),
+## .enter = fm_cmd_run_sh,
+## .config = CMD_MARK_DIR | CMD_MUT | CMD_EXEC,
+## )
+##
+## Another useful example is embedding your opener script.
+##
+## FM_CMD(cmd_opener,
+## .prompt = CUT_NULL,
+## .left = CUT($(embed script/opener_ext)),
+## .enter = fm_cmd_run_sh,
+## .config = CMD_MARK_DIR | CMD_EXEC,
+## )
+##
+## Shell can also be typed directly but its cumbersone to add \\n to the end of
+## each line and escape backslashes and double quotes.
+##
+## .left = CUT("echo \\"$@\\"\\n"),
+!!
// If the FM_CMD system is too limiting you can define your own functions and
// bind them to keys. The same function signature is used in navigation and
// input modes.
@@ -154,3 +178,10 @@ FM_CMD(cmd_trash,
.config = CMD_MARK_DIR | CMD_MUT | CMD_EXEC_MARK,
)
+FM_CMD(cmd_bulk_rename,
+ .prompt = CUT_NULL,
+ .left = CUT($(embed script/bulk-rename)),
+ .enter = fm_cmd_run_sh,
+ .config = CMD_MARK_DIR | CMD_MUT | CMD_EXEC,
+)
+
diff --git a/config_key.h.in b/config_key.h.in
index fde7239..cfb4253 100644
--- a/config_key.h.in
+++ b/config_key.h.in
@@ -92,6 +92,7 @@ static inline void (*fm_key(u32 cp))(struct fm *)
case 'z': return act_alt_buffer;
case 'p': return cmd_chmod;
case 'P': return cmd_chown;
+ case 'B': return cmd_bulk_rename;
case '~': return act_cd_home;
case 'Y': return cmd_copy_clipboard;
diff --git a/script/bulk-rename b/script/bulk-rename
new file mode 100755
index 0000000..3bd6c85
--- /dev/null
+++ b/script/bulk-rename
@@ -0,0 +1,47 @@
+#!/bin/sh -eu
+#
+# Interactive bulk file rename using $EDITOR.
+#
+# Copyright (c) 2026 Dylan Araps
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+case $# in 0) exit; esac
+f=${TMPDIR:=/tmp}/.dfm-brn-$$-$#
+e() { rm -f "$f" || :; exit "$1"; }
+(
+ printf '%s\n' "$@" > "$f" &&
+ "${EDITOR:=vi}" "$f" &&
+ exec 3<"$f" &&
+ for _ do
+ IFS= read -r l <&3
+ set -- "$@" "mv -f -- '$1' '${l:?line mismatch in rename file}'"
+ shift
+ done && {
+ read -r l <&3 && {
+ echo "$0: 39: line mismatch in rename file" >&2
+ return 1
+ }
+ printf '%s\n' '# This file will be executed when the editor is closed.' \
+ '# Clear the file to abort.' "$@"
+ } > "$f" &&
+ "$EDITOR" "$f" && . "$f" && e 0
+) || e 1
+
diff --git a/example/opener_ext b/script/opener_ext
index ce1699a..ce1699a 100755
--- a/example/opener_ext
+++ b/script/opener_ext
diff --git a/example/opener_mime b/script/opener_mime
index 2f7bd52..2f7bd52 100755
--- a/example/opener_mime
+++ b/script/opener_mime