;;; duet.el --- Dual-pane file commander over dirvish/dired -*- lexical-binding: t -*- ;; Author: Craig Jennings ;; URL: https://github.com/cjennings/duet ;; Version: 0.1.0 ;; Package-Requires: ((emacs "29.1")) ;; Keywords: files, tools, convenience ;; This file is not part of GNU Emacs. ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;;; Commentary: ;; DUET — "DUET Unifies Endpoint Trees" — is a two-pane orthodox file ;; manager (Midnight Commander / FileZilla style) built on dirvish/dired. ;; Two dired panes show any location, local or remote; single-key actions ;; on the file under point use the opposite pane as the implied target. ;; ;; Transfers route through a pluggable backend registry: rsync for ;; Unix-to-Unix (delta-transfer, faithful metadata, zero remote install), ;; rclone for cloud and the long protocol tail, lftp for FTP/FTPS/HTTP, and ;; unison for bidirectional sync. TRAMP is the universal substrate. ;; ;; dirvish is recommended as the renderer but not required; DUET degrades to ;; plain dired. ;; ;; STATUS: pre-alpha skeleton. See the design document for the full plan and ;; the staged roadmap. ;;; Code: (require 'tramp) (defgroup duet nil "Dual-pane file commander over dirvish/dired." :group 'files :prefix "duet-") ;;; Path classification (defun duet--classify-path (path) "Classify PATH into a plist describing its locality and components. The returned plist has these keys: :locality `local' or `remote' :method TRAMP method (e.g. \"ssh\"), or nil when local :user remote user, or nil :host remote host (the final hop for a multi-hop path), or nil :port remote port as a string, or nil :localname the path on the target filesystem :hop the leading-hops string for a multi-hop path, or nil TRAMP performs the dissection, so any path `file-remote-p' recognizes is remote and everything else is local. A local PATH has its name expanded \(so a leading ~ resolves to the home directory); a remote localname is kept verbatim because a ~ there is the remote home, not this machine's. Classification is total: a TRAMP-looking string TRAMP does not accept as a remote name (an incomplete \"/ssh:host\") is treated as a local path rather than signaling. Validating raw TRAMP input is the connection reader's job." (if (file-remote-p path) (let ((v (tramp-dissect-file-name path))) (list :locality 'remote :method (tramp-file-name-method v) :user (tramp-file-name-user v) :host (tramp-file-name-host v) :port (tramp-file-name-port v) :localname (tramp-file-name-localname v) :hop (tramp-file-name-hop v))) (list :locality 'local :method nil :user nil :host nil :port nil :localname (expand-file-name path) :hop nil))) ;;;###autoload (defun duet () "Launch the DUET dual-pane file commander." (interactive) (user-error "DUET is not yet implemented — see the design document")) (provide 'duet) ;;; duet.el ends here