[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: dired-move-to-filename-regexp

From: Stefan
Subject: Re: dired-move-to-filename-regexp
Date: Sat, 25 Sep 2004 15:08:04 -0400
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3.50 (darwin)

>> That would be rather unreliable, since it would need to figure out the
>> number of spaces between fields in both the new output and the old
>> buffer.  The gains that we got from --dired would be lost.
>> I won't accept this approach.

>     Of course, the filename part would be determined just as it is now (using
>     the --dired data if available, for example).

> Ok, you're right about that part.  When using --dired, we would
> still reliably find the filename.  But finding where to insert extra
> spaces would not be entirely reliable, just as finding the file name
> was not entirely reliable in the past.

See below a sample patch that "worked for me".
Indeed, finding the places where to insert spaces is not entirely reliable,
but adding spaces as is done below shouldn't make things worse.
There are 2 cases I can think of where the code could pose problem:
1 - the dired-move-to-filename-regexp needs a specific number of spaces
    at some spot.  This is a rare problem but can happen when we don't
    use --dired.  Examples are the nunber of spaces between day and month,
    which is typically either one or 2 spaces, never more.
2 - If dired-move-to-filename initially gets it wrong (and goes too far),
    we may end up adding spaces in the actual file name.
    This is not as bad as it sounds:
    - It's extremely unlikely because we only add spaces "to align
      filenames" (once the filename is aligned to neighboring filenames, we
      don't add any spaces any more), so if dired-move-to-filename goes too
      far, it's very unlikely that we'll add spaces because it's most likely
      going to be already further than neighboring filenames.
    - It's a situation in which even without adding spaces, dired is all
      confused, so it's not clear we'll make things worse.

Number 1 is actually solved in the code by being paranoid and checking each
time we insert spaces that the outcome of dired-move-to-filename has not
been affected (and reverting the change if it did).

Number 2 could be reduced by trying to make sure that such misidentifications
don't happen.  This could be done e.g. by checking
(file-exists-p (dired-get-filename)).  The code below does not bother to do
that, but it can be easily added.


PS: I rarely use dired myself, so this is very lightly tested.

--- orig/lisp/dired.el
+++ mod/lisp/dired.el
@@ -798,6 +798,98 @@
        (dired-insert-directory dir dired-actual-switches
                                file-list (not file-list) t)))))
+(defun dired-align-file (beg end)
+  "Align the fields of a file to the ones of surrounding lines.
+BEG..END is the line where the file info is located."
+  ;; Some versions of ls try to adjust the size of each field so as to just
+  ;; hold the largest element ("largest" in the current invocation, of
+  ;; course).  So when a single line is output, the size of each field is
+  ;; just big enough for that one output.  Thus when dired refreshes one
+  ;; line, the alignment if this line w.r.t the rest is messed up because
+  ;; the fields of that one line will generally be smaller.
+  ;;
+  ;; To work around this problem, we here add spaces to try and re-align the
+  ;; fields as needed.  Since this is purely aesthetic, it is of utmost
+  ;; importance that it doesn't mess up anything like
+  ;; `dired-move-to-filename'.  To this end, we limit ourselves to adding
+  ;; spaces only, and to only add them at places where there was already at
+  ;; least one space.  This way, as long as `dired-move-to-filename-regexp'
+  ;; always matches spaces with "*" or "+", we know we haven't made anything
+  ;; worse.  There is one spot where the exact number of spaces is
+  ;; important, which is just before the actual filename, so we refrain from
+  ;; adding spaces there (and within the filename as well, of course).
+  (save-excursion
+    (let (file file-col other other-col)
+      ;; Check the there is indeed a file, and that there is anoter adjacent
+      ;; file with which to align, and that additional spaces are needed to
+      ;; align the filenames.
+      (when (and (setq file (progn (goto-char beg)
+                                  (dired-move-to-filename nil end)))
+                (setq file-col (current-column))
+                (setq other
+                      (or (progn (goto-char beg) (forward-line -1)
+                                 (dired-move-to-filename))
+                          (progn (goto-char beg) (forward-line 1)
+                                 (dired-move-to-filename))))
+                (setq other-col (current-column))
+                ;; Make sure there is some work left to do.
+                (> other-col file-col))
+       ;; Keep positions uptodate when we insert stuff.
+       (if (> other file) (setq other (copy-marker other)))
+       (setq file (copy-marker file))
+       ;; Main loop.
+       (goto-char beg)
+       (while (and (> other-col file-col)
+                   (skip-chars-forward "^ ")
+                   ;; Skip the spaces, and make sure there's at least one.
+                   (> (skip-chars-forward " ") 0)
+                   ;; Don't touch anything just before (and after) the
+                   ;; beginning of the filename.
+                   (> file (point)))
+         ;; We're now just in front of a field, with a space behind us.
+         (let* ((curcol (current-column))
+                ;; Nums are right-aligned.
+                (num-align (looking-at "[0-9]"))
+                ;; Let's look at the other line, in the same column: we
+                ;; should be either near the end of the previous field, or
+                ;; in the space between that field and the next.
+                ;; [ Of course, it's also possible that we're already within
+                ;; the next field or even past it, but that's highly
+                ;; unlikely since other-col > file-col. ]
+                ;; Let's find the distance to the alignment-point (either
+                ;; the beginning or the end of the next field, depending on
+                ;; whether this field is left or right aligned).
+                (align-pt-offset
+                 (save-excursion
+                   (goto-char other)
+                   (move-to-column curcol)
+                   (when (looking-at
+                          (concat
+                           (if (eq (char-before) ?\ ) " *" "[^ ]* *")
+                           (if num-align "[0-9][^ ]*")))
+                     (- (match-end 0) (match-beginning 0)))))
+                ;; Now, the number of spaces to insert is align-pt-offset
+                ;; minus the distance to the equivalent point on the
+                ;; current line.
+                (spaces
+                 (if (not num-align)
+                     align-pt-offset
+                   (and align-pt-offset
+                        (save-excursion
+                          (skip-chars-forward "^ ")
+                          (- align-pt-offset (- (current-column) curcol)))))))
+           (when (and spaces (> spaces 0))
+             (setq file-col (+ spaces file-col))
+             (if (> file-col other-col)
+                 (setq spaces (- spaces (- file-col other-col))))
+             (insert-char ?\s spaces)
+             ;; Let's just make really sure we did not mess up.
+             (save-excursion
+               (unless (and (dired-move-to-filename) (= (point) file))
+                 ;; Damn!  We messed up: let's revert the change.
+                 (delete-char (- spaces)))))))))))
 (defun dired-insert-directory (dir switches &optional file-list wildcard hdr)
   "Insert a directory listing of DIR, Dired style.
 Use SWITCHES to make the listings.
@@ -816,7 +909,10 @@
     ;; with the new value of dired-move-to-filename-regexp.
     (if file-list
        (dolist (f file-list)
-         (insert-directory f switches nil nil))
+         (let ((beg (point)))
+           (insert-directory f switches nil nil)
+           ;; Re-align fields, if necessary.
+           (dired-align-file beg (point))))
       (insert-directory dir switches wildcard (not wildcard)))
     ;; Quote certain characters, unless ls quoted them for us.
     (if (not (string-match "b" dired-actual-switches))

reply via email to

[Prev in Thread] Current Thread [Next in Thread]