5

This might seem like a duplicate of How to customize dired's display. However, I did not find a satisfactory answer there.

Consider the following picture: columns

It has many columns: permissions, user, groups, etc. I would like to see only four: size, date, time, name. How do I achieve that?

P.S.: The accepted answer in the referenced previously asked question says that I should not mess with ls format, which leaves me no weapon against the problem.

3
  • M-x customize-variable RET dired-listing-switches RET. If man ls doesn't offer you ls switches that let you get what you want then, as the link you cited points out, you're probably better off not trying. Or else you can hack the Dired code... – Drew Sep 22 '17 at 14:41
  • If you want to be radical the other way round, hiding all details, see dired-details that allows to toggle all of them with (. – Ehvince Sep 25 '17 at 9:18
  • The strategy laid out in the accepted answer at stackoverflow is realized in my answer. Please, leave a comment below that answer if it does not work for you. I already discovered and fixed a bug for a corner case with special characters in user and group names. Maybe, there are more such corner cases. But, the code is based on the POSIX specification of ls -l and therefore should work in general. – Tobias Sep 25 '17 at 10:03
1

Intro

The following elisp code demonstrates how individual fields of the ls -l output can be hidden in dired. (It is not ideal yet but already functional.)

Installation

Put the code below into your init file, e.g., ~/.emacs or ~/.emacs.d/init.el. (Note, there should be no need to re-compile this file since it should NOT be byte-compiled anyway.)

The code is best used together with dired+.el from Drew Adams. You can install dired+.el from melpa.

Usage

After pasting the code into your init file and re-starting emacs it should already work. You can customize the hidden fields by M-x customize-option RET diredTZA-invisible-props RET. The customized options apply to newly created dired buffers.

If you have dired+ installed there is a sub-menu Dir -> Hide/Show -> Hide/Show Fields where you can select the hidden fields for the current dired buffer.

Implementation Details

In dired-after-readin-hook the ls -l fields as specified by POSIX are supplemented with additional individual invisible text properties (e.g., the size with diredTZA-size).

These invisible properties can then be added/removed to/from buffer-invisibility-spec by diredTZA-hide-field-toggle which is bound to the menu items in the dired menu Dired -> Hide/Show -> Hide Fields. This is a buffer-local effect.

(require 'cl-lib)
(require 'dired)
(require 'easymenu)

(defun add-to-invisible-prop (beg end sym &optional obj)
  "Add invisible text property SYM to region from BEG to END of object OBJ.
OBJ defaults to the current buffer."
  (declare (special interval)) ; Should not be necessary. Actually a bug in cl.
  (unless obj
    (setq obj (current-buffer)))
  (cl-loop for interval being the intervals property 'invisible from beg to end of obj do
           (let ((prop (get-text-property (car interval) 'invisible obj)))
             (put-text-property
              (car interval)
              (cdr interval)
              'invisible
              (cond
               ((null prop) sym)
               ((listp prop) (cl-union prop (list sym)))
               (t (list prop sym)))
              obj))))

(defconst diredTZA-name-regexp " *[[:alpha:]].*?"
  "Almost anything can be part of the user name.
See, e.g., http://blog.endpoint.com/2008/08/on-valid-unix-usernames-and-ones-sanity.html.
This regular expression tries to make some sensible assumption.")

(defvar diredTZA-ls-output-fields nil
  "Fields output by \"ls -l\" in one line.
Each field is a list with following members:
0: `invisible' property that is set on this field in dired buffers
1: regular expression identifying the field
2: human readable description of the field
See the POSIX specification for designing the regular expressions:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html")
(setq diredTZA-ls-output-fields
  `((diredTZA-file-type-perms " *[dbclp-]\\(?:[r-][w-][SsTtx-]\\)\\{3,3\\}[+.@ ]?" "File type & permissions")
    (diredTZA-num-of-hard-links " *[0-9]+" "Number of hard-links")
    (diredTZA-owner ,diredTZA-name-regexp "Owner")
    (diredTZA-group ,diredTZA-name-regexp "Group")
    (diredTZA-size " *[0-9.]*[0-9KMGT]" "Size")
    (diredTZA-last-modified " *[[:alpha:]]+ +[0-9]\\{1,2\\} +\\(?:[0-9]\\{1,2\\}:[0-9]\\{1,2\\}\\|[0-9]\\{4,4\\}\\)" "Date")
    (diredTZA-filename " *[^[:blank:]].*" "Name")))

(defvar diredTZA-ls-regexp nil
  "Regular expression composed of the regular expressions in `diredTZA-ls-output-fields'.
(Don't change this.)")
(setq diredTZA-ls-regexp (concat "\\(" (mapconcat 'identity (mapcar 'cadr diredTZA-ls-output-fields) "\\) +\\(") "\\)"))

(defcustom diredTZA-invisible-props '(diredTZA-file-type-perms diredTZA-num-of-hard-links diredTZA-owner diredTZA-group)
  "Details that should not be shown by dired."
  :type (append '(set) (mapcar (lambda (field) (list 'const :tag (nth 2 field) (car field))) diredTZA-ls-output-fields))
  :group 'dired-hide-details)

(defun diredTZA-add-invisible-props ()
  "Add invisible properties to fields of ls -l output in dired buffers.
Can be added to `dired-after-readin-hook'."
  (let ((inhibit-read-only t))
    (save-excursion
      (goto-char (point-min))
      (while (re-search-forward diredTZA-ls-regexp nil t)
        (cl-loop for i from 1 upto (length diredTZA-ls-output-fields) do
                 (let ((b (match-beginning i))
                       (e (match-end i)))
                   (add-to-invisible-prop b e (car (nth (1- i) diredTZA-ls-output-fields)))))))))

(add-hook 'dired-after-readin-hook #'diredTZA-add-invisible-props t)

(defun diredTZA-invisible-prop-p (sym)
  "Check whether SYM is in `buffer-invisibility-spec'."
  (if (atom buffer-invisibility-spec)
      (eq buffer-invisibility-spec sym)
    (assoc-string sym buffer-invisibility-spec)))

(defun diredTZA-hide-field-toggle (sym)
  "Toggle visibility of field SYM in the ls -l lines of dired buffers."
  (if (diredTZA-invisible-prop-p sym)
        (remove-from-invisibility-spec sym)
    (add-to-invisibility-spec sym))
  (font-lock-flush))

(defun diredTZA-hide-fields-add-menu ()
  "Add Hide/Show menu for ls -l fields in Dired menu.
Add this function to `dired-mode'."
  (easy-menu-add-item nil '("Dir" "Hide/Show")
                      (append '("Hide/Show Fields"
                                ["Customize" (customize-option 'diredTZA-invisible-props) t])
                              (mapcar
                               (lambda (field)
                                 (let ((sym (list 'quote (car field)))
                                       (doc (nth 2 field)))
                                   (vector doc
                                           `(diredTZA-hide-field-toggle ,sym)
                                           :style 'toggle
                                           :selected `(memq ,sym buffer-invisibility-spec))))
                               diredTZA-ls-output-fields)))
  (mapc #'add-to-invisibility-spec diredTZA-invisible-props))

(add-hook 'dired-mode-hook #'diredTZA-hide-fields-add-menu t)

Screenshot

The following Figure shows the code in action with emacs -q, and dired+ loaded, and default options.

Hiding ls -l fields with default options

8
  • Thank you for your answer and sorry for the delayed reply! The solution worked partially. I have dired+ installed. And perhaps I should mention that I work under Unix system. – honey_badger Sep 25 '17 at 11:33
  • @ted_kingdom Thanks for the feedback! It is the space in the group name. (I hate spaces where they don't belong.) That makes it really difficult to separate the regexps for the ls -l fields. Will see whether I can find a solution. – Tobias Sep 25 '17 at 11:42
  • @ted_kingdom User skrypnyk NET\\Domain with group Users will be indistinguishable from User skrypnyk with group Users NET\\Domain. One has to make some assumption there. – Tobias Sep 25 '17 at 11:55
  • @ted_kingdom Could you try again? – Tobias Sep 25 '17 at 12:13
  • Not yet – honey_badger Sep 25 '17 at 12:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.