Skip to content

Instantly share code, notes, and snippets.

@genegoykhman
Created July 31, 2023 17:56
Show Gist options
  • Save genegoykhman/09868acd369b3fae866be6446997de9f to your computer and use it in GitHub Desktop.
Save genegoykhman/09868acd369b3fae866be6446997de9f to your computer and use it in GitHub Desktop.
Enabled TRAMP completion for Docker containers at the end of a multi-hop connection
;; -*- mode: lisp-interaction; -*-
;; Load tramp variables
(require 'tramp)
;; Disable TRAMP caching so we don't see unavailable containers
(setq tramp-completion-use-cache nil)
;; My tramp completion function, that tries to set the correct
;; default-directory so we run "docker" on the remote host
(defun my-tramp-container-completion-function (program)
"List running containers available for connection.
PROGRAM is the program to be run for \"ps\", either
`tramp-docker-program' or `tramp-podman-program'.
This function is used by `tramp-set-completion-function', please
see its function help for a description of the format."
(when-let ((default-directory (if tramp-last-hop-directory
tramp-last-hop-directory
tramp-compat-temporary-file-directory))
(raw-list (shell-command-to-string
(concat program " ps --format '{{.ID}}\t{{.Names}}'")))
(lines (split-string raw-list "\n" 'omit))
(names (mapcar
(lambda (line)
(when (string-match
(rx bol (group (1+ nonl))
"\t" (? (group (1+ nonl))) eol)
line)
(or (match-string 2 line) (match-string 1 line))))
lines)))
(mapcar (lambda (name) (list nil name)) (delq nil names))))
;; Adds my completion function to TRAMP completion functions list
(add-to-list 'tramp-completion-function-alist
`("docker"
(tramp-container--completion-function ,tramp-docker-program)
(my-tramp-container-completion-function ,tramp-docker-program)))
(defun my-tramp-docker-host-path (orig)
;; Strips off "|docker" suffix from ORIG allowing
;; it to be converted to a tramp-file using TRAMP's path functions.
(let ((regexp "\\(.*\\)|docker"))
(if (string-match regexp orig)
(concat (match-string 1 orig) ":/")
orig)))
;; When TRAMP handles completions, first set tramp-last-hop-directory
;; so that my completion function can set it before running the Docker executable
(defun my-tramp-set-docker-default-directory (filename directory)
(setq tramp-last-hop-directory nil)
(let ((my-host-path (my-tramp-docker-host-path directory)))
(when (tramp-tramp-file-p my-host-path)
(setq tramp-last-hop-directory (tramp-make-tramp-file-name
(tramp-dissect-file-name my-host-path))))))
(advice-add #'tramp-completion-handle-file-name-all-completions :before #'my-tramp-set-docker-default-directory)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment