summaryrefslogtreecommitdiff
path: root/lisp/wdired.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/wdired.el')
-rw-r--r--lisp/wdired.el504
1 files changed, 272 insertions, 232 deletions
diff --git a/lisp/wdired.el b/lisp/wdired.el
index a096abd106f..fd549bac322 100644
--- a/lisp/wdired.el
+++ b/lisp/wdired.el
@@ -1,4 +1,4 @@
-;;; wdired.el --- Rename files editing their names in dired buffers -*- coding: utf-8; -*-
+;;; wdired.el --- Rename files editing their names in dired buffers -*- coding: utf-8; lexical-binding: t; -*-
;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
@@ -85,15 +85,13 @@
If nil, WDired doesn't require confirmation to change the file names,
and the variable `wdired-confirm-overwrite' controls whether it is ok
to overwrite files without asking."
- :type 'boolean
- :group 'wdired)
+ :type 'boolean)
(defcustom wdired-confirm-overwrite t
"If nil the renames can overwrite files without asking.
This variable has no effect at all if `wdired-use-interactive-rename'
is not nil."
- :type 'boolean
- :group 'wdired)
+ :type 'boolean)
(defcustom wdired-use-dired-vertical-movement nil
"If t, the \"up\" and \"down\" movement works as in Dired mode.
@@ -106,15 +104,13 @@ when editing several filenames.
If nil, \"up\" and \"down\" movement is done as in any other buffer."
:type '(choice (const :tag "As in any other mode" nil)
(const :tag "Smart cursor placement" sometimes)
- (other :tag "As in dired mode" t))
- :group 'wdired)
+ (other :tag "As in dired mode" t)))
(defcustom wdired-allow-to-redirect-links t
"If non-nil, the target of the symbolic links are editable.
In systems without symbolic links support, this variable has no effect
at all."
- :type 'boolean
- :group 'wdired)
+ :type 'boolean)
(defcustom wdired-allow-to-change-permissions nil
"If non-nil, the permissions bits of the files are editable.
@@ -135,8 +131,7 @@ Anyway, the real change of the permissions is done by the external
program `dired-chmod-program', which must exist."
:type '(choice (const :tag "Not allowed" nil)
(const :tag "Toggle/set bits" t)
- (other :tag "Bits freely editable" advanced))
- :group 'wdired)
+ (other :tag "Bits freely editable" advanced)))
(defcustom wdired-keep-marker-rename t
;; Use t as default so that renamed files "take their markers with them".
@@ -149,8 +144,7 @@ See `dired-keep-marker-rename' if you want to do the same for files
renamed by `dired-do-rename' and `dired-do-rename-regexp'."
:type '(choice (const :tag "Keep" t)
(character :tag "Mark" :value ?R))
- :version "24.3"
- :group 'wdired)
+ :version "24.3")
(defcustom wdired-create-parent-directories t
"If non-nil, create parent directories of destination files.
@@ -159,51 +153,47 @@ nonexistent directory, wdired will create any parent directories
necessary. When nil, attempts to rename a file into a
nonexistent directory will fail."
:version "26.1"
- :type 'boolean
- :group 'wdired)
+ :type 'boolean)
(defvar wdired-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map "\C-x\C-s" 'wdired-finish-edit)
- (define-key map "\C-c\C-c" 'wdired-finish-edit)
- (define-key map "\C-c\C-k" 'wdired-abort-changes)
- (define-key map "\C-c\C-[" 'wdired-abort-changes)
- (define-key map "\C-x\C-q" 'wdired-exit)
- (define-key map "\C-m" 'ignore)
- (define-key map "\C-j" 'ignore)
- (define-key map "\C-o" 'ignore)
- (define-key map [up] 'wdired-previous-line)
- (define-key map "\C-p" 'wdired-previous-line)
- (define-key map [down] 'wdired-next-line)
- (define-key map "\C-n" 'wdired-next-line)
-
- (define-key map [menu-bar wdired]
- (cons "WDired" (make-sparse-keymap "WDired")))
- (define-key map [menu-bar wdired wdired-customize]
- '("Options" . wdired-customize))
- (define-key map [menu-bar wdired dashes]
- '("--"))
- (define-key map [menu-bar wdired wdired-abort-changes]
- '(menu-item "Abort Changes" wdired-abort-changes
- :help "Abort changes and return to dired mode"))
- (define-key map [menu-bar wdired wdired-finish-edit]
- '("Commit Changes" . wdired-finish-edit))
-
- (define-key map [remap upcase-word] 'wdired-upcase-word)
- (define-key map [remap capitalize-word] 'wdired-capitalize-word)
- (define-key map [remap downcase-word] 'wdired-downcase-word)
-
+ (define-key map "\C-x\C-s" #'wdired-finish-edit)
+ (define-key map "\C-c\C-c" #'wdired-finish-edit)
+ (define-key map "\C-c\C-k" #'wdired-abort-changes)
+ (define-key map "\C-c\C-[" #'wdired-abort-changes)
+ (define-key map "\C-x\C-q" #'wdired-exit)
+ (define-key map "\C-m" #'undefined)
+ (define-key map "\C-j" #'undefined)
+ (define-key map "\C-o" #'undefined)
+ (define-key map [up] #'wdired-previous-line)
+ (define-key map "\C-p" #'wdired-previous-line)
+ (define-key map [down] #'wdired-next-line)
+ (define-key map "\C-n" #'wdired-next-line)
+ (define-key map [remap upcase-word] #'wdired-upcase-word)
+ (define-key map [remap capitalize-word] #'wdired-capitalize-word)
+ (define-key map [remap downcase-word] #'wdired-downcase-word)
+ (define-key map [remap self-insert-command] #'wdired--self-insert)
map)
"Keymap used in `wdired-mode'.")
+(easy-menu-define wdired-mode-menu wdired-mode-map
+ "Menu for `wdired-mode'."
+ '("WDired"
+ ["Commit Changes" wdired-finish-edit]
+ ["Abort Changes" wdired-abort-changes
+ :help "Abort changes and return to Dired mode"]
+ "---"
+ ["Options" wdired-customize]))
+
(defvar wdired-mode-hook nil
"Hooks run when changing to WDired mode.")
;; Local variables (put here to avoid compilation gripes)
-(defvar wdired-col-perm) ;; Column where the permission bits start
-(defvar wdired-old-content)
-(defvar wdired-old-point)
-(defvar wdired-old-marks)
+(defvar wdired--perm-beg) ;; Column where the permission bits start
+(defvar wdired--perm-end) ;; Column where the permission bits stop
+(defvar wdired--old-content)
+(defvar wdired--old-point)
+(defvar wdired--old-marks)
(defun wdired-mode ()
"Writable Dired (WDired) mode.
@@ -242,11 +232,12 @@ See `wdired-mode'."
(interactive)
(unless (derived-mode-p 'dired-mode)
(error "Not a Dired buffer"))
- (setq-local wdired-old-content
+ (setq-local wdired--old-content
(buffer-substring (point-min) (point-max)))
- (setq-local wdired-old-marks
+ (setq-local wdired--old-marks
(dired-remember-marks (point-min) (point-max)))
- (setq-local wdired-old-point (point))
+ (setq-local wdired--old-point (point))
+ (wdired--set-permission-bounds)
(setq-local query-replace-skip-read-only t)
(add-function :after-while (local 'isearch-filter-predicate)
#'wdired-isearch-filter-read-only)
@@ -254,21 +245,12 @@ See `wdired-mode'."
(force-mode-line-update)
(setq buffer-read-only nil)
(dired-unadvertise default-directory)
- (add-hook 'kill-buffer-hook 'wdired-check-kill-buffer nil t)
- (add-hook 'after-change-functions 'wdired--restore-properties nil t)
+ (add-hook 'kill-buffer-hook #'wdired-check-kill-buffer nil t)
+ (add-hook 'before-change-functions #'wdired--before-change-fn nil t)
+ (add-hook 'after-change-functions #'wdired--restore-properties nil t)
(setq major-mode 'wdired-mode)
(setq mode-name "Editable Dired")
- (setq revert-buffer-function 'wdired-revert)
- ;; I temp disable undo for performance: since I'm going to clear the
- ;; undo list, it can save more than a 9% of time with big
- ;; directories because setting properties modify the undo-list.
- (buffer-disable-undo)
- (wdired-preprocess-files)
- (if wdired-allow-to-change-permissions
- (wdired-preprocess-perms))
- (if (fboundp 'make-symbolic-link)
- (wdired-preprocess-symlinks))
- (buffer-enable-undo) ; Performance hack. See above.
+ (add-function :override (local 'revert-buffer-function) #'wdired-revert)
(set-buffer-modified-p nil)
(setq buffer-undo-list nil)
(run-mode-hooks 'wdired-mode-hook)
@@ -276,6 +258,68 @@ See `wdired-mode'."
"Press \\[wdired-finish-edit] when finished \
or \\[wdired-abort-changes] to abort changes")))
+(defun wdired--set-permission-bounds ()
+ (save-excursion
+ (goto-char (point-min))
+ (if (not (re-search-forward dired-re-perms nil t 1))
+ (progn
+ (setq-local wdired--perm-beg nil)
+ (setq-local wdired--perm-end nil))
+ (goto-char (match-beginning 0))
+ ;; Add 1 since the first char matched by `dired-re-perms' is the
+ ;; one describing the nature of the entry (dir/symlink/...) rather
+ ;; than its permissions.
+ (setq-local wdired--perm-beg (1+ (wdired--current-column)))
+ (goto-char (match-end 0))
+ (setq-local wdired--perm-end (wdired--current-column)))))
+
+(defun wdired--current-column ()
+ (- (point) (line-beginning-position)))
+
+(defun wdired--point-at-perms-p ()
+ (and wdired--perm-beg
+ (<= wdired--perm-beg (wdired--current-column) wdired--perm-end)))
+
+(defun wdired--line-preprocessed-p ()
+ (get-text-property (line-beginning-position) 'front-sticky))
+
+(defun wdired--self-insert ()
+ (interactive)
+ (if (wdired--line-preprocessed-p)
+ (call-interactively 'self-insert-command)
+ (wdired--before-change-fn (point) (point))
+ (let* ((map (get-text-property (point) 'keymap)))
+ (call-interactively (or (if map (lookup-key map (this-command-keys)))
+ #'self-insert-command)))))
+
+(put 'wdired--self-insert 'delete-selection 'delete-selection-uses-region-p)
+
+(defun wdired--before-change-fn (beg end)
+ (save-match-data
+ (save-excursion
+ (save-restriction
+ (widen)
+ ;; Make sure to process entire lines.
+ (goto-char end)
+ (setq end (line-end-position))
+ (goto-char beg)
+ (forward-line 0)
+
+ (while (< (point) end)
+ (unless (wdired--line-preprocessed-p)
+ (with-silent-modifications
+ (put-text-property (point) (1+ (point)) 'front-sticky t)
+ (wdired--preprocess-files)
+ (when wdired-allow-to-change-permissions
+ (wdired--preprocess-perms))
+ (when (fboundp 'make-symbolic-link)
+ (wdired--preprocess-symlinks))))
+ (forward-line))
+ (when (eobp)
+ (with-silent-modifications
+ ;; Is this good enough? Assumes no extra white lines from dired.
+ (put-text-property (1- (point-max)) (point-max) 'read-only t)))))))
+
(defun wdired-isearch-filter-read-only (beg end)
"Skip matches that have a read-only property."
(not (text-property-not-all (min beg end) (max beg end)
@@ -283,46 +327,58 @@ or \\[wdired-abort-changes] to abort changes")))
;; Protect the buffer so only the filenames can be changed, and put
;; properties so filenames (old and new) can be easily found.
-(defun wdired-preprocess-files ()
- (put-text-property (point-min) (1+ (point-min))'front-sticky t)
+(defun wdired--preprocess-files ()
(save-excursion
- (goto-char (point-min))
- (let ((b-protection (point))
- (used-F (dired-check-switches dired-actual-switches "F" "classify"))
- filename)
- (while (not (eobp))
- (setq filename (dired-get-filename nil t))
- (when (and filename
- (not (member (file-name-nondirectory filename) '("." ".."))))
- (dired-move-to-filename)
- ;; The rear-nonsticky property below shall ensure that text preceding
- ;; the filename can't be modified.
- (add-text-properties
- (1- (point)) (point) `(old-name ,filename rear-nonsticky (read-only)))
- (put-text-property b-protection (point) 'read-only t)
- (dired-move-to-end-of-filename t)
- (put-text-property (point) (1+ (point)) 'end-name t))
- (when (and used-F (looking-at "[*/@|=>]$")) (forward-char))
- (when (save-excursion
- (and (re-search-backward
- dired-permission-flags-regexp nil t)
- (looking-at "l")
- (search-forward " -> " (line-end-position) t)))
- (goto-char (line-end-position)))
- (setq b-protection (point))
- (forward-line))
- (put-text-property b-protection (point-max) 'read-only t))))
+ (let ((used-F (dired-check-switches dired-actual-switches "F" "classify"))
+ (beg (point))
+ (filename (dired-get-filename nil t)))
+ (when (and filename
+ (not (member (file-name-nondirectory filename) '("." ".."))))
+ (dired-move-to-filename)
+ ;; The rear-nonsticky property below shall ensure that text preceding
+ ;; the filename can't be modified.
+ (add-text-properties
+ (1- (point)) (point) `(old-name ,filename rear-nonsticky (read-only)))
+ (put-text-property beg (point) 'read-only t)
+ (dired-move-to-end-of-filename t)
+ (put-text-property (point) (1+ (point)) 'end-name t))
+ (when (and used-F (looking-at "[*/@|=>]$")) (forward-char))
+ (when (save-excursion
+ (and (re-search-backward
+ dired-permission-flags-regexp nil t)
+ (looking-at "l")
+ (search-forward " -> " (line-end-position) t)))
+ (goto-char (line-end-position))))))
;; This code is a copy of some dired-get-filename lines.
(defsubst wdired-normalize-filename (file unquotep)
(when unquotep
- (setq file
- ;; FIXME: shouldn't we check for a `b' argument or somesuch before
- ;; doing such unquoting? --Stef
- (read (concat
- "\"" (replace-regexp-in-string
- "\\([^\\]\\|\\`\\)\"" "\\1\\\\\"" file)
- "\""))))
+ ;; Unquote names quoted by ls or by dired-insert-directory.
+ ;; This code was written using `read' to unquote, because
+ ;; it's faster than substituting \007 (4 chars) -> ^G (1
+ ;; char) etc. in a lisp loop. Unfortunately, this decision
+ ;; has necessitated hacks such as dealing with filenames
+ ;; with quotation marks in their names.
+ (while (string-match "\\(?:[^\\]\\|\\`\\)\\(\"\\)" file)
+ (setq file (replace-match "\\\"" nil t file 1)))
+ ;; Unescape any spaces escaped by ls -b (bug#10469).
+ ;; Other -b quotes, eg \t, \n, work transparently.
+ (if (dired-switches-escape-p dired-actual-switches)
+ (let ((start 0)
+ (rep "")
+ (shift -1))
+ (while (string-match "\\(\\\\\\) " file start)
+ (setq file (replace-match rep nil t file 1)
+ start (+ shift (match-end 0))))))
+ (when (eq system-type 'windows-nt)
+ (save-match-data
+ (let ((start 0))
+ (while (string-match "\\\\" file start)
+ (aset file (match-beginning 0) ?/)
+ (setq start (match-end 0))))))
+
+ ;; Hence we don't need to worry about converting `\\' back to `\'.
+ (setq file (read (concat "\"" file "\""))))
(and file buffer-file-coding-system
(not file-name-coding-system)
(not default-file-name-coding-system)
@@ -338,6 +394,7 @@ non-nil means return old filename."
;; FIXME: Use dired-get-filename's new properties.
(let ((used-F (dired-check-switches dired-actual-switches "F" "classify"))
beg end file)
+ (wdired--before-change-fn (point) (point))
(save-excursion
(setq end (line-end-position))
(beginning-of-line)
@@ -374,7 +431,6 @@ non-nil means return old filename."
(and file (> (length file) 0)
(concat (dired-current-directory) file))))))
-
(defun wdired-change-to-dired-mode ()
"Change the mode back to dired."
(or (eq major-mode 'wdired-mode)
@@ -391,18 +447,19 @@ non-nil means return old filename."
(setq major-mode 'dired-mode)
(setq mode-name "Dired")
(dired-advertise)
- (remove-hook 'kill-buffer-hook 'wdired-check-kill-buffer t)
- (remove-hook 'after-change-functions 'wdired--restore-properties t)
- (setq-local revert-buffer-function 'dired-revert))
-
+ (remove-hook 'kill-buffer-hook #'wdired-check-kill-buffer t)
+ (remove-hook 'before-change-functions #'wdired--before-change-fn t)
+ (remove-hook 'after-change-functions #'wdired--restore-properties t)
+ (remove-function (local 'revert-buffer-function) #'wdired-revert))
(defun wdired-abort-changes ()
"Abort changes and return to dired mode."
(interactive)
+ (remove-hook 'before-change-functions #'wdired--before-change-fn t)
(let ((inhibit-read-only t))
(erase-buffer)
- (insert wdired-old-content)
- (goto-char wdired-old-point))
+ (insert wdired--old-content)
+ (goto-char wdired--old-point))
(wdired-change-to-dired-mode)
(set-buffer-modified-p nil)
(setq buffer-undo-list nil)
@@ -424,13 +481,14 @@ non-nil means return old filename."
(setq errors (cdr tmp-value))
(setq changes (car tmp-value)))
(when (and wdired-allow-to-change-permissions
- (boundp 'wdired-col-perm)) ; could have been changed
+ wdired--perm-beg) ; could have been changed
(setq tmp-value (wdired-do-perm-changes))
(setq errors (+ errors (cdr tmp-value)))
(setq changes (or changes (car tmp-value))))
(goto-char (point-max))
(while (not (bobp))
- (setq file-old (wdired-get-filename nil t))
+ (setq file-old (and (wdired--line-preprocessed-p)
+ (wdired-get-filename nil t)))
(when file-old
(setq file-new (wdired-get-filename))
(if (equal file-new file-old)
@@ -442,11 +500,11 @@ non-nil means return old filename."
(let ((mark (cond ((integerp wdired-keep-marker-rename)
wdired-keep-marker-rename)
(wdired-keep-marker-rename
- (cdr (assoc file-old wdired-old-marks)))
+ (cdr (assoc file-old wdired--old-marks)))
(t nil))))
(when mark
(push (cons (substitute-in-file-name file-new) mark)
- wdired-old-marks))))
+ wdired--old-marks))))
(push (cons file-old (substitute-in-file-name file-new))
files-renamed))))
(forward-line -1)))
@@ -471,7 +529,7 @@ non-nil means return old filename."
;; Re-sort the buffer.
(revert-buffer)
(let ((inhibit-read-only t))
- (dired-mark-remembered wdired-old-marks)))
+ (dired-mark-remembered wdired--old-marks)))
(let ((inhibit-read-only t))
(remove-text-properties (point-min) (point-max)
'(old-name nil end-name nil old-link nil
@@ -542,7 +600,7 @@ non-nil means return old filename."
;; So we must ensure dired-aux is loaded.
(require 'dired-aux)
(condition-case err
- (let ((dired-backup-overwrite nil))
+ (dlet ((dired-backup-overwrite nil))
(and wdired-create-parent-directories
(wdired-create-parentdirs file-new))
(dired-rename-file file-ori file-new
@@ -644,47 +702,49 @@ Optional arguments are ignored."
(defun wdired--restore-properties (beg end _len)
(save-match-data
(save-excursion
- (let ((lep (line-end-position))
- (used-F (dired-check-switches
- dired-actual-switches
- "F" "classify")))
- ;; Deleting the space between the link name and the arrow (a
- ;; noop) also deletes the end-name property, so restore it.
- (when (and (save-excursion
- (re-search-backward dired-permission-flags-regexp nil t)
- (looking-at "l"))
- (get-text-property (1- (point)) 'dired-filename)
- (not (get-text-property (point) 'dired-filename))
- (not (get-text-property (point) 'end-name)))
+ (save-restriction
+ (widen)
+ (let ((lep (line-end-position))
+ (used-F (dired-check-switches
+ dired-actual-switches
+ "F" "classify")))
+ ;; Deleting the space between the link name and the arrow (a
+ ;; noop) also deletes the end-name property, so restore it.
+ (when (and (save-excursion
+ (re-search-backward dired-permission-flags-regexp nil t)
+ (looking-at "l"))
+ (get-text-property (1- (point)) 'dired-filename)
+ (not (get-text-property (point) 'dired-filename))
+ (not (get-text-property (point) 'end-name)))
(put-text-property (point) (1+ (point)) 'end-name t))
- (beginning-of-line)
- (when (re-search-forward
- directory-listing-before-filename-regexp lep t)
- (setq beg (point)
- end (if (or
- ;; If the file is a symlink, put the
- ;; dired-filename property only on the link
- ;; name. (Using (file-symlink-p
- ;; (dired-get-filename)) fails in
- ;; wdired-mode, bug#32673.)
- (and (re-search-backward
- dired-permission-flags-regexp nil t)
- (looking-at "l")
- ;; macOS and Ultrix adds "@" to the end
- ;; of symlinks when using -F.
- (if (and used-F
- dired-ls-F-marks-symlinks)
- (re-search-forward "@? -> " lep t)
- (search-forward " -> " lep t)))
- ;; When dired-listing-switches includes "F"
- ;; or "classify", don't treat appended
- ;; indicator characters as part of the file
- ;; name (bug#34915).
- (and used-F
- (re-search-forward "[*/@|=>]$" lep t)))
- (goto-char (match-beginning 0))
- lep))
- (put-text-property beg end 'dired-filename t))))))
+ (beginning-of-line)
+ (when (re-search-forward
+ directory-listing-before-filename-regexp lep t)
+ (setq beg (point)
+ end (if (or
+ ;; If the file is a symlink, put the
+ ;; dired-filename property only on the link
+ ;; name. (Using (file-symlink-p
+ ;; (dired-get-filename)) fails in
+ ;; wdired-mode, bug#32673.)
+ (and (re-search-backward
+ dired-permission-flags-regexp nil t)
+ (looking-at "l")
+ ;; macOS and Ultrix adds "@" to the end
+ ;; of symlinks when using -F.
+ (if (and used-F
+ dired-ls-F-marks-symlinks)
+ (re-search-forward "@? -> " lep t)
+ (search-forward " -> " lep t)))
+ ;; When dired-listing-switches includes "F"
+ ;; or "classify", don't treat appended
+ ;; indicator characters as part of the file
+ ;; name (bug#34915).
+ (and used-F
+ (re-search-forward "[*/@|=>]$" lep t)))
+ (goto-char (match-beginning 0))
+ lep))
+ (put-text-property beg end 'dired-filename t)))))))
(defun wdired-next-line (arg)
"Move down lines then position at filename or the current column.
@@ -715,21 +775,17 @@ says how many lines to move; default is one line."
(dired-move-to-filename)))
;; Put the needed properties to allow the user to change links' targets
-(defun wdired-preprocess-symlinks ()
- (let ((inhibit-read-only t))
- (save-excursion
- (goto-char (point-min))
- (while (not (eobp))
- (when (looking-at dired-re-sym)
- (re-search-forward " -> \\(.*\\)$")
- (put-text-property (1- (match-beginning 1))
- (match-beginning 1) 'old-link
- (match-string-no-properties 1))
- (put-text-property (match-end 1) (1+ (match-end 1)) 'end-link t)
- (unless wdired-allow-to-redirect-links
- (put-text-property (match-beginning 0)
- (match-end 1) 'read-only t)))
- (forward-line)))))
+(defun wdired--preprocess-symlinks ()
+ (save-excursion
+ (when (looking-at dired-re-sym)
+ (re-search-forward " -> \\(.*\\)$")
+ (put-text-property (1- (match-beginning 1))
+ (match-beginning 1) 'old-link
+ (match-string-no-properties 1))
+ (put-text-property (match-end 1) (1+ (match-end 1)) 'end-link t)
+ (unless wdired-allow-to-redirect-links
+ (put-text-property (match-beginning 0)
+ (match-end 1) 'read-only t)))))
(defun wdired-get-previous-link (&optional old move)
"Return the next symlink target.
@@ -813,56 +869,49 @@ Like original function but it skips read-only words."
(interactive "p")
(wdired-xcase-word 'capitalize-word arg))
-
;; The following code deals with changing the access bits (or
;; permissions) of the files.
(defvar wdired-perm-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map " " 'wdired-toggle-bit)
- (define-key map "r" 'wdired-set-bit)
- (define-key map "w" 'wdired-set-bit)
- (define-key map "x" 'wdired-set-bit)
- (define-key map "-" 'wdired-set-bit)
- (define-key map "S" 'wdired-set-bit)
- (define-key map "s" 'wdired-set-bit)
- (define-key map "T" 'wdired-set-bit)
- (define-key map "t" 'wdired-set-bit)
- (define-key map "s" 'wdired-set-bit)
- (define-key map "l" 'wdired-set-bit)
- (define-key map [down-mouse-1] 'wdired-mouse-toggle-bit)
+ (define-key map " " #'wdired-toggle-bit)
+ (define-key map "r" #'wdired-set-bit)
+ (define-key map "w" #'wdired-set-bit)
+ (define-key map "x" #'wdired-set-bit)
+ (define-key map "-" #'wdired-set-bit)
+ (define-key map "S" #'wdired-set-bit)
+ (define-key map "s" #'wdired-set-bit)
+ (define-key map "T" #'wdired-set-bit)
+ (define-key map "t" #'wdired-set-bit)
+ (define-key map "s" #'wdired-set-bit)
+ (define-key map "l" #'wdired-set-bit)
+ (define-key map [mouse-1] #'wdired-mouse-toggle-bit)
map))
;; Put a keymap property to the permission bits of the files, and store the
;; original name and permissions as a property
-(defun wdired-preprocess-perms ()
- (let ((inhibit-read-only t))
- (setq-local wdired-col-perm nil)
- (save-excursion
- (goto-char (point-min))
- (while (not (eobp))
- (when (and (not (looking-at dired-re-sym))
- (wdired-get-filename)
- (re-search-forward dired-re-perms (line-end-position) 'eol))
- (let ((begin (match-beginning 0))
- (end (match-end 0)))
- (unless wdired-col-perm
- (setq wdired-col-perm (- (current-column) 9)))
- (if (eq wdired-allow-to-change-permissions 'advanced)
- (progn
- (put-text-property begin end 'read-only nil)
- ;; make first permission bit writable
- (put-text-property
- (1- begin) begin 'rear-nonsticky '(read-only)))
- ;; avoid that keymap applies to text following permissions
- (add-text-properties
- (1+ begin) end
- `(keymap ,wdired-perm-mode-map rear-nonsticky (keymap))))
- (put-text-property end (1+ end) 'end-perm t)
- (put-text-property
- begin (1+ begin) 'old-perm (match-string-no-properties 0))))
- (forward-line)
- (beginning-of-line)))))
+(defun wdired--preprocess-perms ()
+ (save-excursion
+ (when (and (not (looking-at dired-re-sym))
+ (wdired-get-filename)
+ (re-search-forward dired-re-perms
+ (line-end-position) 'eol))
+ (let ((begin (match-beginning 0))
+ (end (match-end 0)))
+ (if (eq wdired-allow-to-change-permissions 'advanced)
+ (progn
+ (put-text-property begin end 'read-only nil)
+ ;; make first permission bit writable
+ (put-text-property
+ (1- begin) begin 'rear-nonsticky '(read-only)))
+ ;; avoid that keymap applies to text following permissions
+ (add-text-properties
+ (1+ begin) end
+ `(keymap ,wdired-perm-mode-map rear-nonsticky (keymap))))
+ (put-text-property end (1+ end) 'end-perm t)
+ (put-text-property
+ begin (1+ begin)
+ 'old-perm (match-string-no-properties 0))))))
(defun wdired-perm-allowed-in-pos (char pos)
(cond
@@ -874,39 +923,30 @@ Like original function but it skips read-only words."
((memq char '(?t ?T)) (= pos 8))
((= char ?l) (= pos 5))))
-(defun wdired-set-bit ()
+(defun wdired-set-bit (&optional char)
"Set a permission bit character."
- (interactive)
- (if (wdired-perm-allowed-in-pos last-command-event
- (- (current-column) wdired-col-perm))
- (let ((new-bit (char-to-string last-command-event))
+ (interactive (list last-command-event))
+ (unless char (setq char last-command-event))
+ (if (wdired-perm-allowed-in-pos char
+ (- (wdired--current-column) wdired--perm-beg))
+ (let ((new-bit (char-to-string char))
(inhibit-read-only t)
- (pos-prop (- (point) (- (current-column) wdired-col-perm))))
- (put-text-property 0 1 'keymap wdired-perm-mode-map new-bit)
- (put-text-property 0 1 'read-only t new-bit)
+ (pos-prop (+ (line-beginning-position) wdired--perm-beg)))
+ (set-text-properties 0 1 (text-properties-at (point)) new-bit)
(insert new-bit)
(delete-char 1)
- (put-text-property (1- pos-prop) pos-prop 'perm-changed t)
- (put-text-property (1- (point)) (point) 'rear-nonsticky '(keymap)))
+ (put-text-property (1- pos-prop) pos-prop 'perm-changed t))
(forward-char 1)))
(defun wdired-toggle-bit ()
"Toggle the permission bit at point."
(interactive)
- (let ((inhibit-read-only t)
- (new-bit "-")
- (pos-prop (- (point) (- (current-column) wdired-col-perm))))
- (if (eq (char-after (point)) ?-)
- (setq new-bit
- (if (= (% (- (current-column) wdired-col-perm) 3) 0) "r"
- (if (= (% (- (current-column) wdired-col-perm) 3) 1) "w"
- "x"))))
- (put-text-property 0 1 'keymap wdired-perm-mode-map new-bit)
- (put-text-property 0 1 'read-only t new-bit)
- (insert new-bit)
- (delete-char 1)
- (put-text-property (1- pos-prop) pos-prop 'perm-changed t)
- (put-text-property (1- (point)) (point) 'rear-nonsticky '(keymap))))
+ (wdired-set-bit
+ (cond
+ ((not (eq (char-after (point)) ?-)) ?-)
+ ((= (% (- (wdired--current-column) wdired--perm-beg) 3) 0) ?r)
+ ((= (% (- (wdired--current-column) wdired--perm-beg) 3) 1) ?w)
+ (t ?x))))
(defun wdired-mouse-toggle-bit (event)
"Toggle the permission bit that was left clicked."