aboutsummaryrefslogtreecommitdiff
path: root/modules/system-utils.el
diff options
context:
space:
mode:
Diffstat (limited to 'modules/system-utils.el')
-rw-r--r--modules/system-utils.el111
1 files changed, 57 insertions, 54 deletions
diff --git a/modules/system-utils.el b/modules/system-utils.el
index 29076f6d..86c2ae16 100644
--- a/modules/system-utils.el
+++ b/modules/system-utils.el
@@ -55,43 +55,50 @@
;;; ------------------------------- Open File With ------------------------------
;; TASK: Favor this method over cj/open-this-file-with and add to custom buffer funcs
+(defun cj/--file-from-context (&optional explicit-filename)
+ "Return a file path from the current context, or nil.
+Resolves in priority order:
+ 1. EXPLICIT-FILENAME, if non-nil.
+ 2. `buffer-file-name' of the current buffer.
+ 3. The file at point if the current buffer is in dired-mode.
+Returns nil when none of these yield a file."
+ (or explicit-filename
+ buffer-file-name
+ (and (derived-mode-p 'dired-mode)
+ (dired-file-name-at-point))))
+
+(defun cj/--open-with-is-launcher-p (command)
+ "Return non-nil if COMMAND is a desktop launcher.
+Launchers (xdg-open, open, start) need to be called with `call-process'
+and a zero BUFFER argument so they fully detach from Emacs. Other
+commands get `start-process-shell-command' so their output is visible."
+ (and (member command '("xdg-open" "open" "start")) t))
+
(defun cj/open-file-with-command (command)
"Open the current file with COMMAND.
-Works in both Dired buffers and regular file buffers. The command runs
-fully detached from Emacs."
+Works in both Dired buffers and regular file buffers. Prompts for a
+file only when neither context yields one. The command runs fully
+detached from Emacs."
(interactive "MOpen with command: ")
- (let* ((file (cond
- ;; In dired/dirvish mode, get file at point
- ((derived-mode-p 'dired-mode)
- (dired-get-file-for-visit))
- ;; In a regular file buffer
- (buffer-file-name
- buffer-file-name)
- ;; Fallback - prompt for file
- (t
- (read-file-name "File to open: "))))
- ;; For xdg-open and similar launchers, we need special handling
- (is-launcher (member command '("xdg-open" "open" "start"))))
- ;; Validate file exists
- (unless (and file (file-exists-p file))
- (error "No valid file found or selected"))
- ;; Use different approaches for launchers vs regular commands
- (if is-launcher
- ;; For launchers, use call-process with 0 to fully detach
- (progn
- (call-process command nil 0 nil file)
- (message "Opening %s with %s..." (file-name-nondirectory file) command))
- ;; For other commands, use start-process-shell-command for potential output
- (let* ((output-buffer-name (format "*Open with %s: %s*"
- command
- (file-name-nondirectory file)))
- (output-buffer (generate-new-buffer output-buffer-name)))
- (start-process-shell-command
- command
- output-buffer
- (format "%s %s" command (shell-quote-argument file)))
- (message "Running %s on %s..." command (file-name-nondirectory file))))))
-
+ (let* ((file (or (cj/--file-from-context)
+ (read-file-name "File to open: "))))
+ (unless (and file (file-exists-p file))
+ (error "No valid file found or selected"))
+ (if (cj/--open-with-is-launcher-p command)
+ (progn
+ (call-process command nil 0 nil file)
+ (message "Opening %s with %s..."
+ (file-name-nondirectory file) command))
+ (let* ((output-buffer-name (format "*Open with %s: %s*"
+ command
+ (file-name-nondirectory file)))
+ (output-buffer (generate-new-buffer output-buffer-name)))
+ (start-process-shell-command
+ command
+ output-buffer
+ (format "%s %s" command (shell-quote-argument file)))
+ (message "Running %s on %s..."
+ (file-name-nondirectory file) command)))))
(defun cj/identify-external-open-command ()
"Return the OS-default \"open\" command for this host.
@@ -107,26 +114,22 @@ Signals an error if the host is unsupported."
Logs output and exit code to buffer *external-open.log*."
(interactive)
(let* ((file (expand-file-name
- (or filename
- buffer-file-name
- (and (derived-mode-p 'dired-mode) (dired-file-name-at-point))
- (user-error "No file associated with this buffer"))))
- (cmd (cj/identify-external-open-command))
- (logbuf (get-buffer-create "*external-open.log*")))
- (with-current-buffer logbuf
- (goto-char (point-max))
- (insert (format-time-string "[%Y-%m-%d %H:%M:%S] "))
- (insert (format "Opening: %s\n" file)))
- (cond
- ;; Windows: let the shell handle association; fully detached.
- ((env-windows-p)
- (w32-shell-execute "open" file))
- ;; macOS/Linux: run the opener synchronously; it returns immediately.
- (t
- (call-process cmd nil 0 nil file)
- (with-current-buffer logbuf
- (insert " → Launched asynchronously\n"))))
- nil))
+ (or (cj/--file-from-context filename)
+ (user-error "No file associated with this buffer"))))
+ (cmd (cj/identify-external-open-command))
+ (logbuf (get-buffer-create "*external-open.log*")))
+ (with-current-buffer logbuf
+ (goto-char (point-max))
+ (insert (format-time-string "[%Y-%m-%d %H:%M:%S] "))
+ (insert (format "Opening: %s\n" file)))
+ (cond
+ ((env-windows-p)
+ (w32-shell-execute "open" file))
+ (t
+ (call-process cmd nil 0 nil file)
+ (with-current-buffer logbuf
+ (insert " → Launched asynchronously\n"))))
+ nil))
;;; ------------------------------ Server Shutdown ------------------------------