Is there an easy way to select (via buffer-name regex or similar) a subset of terminals in elisp, and then squirt the same command into each one?
Sure Gaz, that sounds fairly straightforward. The shell wrappers already stores the terminal buffers in sw-buffers. We just need to think of how we want to select the buffers. And it probably doesn’t come as any surprise that I’m going to use ido.
Ido provides regex matching by pressing C-t or defining ido-enable-regexp. It also has flex matching with ido-enable-flex-matching and you can continuously refine selections using C-SPC. It really is amazingly cool.
Surprisingly, I couldn’t find a straightforward way of accessing the interim matches. Nor is there a hook that executes at selection time. Instead, we will override RETURN. Dynamic scoping means we can define an effectively global variable, sw-buffer-matches to store the interim matches for later use. Then, we iterate over these matches and send the command using term-simple-send.
We only want RETURN to be overridden for this particular usage of ido, so we set the keymap on the ido-setup-hook.
(defun sw-ido-save-matches () (interactive) (setq sw-buffer-matches ido-matches) (exit-minibuffer)) (defun sw-ido-my-keys () (define-key ido-completion-map (kbd "RET") 'sw-ido-save-matches)) (defun sw-multi-cmd (&optional cmd) (interactive "sCommand: ") (let ((ido-setup-hook 'sw-ido-my-keys) (sw-buffer-matches "")) (ido-completing-read "choose buffers: " sw-buffers) (dolist (buffer sw-buffer-matches) (term-simple-send (sw-shell-get-process buffer) cmd))))
Why not ibuffer and ibuffer-do-eval?
Hi foo,
ibuffer is nice with the wide range of filters and arbitrary marking but
a) I really like ido
and
b) I already have the list of buffers that contain shells
Hi Jared,
I’ve been using your sw-multi-cmd code for a couple of hours now, and it works better than screen for sending a command to all the open sw-buffers.
However, I’m not sure that ido is the right tool for narrowing the buffer list interactively. It makes it difficult to choose ‘these 20 machines from my list of 30′, or ‘all machines except this one, this one and this one’. Actually, as long as I’ve memorized the names and architectures of all 30 of the machines I’m working with, I can use the regex matching mode… but is there a nicer way to do it?
Gaz
I remembered to tick ‘Notify me of follow-ups by email’ this time, so it won’t take me 8 months to find my way back this time
For posterity, here is the startup code I added to my .emacs today to call your shell-wrapper functions:
(define sw-hosts (list “hostname1″ “hostname2″ … “hostname30″))
(defmacro until (test &rest body)
`(while (not ,test) ,@body))
(defun sw-next-terminal ()
(interactive)
(let ((buffer-name (buffer-name))
(hosts sw-hosts))
(until (string-match (concat “*” (car hosts) “*”) buffer-name)
(setq hosts (cdr hosts)))
(switch-to-buffer (concat “*” (or (cadr hosts) (car sw-hosts)) “*”))))
(defun sw-prior-terminal ()
(interactive)
(let ((buffer-name (buffer-name))
(hosts sw-hosts)
prior)
(until (string-match (concat “*” (car hosts) “*”) buffer-name)
(setq prior (car hosts)
hosts (cdr hosts)))
(switch-to-buffer (concat “*” (or prior (car (last sw-hosts))) “*”))))
;;;; otherwise a single accidental C-C quits my execed ssh
(define-key term-raw-map (kbd “C-c”) term-send-raw)
(define-key term-raw-map [(control next)] ‘sw-next-terminal)
(define-key term-raw-map [(control prior)] ‘sw-prior-terminal)
(define-key term-raw-map [(control end)] ‘sw-multi-cmd)
(dolist (host sw-hosts)
(sw-open-remote-shell host “gaz@gateway.example.com”)
;; otherwise only the first 10 or so succeed:
(sleep-for 0.6))
Thanks again!
Hi Gaz, thanks for the follow-up.
I think that if you want to select arbitrary buffers (that don’t map easily to a regex) to send commands to, maybe ibuffer, as foo mentions above, is a better choice than ido to hook into.