From 48bee4a04b4496ea78645929c5fe1270a4820173 Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Wed, 24 Dec 2025 14:53:24 +0100 Subject: [PATCH] update dwim-shell-command --- .../dwim-shell-command-autoloads.el | 25 ++- .../dwim-shell-command-pkg.el | 6 +- .../dwim-shell-command.el | 4 +- .../dwim-shell-commands.el | 212 +++++++++++++----- 4 files changed, 186 insertions(+), 61 deletions(-) rename elpa/{dwim-shell-command-20250218.1720 => dwim-shell-command-20251211.1325}/dwim-shell-command-autoloads.el (95%) rename elpa/{dwim-shell-command-20250218.1720 => dwim-shell-command-20251211.1325}/dwim-shell-command-pkg.el (55%) rename elpa/{dwim-shell-command-20250218.1720 => dwim-shell-command-20251211.1325}/dwim-shell-command.el (99%) rename elpa/{dwim-shell-command-20250218.1720 => dwim-shell-command-20251211.1325}/dwim-shell-commands.el (90%) diff --git a/elpa/dwim-shell-command-20250218.1720/dwim-shell-command-autoloads.el b/elpa/dwim-shell-command-20251211.1325/dwim-shell-command-autoloads.el similarity index 95% rename from elpa/dwim-shell-command-20250218.1720/dwim-shell-command-autoloads.el rename to elpa/dwim-shell-command-20251211.1325/dwim-shell-command-autoloads.el index ba4bfd37..cc9921d6 100644 --- a/elpa/dwim-shell-command-20250218.1720/dwim-shell-command-autoloads.el +++ b/elpa/dwim-shell-command-20251211.1325/dwim-shell-command-autoloads.el @@ -126,6 +126,8 @@ Horizontally flip image(s)." t) Convert all marked images to jpg(s)." t) (autoload 'dwim-shell-commands-image-to-png "dwim-shell-commands" "\ Convert all marked images to png(s)." t) +(autoload 'dwim-shell-commands-image-to-webp "dwim-shell-commands" "\ +Convert all marked images to webp(s)." t) (autoload 'dwim-shell-commands-svg-to-png "dwim-shell-commands" "\ Convert all marked svg(s) to png(s)." t) (autoload 'dwim-shell-commands-svg-to-favicons "dwim-shell-commands" "\ @@ -146,6 +148,10 @@ Convert all marked images to grayscale." t) Reorient images." t) (autoload 'dwim-shell-commands-gif-to-video "dwim-shell-commands" "\ Convert all marked gif(s) to video(s)." t) +(autoload 'dwim-shell-commands-extract-first-video-frame "dwim-shell-commands" "\ +Extract first frame from video(s)." t) +(autoload 'dwim-shell-commands-set-video-framerate "dwim-shell-commands" "\ +Set framerate for marked video(s)." t) (autoload 'dwim-shell-commands-macos-empty-trash "dwim-shell-commands" "\ Empty macOS trash." t) (autoload 'dwim-shell-commands-macos-ocr-text-from-desktop-region "dwim-shell-commands" "\ @@ -282,12 +288,19 @@ Convert png to icns icon." t) Add a drop shadow." t) (autoload 'dwim-shell-commands-image-trim-borders "dwim-shell-commands" "\ Trim image(s) border (useful for video screenshots)." t) -(autoload 'dwim-shell-commands-git-clone-clipboard-url-to-downloads "dwim-shell-commands" "\ -Clone git URL in clipboard to \"~/Downloads/\"." t) (autoload 'dwim-shell-commands-http-serve-dir "dwim-shell-commands" "\ HTTP serve current directory." t) (autoload 'dwim-shell-commands-git-clone-clipboard-url "dwim-shell-commands" "\ -Clone git URL in clipboard to `default-directory'." t) +Clone git URL in clipboard to a directory. +With C-u ARG, prompt for directory from +`dwim-shell-commands-git-clone-dirs'. + +With C-u C-u ARG, prompt for any directory. + +Without prefix, use the first directory in +`dwim-shell-commands-git-clone-dirs'. + +(fn &optional ARG)" t) (autoload 'dwim-shell-commands-pass-git-pull "dwim-shell-commands" "\ Pass git pull." t) (autoload 'dwim-shell-commands-git-list-untracked-files "dwim-shell-commands" "\ @@ -302,7 +315,11 @@ Needs ideviceinstaller and libmobiledevice installed." t) (autoload 'dwim-shell-commands-copy-to-downloads "dwim-shell-commands" "\ Copy file to ~/Downloads." t) (autoload 'dwim-shell-commands-duplicate "dwim-shell-commands" "\ -Duplicate file." t) +Duplicate file. + +With prefix, duplicate it n TIMES. + +(fn TIMES)" t) (autoload 'dwim-shell-commands-rename-all "dwim-shell-commands" "\ Rename all marked file(s)." t) (autoload 'dwim-shell-commands-move-to-downloads "dwim-shell-commands" "\ diff --git a/elpa/dwim-shell-command-20250218.1720/dwim-shell-command-pkg.el b/elpa/dwim-shell-command-20251211.1325/dwim-shell-command-pkg.el similarity index 55% rename from elpa/dwim-shell-command-20250218.1720/dwim-shell-command-pkg.el rename to elpa/dwim-shell-command-20251211.1325/dwim-shell-command-pkg.el index 4b0f089c..6521d43e 100644 --- a/elpa/dwim-shell-command-20250218.1720/dwim-shell-command-pkg.el +++ b/elpa/dwim-shell-command-20251211.1325/dwim-shell-command-pkg.el @@ -1,7 +1,7 @@ ;; -*- no-byte-compile: t; lexical-binding: nil -*- -(define-package "dwim-shell-command" "20250218.1720" +(define-package "dwim-shell-command" "20251211.1325" "Shell commands with DWIM behaviour." '((emacs "28.1")) :url "https://github.com/xenodium/dwim-shell-command" - :commit "4b077432a94873e5f505c8f569743cfd984eebb1" - :revdesc "4b077432a948") + :commit "35ca64d529987578dbbdf3f07d34310ee727b4a5" + :revdesc "35ca64d52998") diff --git a/elpa/dwim-shell-command-20250218.1720/dwim-shell-command.el b/elpa/dwim-shell-command-20251211.1325/dwim-shell-command.el similarity index 99% rename from elpa/dwim-shell-command-20250218.1720/dwim-shell-command.el rename to elpa/dwim-shell-command-20251211.1325/dwim-shell-command.el index 425cacc1..b4ed1f34 100644 --- a/elpa/dwim-shell-command-20250218.1720/dwim-shell-command.el +++ b/elpa/dwim-shell-command-20251211.1325/dwim-shell-command.el @@ -5,8 +5,8 @@ ;; Author: Alvaro Ramirez ;; Package-Requires: ((emacs "28.1")) ;; URL: https://github.com/xenodium/dwim-shell-command -;; Package-Version: 20250218.1720 -;; Package-Revision: 4b077432a948 +;; Package-Version: 20251211.1325 +;; Package-Revision: 35ca64d52998 ;; This package is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by diff --git a/elpa/dwim-shell-command-20250218.1720/dwim-shell-commands.el b/elpa/dwim-shell-command-20251211.1325/dwim-shell-commands.el similarity index 90% rename from elpa/dwim-shell-command-20250218.1720/dwim-shell-commands.el rename to elpa/dwim-shell-command-20251211.1325/dwim-shell-commands.el index 7984af97..06f78261 100644 --- a/elpa/dwim-shell-command-20250218.1720/dwim-shell-commands.el +++ b/elpa/dwim-shell-command-20251211.1325/dwim-shell-commands.el @@ -84,10 +84,7 @@ done" (if prefix "true" "false") - prefix - (if prefix - "true" - "false")) + prefix) :utils "jq" :extensions "har")) @@ -296,6 +293,15 @@ Optional argument ARGS as per `browse-url-default-browser'" "convert -verbose '<>' '<>.png'" :utils "convert")) +;;;###autoload +(defun dwim-shell-commands-image-to-webp () + "Convert all marked images to webp(s)." + (interactive) + (dwim-shell-command-on-marked-files + "Convert to png" + "convert -verbose '<>' '<>.webp'" + :utils "convert")) + ;;;###autoload (defun dwim-shell-commands-svg-to-png () "Convert all marked svg(s) to png(s)." @@ -416,6 +422,26 @@ Optional argument ARGS as per `browse-url-default-browser'" "ffmpeg -i '<>' -movflags faststart -pix_fmt yuv420p -vf 'scale=trunc(iw/2)*2:trunc(ih/2)*2' '<>.mp4'" :utils "ffmpeg")) +;;;###autoload +(defun dwim-shell-commands-extract-first-video-frame () + "Extract first frame from video(s)." + (interactive) + (dwim-shell-command-on-marked-files + "Convert to gif" + "ffmpeg -i '<>' -vframes 1 -q:v 2 '<>.jpg'" + :utils "ffmpeg")) + +;;;###autoload +(defun dwim-shell-commands-set-video-framerate () + "Set framerate for marked video(s)." + (interactive) + (dwim-shell-command-on-marked-files + "Set video framerate" + (let ((fps (read-number "Target framerate (fps): " 30))) + (format "ffmpeg -i '<>' -r %d -c:a copy '<>_%dfps.<>'" + fps fps)) + :utils "ffmpeg")) + ;;;###autoload (defun dwim-shell-commands-macos-empty-trash () "Empty macOS trash." @@ -504,7 +530,7 @@ Optional argument ARGS as per `browse-url-default-browser'" (interactive) (dwim-shell-command-on-marked-files "Convert to webp" - "ffmpeg -i '<>' -vcodec libwebp -filter:v fps=fps=10 -compression_level 3 -lossless 1 -loop 0 -preset default -an -vsync 0 '<>'.webp" + "ffmpeg -i '<>' -vcodec libwebp -filter:v fps=fps=10 -compression_level 3 -loop 0 -preset default -an -vsync 0 '<>'.webp" :utils "ffmpeg")) ;;;###autoload @@ -754,8 +780,10 @@ EOF" (cons (nth 1 (split-string device " - ")) (nth 0 (split-string device " - ")))) devices)) - (selected-name (completing-read "Toggle connection: " - (seq-sort #'string-lessp candidates) nil t)) + (selected-name (completing-read "Toggle BT connection: " + (seq-sort (lambda (a b) + (string-lessp (car a) (car b))) + candidates) nil t)) (address (map-elt candidates selected-name))) (dwim-shell-command-on-marked-files (format "Toggle %s" selected-name) @@ -896,7 +924,6 @@ fi" source) ".org")) (fields (with-temp-buffer (insert-file-contents source) - (buffer-substring-no-properties (point-min) (line-end-position)) (read-string "Fields: " (mapconcat 'identity (mapcar (lambda (item) (symbol-name (car item))) (json-read-from-string @@ -977,11 +1004,10 @@ fi" (defun dwim-shell-commands-video-to-thumbnail () "Generate a thumbnail for marked video(s)." (interactive) - (let ((temp-dir (make-temp-file "thumbnails-" t))) - (dwim-shell-command-on-marked-files - "Thumbnail with ffmpeg" - "ffmpeg -i '<>' -ss 00:00:01.000 -vframes 1 '<>.jpg'" - :utils "ffmpeg"))) + (dwim-shell-command-on-marked-files + "Thumbnail with ffmpeg" + "ffmpeg -i '<>' -ss 00:00:01.000 -vframes 1 '<>.jpg'" + :utils "ffmpeg")) ;;;###autoload (defun dwim-shell-commands-drop-video-audio () @@ -1374,13 +1400,14 @@ echo \"<>.svg\" (inhibit-message t)) ;; Silence echo to avoid unrelated messages making into animation. (cl-letf (((symbol-function 'dwim-shell-command--message) - (lambda (fmt &rest args) nil))) + (lambda (_fmt &rest _args) nil))) (dwim-shell-command-on-marked-files "Start recording a macOS window." (format "macosrec --record '%s' --gif --output '<>'" (cdr window)) :silent-success t + :focus-now nil :monitor-directory "~/Screenshots" :no-progress t :utils '("ffmpeg" "macosrec") @@ -1423,7 +1450,7 @@ echo \"<>.svg\" (interactive) (let ((inhibit-message t)) (cl-letf (((symbol-function 'dwim-shell-command--message) - (lambda (fmt &rest args) nil))) + (lambda (_fmt &rest _args) nil))) (dwim-shell-command-on-marked-files "End recording macOS window." "macosrec --save" @@ -1438,7 +1465,7 @@ echo \"<>.svg\" (interactive) (let ((inhibit-message t)) (cl-letf (((symbol-function 'dwim-shell-command--message) - (lambda (fmt &rest args) nil))) + (lambda (_fmt &rest _args) nil))) (dwim-shell-command-on-marked-files "Abort recording macOS window." "macosrec --abort" @@ -1519,28 +1546,6 @@ echo \"<>.svg\" "magick convert -fuzz 3% -define trim:percent-background=0% -trim +repage '<>' '<>_trimmed.<>'" :utils "magick")) -;;;###autoload -(defun dwim-shell-commands-git-clone-clipboard-url-to-downloads () - "Clone git URL in clipboard to \"~/Downloads/\"." - (interactive) - (cl-assert (or (string-match-p "^\\(http\\|https\\|ssh\\)://" (current-kill 0)) - (string-match-p "^git@" (current-kill 0))) nil "No URL in clipboard") - (let* ((url (current-kill 0)) - (download-dir (expand-file-name "~/Downloads/")) - (project-dir (concat download-dir (file-name-base url))) - (default-directory download-dir)) - (when (or (not (file-exists-p project-dir)) - (when (y-or-n-p (format "%s exists. delete?" (file-name-base url))) - (delete-directory project-dir t) - t)) - (dwim-shell-command-on-marked-files - (format "Clone %s" (file-name-base url)) - (format "git clone %s" url) - :utils "git" - :on-completion (lambda (buffer _process) - (kill-buffer buffer) - (dired project-dir)))))) - ;;;###autoload (defun dwim-shell-commands-http-serve-dir () "HTTP serve current directory." @@ -1569,14 +1574,67 @@ echo \"<>.svg\" (t (error "No python found")))) +(defcustom dwim-shell-commands-git-clone-dirs + '("~/Downloads" "~/Desktop") + "List of directories where git repositories can be cloned. +The first directory is used as the default." + :type '(repeat directory) + :group 'dwim-shell-commands) + ;;;###autoload -(defun dwim-shell-commands-git-clone-clipboard-url () - "Clone git URL in clipboard to `default-directory'." - (interactive) - (dwim-shell-command-on-marked-files - (format "Clone %s" (file-name-base (current-kill 0))) - "git clone <>" - :utils "git")) +(defun dwim-shell-commands-git-clone-clipboard-url (&optional arg) + "Clone git URL in clipboard to a directory. +With C-u ARG, prompt for directory from +`dwim-shell-commands-git-clone-dirs'. + +With C-u C-u ARG, prompt for any directory. + +Without prefix, use the first directory in +`dwim-shell-commands-git-clone-dirs'." + (interactive "P") + (unless (or (string-match-p "^\\(?:http\\|https\\|ssh\\|git\\)://" (string-trim (current-kill 0))) + (string-match-p "^git@" (string-trim (current-kill 0)))) + (user-error "No URL in clipboard")) + (let* ((url (string-trim (current-kill 0))) + (current-dir (abbreviate-file-name + (directory-file-name default-directory))) + (fallback-dir (car dwim-shell-commands-git-clone-dirs)) + (candidates (append (list (cons fallback-dir fallback-dir)) + (list (cons (concat current-dir " (current)") current-dir)) + (mapcar (lambda (dir) + (cons dir dir)) + (cdr dwim-shell-commands-git-clone-dirs)))) + (target-dir (cond + ;; C-u prefix - Choose from `dwim-shell-commands-git-clone-dirs' + ((equal arg '(4)) + (expand-file-name + (map-elt candidates + (completing-read "Clone repo to: " candidates + nil t)))) + ;; C-u C-u prefix - Choose any directory + ((equal arg '(16)) + (expand-file-name + (read-directory-name "Clone repo to: " nil nil t))) + ;; Default to using first in `dwim-shell-commands-git-clone-dirs' + (t + (expand-file-name fallback-dir)))) + (base-name (file-name-base url)) + (project-dir (dwim-shell-command--unique-new-file-path + (concat (file-name-as-directory target-dir) base-name))) + (default-directory target-dir)) + (dwim-shell-command-on-marked-files + (format "Clone %s" (file-name-base url)) + (format "git clone %s %s" + (shell-quote-argument url) + (shell-quote-argument (file-name-nondirectory project-dir))) + :monitor-directory target-dir + :utils "git" + :on-completion (lambda (buffer _) + (kill-buffer buffer) + (dired project-dir) + (goto-char (point-min)) + (when (re-search-forward "README" nil t) + (beginning-of-line)))))) ;;;###autoload (defun dwim-shell-commands-pass-git-pull () @@ -1642,13 +1700,29 @@ Needs ideviceinstaller and libmobiledevice installed." :monitor-directory "~/Downloads")) ;;;###autoload -(defun dwim-shell-commands-duplicate () - "Duplicate file." - (interactive) - (dwim-shell-command-on-marked-files - "Duplicate file(s)." - "cp -R '<>' '<>'" - :utils "cp")) +(defun dwim-shell-commands-duplicate (times) + "Duplicate file. + +With prefix, duplicate it n TIMES." + (interactive "p") + (dwim-shell-commands--duplicate (list times))) + +(defun dwim-shell-commands--duplicate (remaining) + "Helper using REMAINING as a list to share recursion state." + (let ((current-buffer (current-buffer))) + (dwim-shell-command-on-marked-files + "Duplicate file(s)." + "cp -R '<>' '<>'" + :utils "cp" + :on-completion + (lambda (buffer _process) + (kill-buffer buffer) + (setcar remaining (1- (car remaining))) + (if (> (car remaining) 0) + (with-current-buffer current-buffer + (dwim-shell-commands--duplicate remaining)) + (dired-jump nil (with-current-buffer current-buffer + default-directory))))))) ;;;###autoload (defun dwim-shell-commands-rename-all () @@ -1714,6 +1788,40 @@ gpg: decryption failed: No pinentry" :utils "gpgconf" :silent-success t)) +(defun dwim-shell-commands-upload-to-tmpfiles-org () + "Upload the marked files to 0x0.st" + (interactive) + (dwim-shell-command-on-marked-files + "0x0 upload" + "curl -Ffile=@<> -Fsecret= https://tmpfiles.org/api/v1/upload" + :utils "curl" + :post-process-template + ;; The placement of required single quotes confuse the escaping + ;; mechanisms of dwim-shell-command, as it considers @ as the + ;; opening 'quote' because it appears in front of <>. + ;; + ;; What we want is: + ;; + ;; curl -F'file=@yourfile.png' -Fsecret= https://tmpfiles.org/api/v1/upload + (lambda (template path) + (string-replace "-Ffile" "-F'file" + (string-replace path (concat path "'") template))) + :on-completion + (lambda (buffer process) + (if (= (process-exit-status process) 0) + (with-current-buffer buffer + (if-let* ((json (condition-case nil + (json-read-from-string (buffer-string)) + (error nil))) + (success (equal (map-elt json 'status) "success"))) + (progn + (eww (map-nested-elt json '(data url))) + (kill-new (map-nested-elt json '(data url))) + (message "Copied: %s" (current-kill 0)) + (kill-buffer buffer)) + (switch-to-buffer buffer))) + (switch-to-buffer buffer))))) + ;; Based on ;; https://apps.bram85.nl/git/bram/gists/src/commit/31ac3363da925daafa2420b7f96c67612ca28241/gists/dwim-0x0-upload.el ;;;###autoload -- 2.47.3