unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Partial wdired (edit just filename at the point)
@ 2021-03-16 18:23 Arthur Miller
  2021-03-17  1:18 ` Stefan Monnier
  0 siblings, 1 reply; 33+ messages in thread
From: Arthur Miller @ 2021-03-16 18:23 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1512 bytes --]


Wdired is really nice for batch renaming files, but I have noticed that
in case there are lots of files, starting wdired mode and finalizing
changes can take a while. Sometimes I switch to wdired mode just to rename
a single file. On my machine, a directory with ~700 - 800 files causes
a noticable delay. I haven't measured but it is in range of 2-3
seconds I would guess. I had one directory with almost 2000 files and
when tested it took quite a bit of time.

I traced it down to how dired/wdired use text properties to controll if
text is writable or not. When switching to, wdired goes three times
through entire buffer (filenames, perms and symlinks) and changes text
properties to writable text.

I have rewritten those few functions to drop to wdired mode to only work
on a line under the point; it is just quick copy/paste hack. It
works fine for my needs and wdired starts without noticable delay, but
there is one cosmetic detail: despite me changing properties only for
current line, wdired still let me edit other text in dired buffer
itself.

When saving changes, it properly saves only the intended line. I don't
seem to be able to find which property affect that behaviour, wonder if
someone can help in that regard?

Another question: is this interesting to add to wdired? It makes Emacs
behave a bit more like standard file managers; they usually bound F2
(for example Dolphing) to file-rename operation.

Error checking is needed to handle cases when point is not in a line
with a filename.


[-- Attachment #2: partial-wdired.el --]
[-- Type: text/plain, Size: 5412 bytes --]

(defun wdired-change-to-partial-wdired-mode ()
  "Put a Dired buffer in Writable Dired (WDired) mode.
\\<wdired-mode-map>
In WDired mode, you can edit the names of the files in the
buffer, the target of the links, and the permission bits of the
files.  After typing \\[wdired-finish-edit], Emacs modifies the files and
directories to reflect your edits.

See `wdired-mode'."
  (interactive)
  (unless (derived-mode-p 'dired-mode)
    (error "Not a Dired buffer"))
  (setq-local wdired-old-content
              (buffer-substring (line-beginning-position) (line-end-position)))
  (setq-local wdired-old-marks
              (dired-remember-marks (line-beginning-position) (line-end-position)))
  (setq-local wdired-old-point (point))
  (setq-local query-replace-skip-read-only t)
  (add-function :after-while (local 'isearch-filter-predicate)
                #'wdired-isearch-filter-read-only)
  (use-local-map wdired-mode-map)
  (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)
  (setq major-mode 'wdired-mode)
  (setq mode-name "Partially 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-partial-preprocess-files)
  (if wdired-allow-to-change-permissions
      (wdired-partial-preprocess-perms))
  (if (fboundp 'make-symbolic-link)
      (wdired-partial-preprocess-symlinks))
  (buffer-enable-undo) ; Performance hack. See above.
  (set-buffer-modified-p nil)
  (setq buffer-undo-list nil)
  (run-mode-hooks 'wdired-mode-hook)
  (message "%s" (substitute-command-keys
		 "Press \\[wdired-finish-edit] when finished \
or \\[wdired-abort-changes] to abort changes")))

(defun wdired-abort-changes ()
  "Abort changes and return to dired mode."
  (interactive)
  (let ((inhibit-read-only t))
    (if (equal mode-name "Partially Editable Dired")
        (delete-region (line-beginning-position) (line-end-position))
      (erase-buffer))
    (insert wdired-old-content)
    (goto-char wdired-old-point))
  (wdired-change-to-dired-mode)
  (set-buffer-modified-p nil)
  (setq buffer-undo-list nil)
  (message "Changes aborted"))

;; Protect the buffer so only the filename can be changed, and put
;; properties so filename (old and new) can be easily found.
(defun wdired-partial-preprocess-files ()
  (put-text-property (line-beginning-position) (1+ (line-beginning-position))'front-sticky t)
  (save-excursion
    (goto-char (line-beginning-position))
    (let ((b-protection (point))
          (used-F (dired-check-switches dired-actual-switches "F" "classify"))
	  filename)
      (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))
      (put-text-property b-protection (line-end-position) 'read-only t))))

(defun wdired-partial-preprocess-perms ()
  (let ((inhibit-read-only t))
    (setq-local wdired-col-perm nil)
    (save-excursion
      (goto-char (line-beginning-position))
      (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)))))))

(defun wdired-partial-preprocess-symlinks ()
  (let ((inhibit-read-only t))
    (save-excursion
      (goto-char (line-beginning-position))
      (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))))))

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2021-03-23 23:32 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-16 18:23 Partial wdired (edit just filename at the point) Arthur Miller
2021-03-17  1:18 ` Stefan Monnier
2021-03-17  2:21   ` Arthur Miller
2021-03-17  2:34     ` Stefan Monnier
2021-03-17 13:58       ` Arthur Miller
2021-03-17 14:09         ` Stefan Monnier
2021-03-17 19:56           ` Arthur Miller
2021-03-17 22:40             ` Arthur Miller
2021-03-18  2:10               ` Stefan Monnier
2021-03-18 10:26                 ` Arthur Miller
2021-03-18 10:32                   ` Thierry Volpiatto
2021-03-18 11:00                     ` Arthur Miller
2021-03-18 11:11                       ` Thierry Volpiatto
2021-03-18 11:46                         ` Arthur Miller
2021-03-23 23:32                     ` Michael Heerdegen
2021-03-18 14:21                   ` Stefan Monnier
2021-03-19 11:15                     ` Arthur Miller
2021-03-19 16:18                       ` Stefan Monnier
2021-03-19 20:40                         ` Sv: " arthur miller
2021-03-19 21:58                           ` Stefan Monnier
2021-03-20 11:23                             ` Sv: " arthur miller
2021-03-21 22:17                 ` Tomas Hlavaty
2021-03-22  8:12                   ` tomas
2021-03-22 12:44                     ` Arthur Miller
2021-03-22 14:50                       ` tomas
2021-03-22 13:11                   ` Stefan Monnier
2021-03-22 20:08                     ` Tomas Hlavaty
2021-03-22 20:28                       ` Andreas Schwab
2021-03-22 21:00                       ` Stefan Monnier
2021-03-22 21:52                         ` Tomas Hlavaty
2021-03-22 22:16                           ` Stefan Monnier
2021-03-22 22:39                             ` Tomas Hlavaty
2021-03-22 23:27                           ` Andreas Schwab

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).