Cuaderno de GNUtas

Para copiar o mover archivos entre varias ventanas de Dired usando ace-window

La biblioteca para Emacs ace-window es una de mis imprescindibles. Nos permite saltar cómodamente entre varias ventanas1 abiertas simplemente con pulsar el número que, de manera transitoria, aparece sobre cada ventana cada vez que llamamos a la función principal ace-window. Ahora bien, hace no mucho, en uno de esos extraños momentos de divagación y pasme en que uno cae frente a la pantalla, pensé en que tal vez estaría bien extender el paquete y reciclar parte de su código para poder copiar o mover uno o varios archivos marcados entre varias ventanas de Dired. Es decir, tenemos los archivos marcados en una ventana (o tan sólo el cursor sobre un archivo), llamamos a la función interesada, aparecen los numeritos sobre las ventanas y, tras pulsar el numerito deseado, los archivos se copian (o se mueven) a la ventana correspondiente. Digamos que vendría a ser esto como una suerte de «arrastrar y soltar» pero sin usar ratón ni levantar las manos del teclado.

Tras estudiar el código de ace-window fui capaz de ensayar el apaño, cuyo código detallo a continuación.

Comenzamos, por supuesto, requiriendo ace-window, ya que emplearemos algunas de sus funciones.

(require 'ace-window)

Estas dos funciones que siguen son idénticas, y sólo difieren en el comando de shell a que llaman: la una copia los archivos marcados y la otra los mueve. Y al terminar de hacerlo, para que se vea claramente la cosecuencia de la acción, refrescan tanto el búfer de salida como el de entrada.

(defun mi-aw-copia-dired-a-ventana (window)
  (let* ((frame (window-frame window))
         (dir-destino (save-window-excursion (aw--push-window (selected-window))
                                             (when (and (frame-live-p frame)
                                                        (not (eq frame (selected-frame))))
                                               (select-frame-set-input-focus frame))
                                             (if (window-live-p window)
                                                 (select-window window)
                                               (error "Got a dead window %S" window))
                                             (expand-file-name default-directory))))
    (when archivos-a-copiar-lista
      (shell-command
       (mapconcat
        #'shell-quote-argument
        `("cp" "-r" ,@archivos-a-copiar-lista ,dir-destino)
        " "))))
  (save-window-excursion
    (select-window window)
    (revert-buffer))
  (setq archivos-a-copiar-lista nil))

(defun mi-aw-mueve-dired-a-ventana (window)
  (let* ((frame (window-frame window))
         (dir-destino (save-window-excursion (aw--push-window (selected-window))
                                             (when (and (frame-live-p frame)
                                                        (not (eq frame (selected-frame))))
                                               (select-frame-set-input-focus frame))
                                             (if (window-live-p window)
                                                 (select-window window)
                                               (error "Got a dead window %S" window))
                                             (expand-file-name default-directory))))
    (when archivos-a-copiar-lista
      (shell-command
       (mapconcat
        #'shell-quote-argument
        `("mv" ,@archivos-a-copiar-lista ,dir-destino)
        " "))))
  (save-window-excursion
    (select-window window)
    (revert-buffer))
  (revert-buffer)
  (setq archivos-a-copiar-lista nil))

Y, por último, la función que llama a las dos funciones anteriores. Para mover en lugar de copiar se usa un argumento universal C-u:

(defun mi-dired-aw-copia-archivo ()
  (interactive)
  (setq archivos-a-copiar-lista (dired-get-marked-files))
  (if (equal current-prefix-arg nil) ; no C-u
      (aw-select "Copia archivo" #'mi-aw-copia-dired-a-ventana)
    (aw-select "Mueve archivo" #'mi-aw-mueve-dired-a-ventana)))

Y el broche, el atajo para Dired. En mi caso, escojo la letra «K». De modo que —recordemos— K copia los archivos y C-u K los mueve.

(with-eval-after-load 'dired
  (define-key dired-mode-map (kbd "K") 'mi-dired-aw-copia-archivo))

Si se hace click en la captura del siguiente vídeo se puede ver el proceso en acción:

aw-test-captura.png

Publicado: 29/10/21

Última actualización: 21/01/22


Índice general

Acerca de...

Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.

Notas:

1

Un recordatorio para los recién llegados a Emacs: lo que Emacs llama «ventanas» es lo que otros editores llaman «marcos». Y lo que Emacs llama «marcos» es lo que otros editores llaman «ventanas» (es decir, las ventanas del entorno de escritorio).

© Juan Manuel Macías
Creado con esmero en
GNU Emacs