├── .gitignore ├── .travis.yml ├── ChangeLog.md ├── README.md ├── Rakefile ├── dired-atool.el └── scripts └── setup-error-on-warn.el /.gitignore: -------------------------------------------------------------------------------- 1 | *.elc 2 | .cask/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | dist: bionic 3 | 4 | before_install: 5 | # install evm 6 | - curl -fsSL https://raw.githubusercontent.com/rejeep/evm/master/go | bash 7 | - export PATH="$HOME/.evm/bin:$PATH" 8 | - evm config path /tmp 9 | 10 | # install emacs 11 | - evm install $EVM_EMACS --use --skip 12 | 13 | before_script: 14 | - ruby --version 15 | - rake --version 16 | - emacs --version 17 | 18 | script: 19 | - rake compilation_test 20 | 21 | env: 22 | - EVM_EMACS=emacs-24.5-travis 23 | - EVM_EMACS=emacs-25.3-travis 24 | - EVM_EMACS=emacs-26.3-travis-linux-xenial 25 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | # dired-atool ChangeLog 2 | 3 | ## development 4 | 5 | [Commits](https://github.com/HKey/dired-atool/compare/1.3.0...master) 6 | 7 | ## 1.3.0 (2021/07/07) 8 | 9 | [Commits](https://github.com/HKey/dired-atool/compare/1.2.0...1.3.0) 10 | 11 | - Add dired-atool-do-unpack-to-current-dir and dired-atool-unpack-no-confirm. ([#6](https://github.com/HKey/dired-atool/pull/6)) 12 | `dired-atool-unpack-no-confirm` can disable confirmation of `dired-atool-do-unpack-to-current-dir` and `dired-atool-do-unpack-with-subdirectory`. 13 | 14 | ## 1.2.0 (2018/12/28) 15 | 16 | [Commits](https://github.com/HKey/dired-atool/compare/1.1.0...1.2.0) 17 | 18 | - Added support for TRAMP. ([#5](https://github.com/HKey/dired-atool/pull/5)) 19 | - Fix file name completion of `dired-atool-do-pack`. ([#3](https://github.com/HKey/dired-atool/pull/3)) 20 | 21 | ## 1.1.0 (2016/02/07) 22 | 23 | [Commits](https://github.com/HKey/dired-atool/compare/1.0.0...1.1.0) 24 | 25 | - Added a feature to insert an exit message to a process buffer. ([#1](https://github.com/HKey/dired-atool/pull/1)) 26 | The corresponding option is `dired-atool-insert-exit-message`. 27 | 28 | ## 1.0.0 (2016/02/05) 29 | 30 | [Commits](https://github.com/HKey/dired-atool/compare/0.1.0...1.0.0) 31 | 32 | - Added an optional parameter to `dired-atool-do-unpack-with-subdirectory`. 33 | Now the command behaves like `dired-atool-do-unpack` when selecting a file 34 | with a `C-u` prefix. 35 | - Changed to use `dired-mark-pop-up` to show a prompt about selecting files. 36 | So dired-atool's commands behave more like dired's commands. 37 | 38 | ## 0.1.0 39 | 40 | - First release 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dired-atool 2 | 3 | [![Build Status](https://travis-ci.org/HKey/dired-atool.svg?branch=master)](https://travis-ci.org/HKey/dired-atool) 4 | [![MELPA](https://melpa.org/packages/dired-atool-badge.svg)](https://melpa.org/#/dired-atool) 5 | [![MELPA Stable](https://stable.melpa.org/packages/dired-atool-badge.svg)](https://stable.melpa.org/#/dired-atool) 6 | 7 | Dired-atool is an utility to pack/unpack files with [atool](http://www.nongnu.org/atool/) on dired. 8 | 9 | ## Requirements 10 | 11 | - Emacs 24 or later 12 | 13 | ## Installation 14 | 15 | You can install dired-atool from [MELPA](https://melpa.org/#/) or 16 | [MELPA Stable](https://stable.melpa.org/#/) by following steps: 17 | 18 | 1. Setup the Emacs built-in package manager to use MELPA or MELPA Stable. 19 | MELPA's documentation is [here](https://github.com/melpa/melpa#usage). 20 | 21 | 2. Install dired-atool. 22 | `M-x package-install dired-atool` 23 | 24 | ## Setup key bindings 25 | 26 | Call `dired-atool-setup` in your init.el like below: 27 | 28 | ```emacs-lisp 29 | (dired-atool-setup) 30 | ``` 31 | 32 | or `M-x dired-atool-setup`. 33 | `dired-atool-setup` sets key bindings of `dired-mode-map` below: 34 | 35 | | key | command | 36 | |-----|-------------------------| 37 | | z | `dired-atool-do-unpack` | 38 | | Z | `dired-atool-do-pack` | 39 | 40 | You can also set key bindings manually like below: 41 | 42 | ```emacs-lisp 43 | (require 'dired) 44 | 45 | (define-key dired-mode-map "z" #'dired-atool-do-unpack) 46 | (define-key dired-mode-map "Z" #'dired-atool-do-pack) 47 | ``` 48 | ## Versioning 49 | 50 | The versioning of dired-atool follows [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html). 51 | 52 | ## Commands 53 | 54 | ### `dired-atool-do-unpack` 55 | 56 | This unpacks file(s) selected/marked on dired. 57 | 58 | ### `dired-atool-do-unpack-to-current-dir` 59 | 60 | This is an unpacking command like `dired-atool-do-unpack`. 61 | But this always unpacks file(s) into the current directory. 62 | 63 | ### `dired-atool-do-unpack-with-subdirectory` 64 | 65 | This is an unpacking command like `dired-atool-do-unpack`. 66 | But this makes subdirectories in the current directory and unpacks 67 | files into them. 68 | 69 | ### `dired-atool-do-pack` 70 | 71 | This packs file(s) selected/marked on dired. 72 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/clean' 2 | 3 | EMACS = ENV['EMACS'] || 'emacs' 4 | 5 | COMPILATION_TARGETS = FileList['*.el'] 6 | 7 | # Utilities 8 | 9 | def byte_compile_file(el_file, error_on_warn = false) 10 | command = %W(#{EMACS} -Q -batch) 11 | command.concat(%w(-l scripts/setup-error-on-warn.el)) if error_on_warn 12 | command.concat(%W(-f batch-byte-compile #{el_file})) 13 | sh(*command) 14 | end 15 | 16 | # Tasks 17 | 18 | CLEAN.include(COMPILATION_TARGETS.ext('.elc')) 19 | 20 | rule '.elc' => '.el' do |t| 21 | byte_compile_file t.source 22 | end 23 | 24 | desc 'Compile emacs lisp files' 25 | task compile: COMPILATION_TARGETS.ext('.elc') 26 | 27 | desc 'Run compilation test' 28 | task compilation_test: :clean do 29 | COMPILATION_TARGETS.each do |el_file| 30 | byte_compile_file el_file, true 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /dired-atool.el: -------------------------------------------------------------------------------- 1 | ;;; dired-atool.el --- Pack/unpack files with atool on dired. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2016 Hiroki YAMAKAWA 4 | 5 | ;; Author: Hiroki YAMAKAWA 6 | ;; URL: https://github.com/HKey/dired-atool 7 | ;; Version: 1.3.0 8 | ;; Package-Requires: ((emacs "24")) 9 | ;; Keywords: files 10 | 11 | ;; This program is free software; you can redistribute it and/or modify 12 | ;; it under the terms of the GNU General Public License as published by 13 | ;; the Free Software Foundation, either version 3 of the License, or 14 | ;; (at your option) any later version. 15 | 16 | ;; This program is distributed in the hope that it will be useful, 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | ;; GNU General Public License for more details. 20 | 21 | ;; You should have received a copy of the GNU General Public License 22 | ;; along with this program. If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; Dired-atool is an utility to pack/unpack files with atool on dired. 27 | 28 | ;; Please see https://github.com/HKey/dired-atool/blob/master/README.md 29 | ;; for more details. 30 | 31 | ;;; Code: 32 | 33 | (require 'dired) 34 | (require 'dired-aux) 35 | 36 | 37 | (defgroup dired-atool nil 38 | "Atool utilities for dired." 39 | :group 'dired 40 | :prefix "dired-atool-") 41 | 42 | (defcustom dired-atool-atool "atool" 43 | "Atool program which is used to pack/unpack files." 44 | :type 'string 45 | :group 'dired-atool 46 | :package-version '(dired-atool . "0.1.0")) 47 | 48 | (defcustom dired-atool-unpacking-options '("--explain") 49 | "Additional options for unpacking with atool." 50 | :type '(repeat string) 51 | :group 'dired-atool 52 | :package-version '(dired-atool . "0.1.0")) 53 | 54 | (defcustom dired-atool-packing-options '("--explain") 55 | "Additional options for packing with atool." 56 | :type '(repeat string) 57 | :group 'dired-atool 58 | :package-version '(dired-atool . "0.1.0")) 59 | 60 | (defcustom dired-atool-insert-exit-message t 61 | "Non-nil means that dired-atool inserts an exit message to a process buffer." 62 | :type 'boolean 63 | :group 'dired-atool 64 | :package-version '(dired-atool . "1.1.0")) 65 | 66 | (defcustom dired-atool-unpack-no-confirm nil 67 | "Non-nil means that dired-atool does not confirm with user before unpacking." 68 | :type 'boolean 69 | :group 'dired-atool 70 | :package-version '(dired-atool . "1.3.0")) 71 | 72 | (defun dired-atool--buffer-name (message) 73 | "Make a buffer name using MESSAGE." 74 | (format "*dired-atool: %s*" message)) 75 | 76 | (defun dired-atool--exit-message (process) 77 | "Make a message string about exit of PROCESS." 78 | (format "%s exited with code %d at %s" 79 | (mapconcat #'identity (process-command process) " ") 80 | (process-exit-status process) 81 | (current-time-string))) 82 | 83 | (defun dired-atool--insert-exit-message (process) 84 | "Insert an exit message in a buffer of PROCESS." 85 | (with-current-buffer (process-buffer process) 86 | (insert "\n" (dired-atool--exit-message process)))) 87 | 88 | (defun dired-atool--async-shell-command (command-list) 89 | "A wrapper function to call `async-shell-command'. 90 | COMMAND-LIST is a list of a command separated by spaces." 91 | (let* ((command (mapconcat #'shell-quote-argument command-list " ")) 92 | (buffer-name (dired-atool--buffer-name command))) 93 | (async-shell-command command buffer-name buffer-name) 94 | ;; Add an exit message to the process buffer 95 | (when dired-atool-insert-exit-message 96 | (let* ((process (get-buffer-process buffer-name)) 97 | (sentinel (process-sentinel process))) 98 | (set-process-sentinel 99 | process 100 | (lambda (process status) 101 | (when (functionp sentinel) 102 | (funcall sentinel process status)) 103 | (when (memq (process-status process) '(exit signal)) 104 | (dired-atool--insert-exit-message process)))))))) 105 | 106 | (defun dired-atool--make-directory (dir prompt) 107 | "Make DIR directory if the answer of PROMPT is yes." 108 | (when (yes-or-no-p prompt) 109 | (make-directory dir t) 110 | t)) 111 | 112 | (defun dired-atool--file-names-for-prompt (files) 113 | "Return a string to show in a prompt message about FILES." 114 | (if (= (length files) 1) 115 | (car files) 116 | (format "* [%d files]" (length files)))) 117 | 118 | (defun dired-atool--local-file-name (file) 119 | "Return local file name if FILE is on a remote system. 120 | Otherwise return FILE as is." 121 | (let ((local-file (file-remote-p file 'localname))) 122 | (or local-file file))) 123 | 124 | ;;;###autoload 125 | (defun dired-atool-do-unpack (&optional arg) 126 | "Unpack file(s) with atool. 127 | ARG is used for `dired-get-marked-files'." 128 | (interactive "P") 129 | (let* ((files (dired-get-marked-files t arg)) 130 | (dir (expand-file-name ; to expand "~" to a real path name 131 | (dired-mark-pop-up 132 | nil nil files 133 | #'read-directory-name 134 | (format "Unpack %s to: " 135 | (dired-atool--file-names-for-prompt files)) 136 | (dired-dwim-target-directory)))) 137 | (dir-local-name (dired-atool--local-file-name dir)) 138 | (command-list `(,dired-atool-atool 139 | ,(concat "--extract-to=" dir-local-name) 140 | "--each" 141 | ,@dired-atool-unpacking-options 142 | ,@files))) 143 | (if (or (file-exists-p dir) 144 | (dired-atool--make-directory 145 | dir 146 | (format 147 | "Directory %s does not exist. Make it before unpacking?" 148 | dir))) 149 | (dired-atool--async-shell-command command-list) 150 | (message "Unpacking canceled.")))) 151 | 152 | ;;;###autoload 153 | (defun dired-atool-do-unpack-to-current-dir (&optional arg) 154 | "Unpack file(s) with atool to current directory. 155 | When `dired-atool-unpack-no-confirm' is non-nil, this doesn't confirm 156 | about unpacking. 157 | ARG is used for `dired-get-marked-files'." 158 | (interactive "P") 159 | (let* ((files (dired-get-marked-files t arg)) 160 | (dir-local-name (dired-atool--local-file-name (dired-current-directory))) 161 | (command-list `(,dired-atool-atool 162 | ,(concat "--extract-to=" dir-local-name) 163 | "--each" 164 | ,@dired-atool-unpacking-options 165 | ,@files))) 166 | (if (or dired-atool-unpack-no-confirm 167 | (dired-mark-pop-up nil nil files 168 | #'yes-or-no-p 169 | (format "Unpack %s?" 170 | (dired-atool--file-names-for-prompt files)))) 171 | (dired-atool--async-shell-command command-list) 172 | (message "Unpacking canceled.")))) 173 | 174 | ;;;###autoload 175 | (defun dired-atool-do-unpack-with-subdirectory (&optional arg) 176 | "Unpack file(s) with atool. 177 | This command makes subdirectories in the current directory and unpacks 178 | files into them. 179 | When `dired-atool-unpack-no-confirm' is non-nil, this doesn't confirm 180 | about unpacking. 181 | ARG is used for `dired-get-marked-files'." 182 | (interactive "P") 183 | (let* ((files (dired-get-marked-files t arg)) 184 | (command-list `(,dired-atool-atool 185 | "--extract" 186 | "--subdir" 187 | "--each" 188 | ,@dired-atool-unpacking-options 189 | ,@files))) 190 | (if (or dired-atool-unpack-no-confirm 191 | (dired-mark-pop-up nil nil files 192 | #'yes-or-no-p 193 | (format "Unpack %s?" 194 | (dired-atool--file-names-for-prompt files)))) 195 | (dired-atool--async-shell-command command-list) 196 | (message "Unpacking canceled.")))) 197 | 198 | ;;;###autoload 199 | (defun dired-atool-do-pack (&optional arg) 200 | "Pack file(s) with atool. 201 | ARG is used for `dired-get-marked-files'." 202 | (interactive "P") 203 | (let* ((files (dired-get-marked-files t arg)) 204 | (archive (expand-file-name ; to expand "~" to a real path name 205 | (dired-mark-pop-up 206 | nil nil files 207 | #'read-file-name 208 | (format "Pack %s to: " 209 | (dired-atool--file-names-for-prompt files)) 210 | (dired-dwim-target-directory)))) 211 | (dir (directory-file-name (file-name-directory archive))) 212 | (archive-local-name (dired-atool--local-file-name archive)) 213 | (command-list `(,dired-atool-atool 214 | "--add" 215 | ,archive-local-name 216 | ,@dired-atool-packing-options 217 | ,@files)) 218 | (ok? nil)) 219 | (catch 'cancel 220 | (when (file-exists-p archive) 221 | (if (yes-or-no-p 222 | (format "%s already exists. Remove it before packing?" archive)) 223 | (delete-file archive) 224 | (throw 'cancel nil))) 225 | (unless (or (file-exists-p dir) 226 | (dired-atool--make-directory 227 | dir 228 | (format 229 | "Directory %s does not exist. Make it before packing?" 230 | dir))) 231 | (throw 'cancel nil)) 232 | (setq ok? t)) 233 | (if ok? 234 | (dired-atool--async-shell-command command-list) 235 | (message "Packing canceled.")))) 236 | 237 | ;;;###autoload 238 | (defun dired-atool-setup () 239 | "Setup key bindings of dired-atool commands." 240 | (interactive) 241 | (define-key dired-mode-map (kbd "z") #'dired-atool-do-unpack) 242 | (define-key dired-mode-map (kbd "Z") #'dired-atool-do-pack)) 243 | 244 | (provide 'dired-atool) 245 | ;;; dired-atool.el ends here 246 | 247 | ;; Local Variables: 248 | ;; eval: (when (fboundp (quote flycheck-mode)) (flycheck-mode 1)) 249 | ;; eval: (when (fboundp (quote flycheck-package-setup)) (flycheck-package-setup)) 250 | ;; End: 251 | -------------------------------------------------------------------------------- /scripts/setup-error-on-warn.el: -------------------------------------------------------------------------------- 1 | ;;; -*- lexical-binding: t; -*- 2 | 3 | (setq byte-compile-error-on-warn t) 4 | --------------------------------------------------------------------------------