diff options
Diffstat (limited to 'lisp/emacs-lisp/tabulated-list.el')
-rw-r--r-- | lisp/emacs-lisp/tabulated-list.el | 128 |
1 files changed, 88 insertions, 40 deletions
diff --git a/lisp/emacs-lisp/tabulated-list.el b/lisp/emacs-lisp/tabulated-list.el index e9bb8a8ac0d..f0ee78745ac 100644 --- a/lisp/emacs-lisp/tabulated-list.el +++ b/lisp/emacs-lisp/tabulated-list.el @@ -36,6 +36,8 @@ ;;; Code: +(eval-when-compile (require 'cl-lib)) + (defgroup tabulated-list nil "Tabulated-list customization group." :group 'convenience @@ -212,6 +214,8 @@ If ADVANCE is non-nil, move forward by one line afterwards." special-mode-map)) (define-key map "n" 'next-line) (define-key map "p" 'previous-line) + (define-key map (kbd "M-<left>") 'tabulated-list-previous-column) + (define-key map (kbd "M-<right>") 'tabulated-list-next-column) (define-key map "S" 'tabulated-list-sort) (define-key map "}" 'tabulated-list-widen-current-column) (define-key map "{" 'tabulated-list-narrow-current-column) @@ -269,42 +273,48 @@ Populated by `tabulated-list-init-header'.") ;; FIXME: Should share code with tabulated-list-print-col! (let ((x (max tabulated-list-padding 0)) (button-props `(help-echo "Click to sort by column" - mouse-face header-line-highlight - keymap ,tabulated-list-sort-button-map)) + mouse-face header-line-highlight + keymap ,tabulated-list-sort-button-map)) + (len (length tabulated-list-format)) (cols nil)) (if display-line-numbers (setq x (+ x (tabulated-list-line-number-width)))) (push (propertize " " 'display `(space :align-to ,x)) cols) - (dotimes (n (length tabulated-list-format)) + (dotimes (n len) (let* ((col (aref tabulated-list-format n)) + (not-last-col (< n (1- len))) (label (nth 0 col)) + (lablen (length label)) + (pname label) (width (nth 1 col)) (props (nthcdr 3 col)) (pad-right (or (plist-get props :pad-right) 1)) (right-align (plist-get props :right-align)) (next-x (+ x pad-right width))) + (when (and (>= lablen 3) (> lablen width) not-last-col) + (setq label (truncate-string-to-width label (- lablen 1) nil nil t))) (push (cond ;; An unsortable column ((not (nth 2 col)) - (propertize label 'tabulated-list-column-name label)) + (propertize label 'tabulated-list-column-name pname)) ;; The selected sort column ((equal (car col) (car tabulated-list-sort-key)) (apply 'propertize - (concat label - (cond - ((> (+ 2 (length label)) width) "") - ((cdr tabulated-list-sort-key) + (concat label + (cond + ((and (< lablen 3) not-last-col) "") + ((cdr tabulated-list-sort-key) (format " %c" tabulated-list-gui-sort-indicator-desc)) - (t (format " %c" + (t (format " %c" tabulated-list-gui-sort-indicator-asc)))) - 'face 'bold - 'tabulated-list-column-name label - button-props)) + 'face 'bold + 'tabulated-list-column-name pname + button-props)) ;; Unselected sortable column. (t (apply 'propertize label - 'tabulated-list-column-name label + 'tabulated-list-column-name pname button-props))) cols) (when right-align @@ -404,8 +414,7 @@ specified by `tabulated-list-sort-key'. It then erases the buffer and inserts the entries with `tabulated-list-printer'. Optional argument REMEMBER-POS, if non-nil, means to move point -to the entry with the same ID element as the current line and -recenter window line accordingly. +to the entry with the same ID element as the current line. Non-nil UPDATE argument means to use an alternative printing method which is faster if most entries haven't changed since the @@ -418,18 +427,10 @@ changing `tabulated-list-sort-key'." (funcall tabulated-list-entries) tabulated-list-entries)) (sorter (tabulated-list--get-sorter)) - entry-id saved-pt saved-col window-line) + entry-id saved-pt saved-col) (and remember-pos (setq entry-id (tabulated-list-get-id)) - (setq saved-col (current-column)) - (when (eq (window-buffer) (current-buffer)) - (setq window-line - (save-excursion - (save-restriction - (widen) - (narrow-to-region (window-start) (point)) - (goto-char (point-min)) - (vertical-motion (buffer-size))))))) + (setq saved-col (current-column))) ;; Sort the entries, if necessary. (when sorter (setq entries (sort entries sorter))) @@ -484,9 +485,7 @@ changing `tabulated-list-sort-key'." ;; If REMEMBER-POS was specified, move to the "old" location. (if saved-pt (progn (goto-char saved-pt) - (move-to-column saved-col) - (when window-line - (recenter window-line))) + (move-to-column saved-col)) (goto-char (point-min))))) (defun tabulated-list-print-entry (id cols) @@ -547,10 +546,10 @@ Return the column number after insertion." ;; Don't truncate to `width' if the next column is align-right ;; and has some space left, truncate to `available-space' instead. (when (and not-last-col - (> label-width available-space) - (setq label (truncate-string-to-width - label available-space nil nil t t) - label-width available-space))) + (> label-width available-space)) + (setq label (truncate-string-to-width + label available-space nil nil t t) + label-width available-space)) (setq label (bidi-string-mark-left-to-right label)) (when (and right-align (> width label-width)) (let ((shift (- width label-width))) @@ -650,18 +649,41 @@ this is the vector stored within it." (defun tabulated-list-sort (&optional n) "Sort Tabulated List entries by the column at point. -With a numeric prefix argument N, sort the Nth column." +With a numeric prefix argument N, sort the Nth column. + +If the numeric prefix is -1, restore order the list was +originally displayed in." (interactive "P") - (let ((name (if n - (car (aref tabulated-list-format n)) - (get-text-property (point) - 'tabulated-list-column-name)))) - (if (nth 2 (assoc name (append tabulated-list-format nil))) - (tabulated-list--sort-by-column-name name) - (user-error "Cannot sort by %s" name)))) + (if (equal n -1) + ;; Restore original order. + (progn + (unless tabulated-list--original-order + (error "Order is already in original order")) + (setq tabulated-list-entries + (sort tabulated-list-entries + (lambda (e1 e2) + (< (gethash e1 tabulated-list--original-order) + (gethash e2 tabulated-list--original-order))))) + (setq tabulated-list-sort-key nil) + (tabulated-list-init-header) + (tabulated-list-print t)) + ;; Sort based on a column name. + (let ((name (if n + (car (aref tabulated-list-format n)) + (get-text-property (point) + 'tabulated-list-column-name)))) + (if (nth 2 (assoc name (append tabulated-list-format nil))) + (tabulated-list--sort-by-column-name name) + (user-error "Cannot sort by %s" name))))) (defun tabulated-list--sort-by-column-name (name) (when (and name (derived-mode-p 'tabulated-list-mode)) + (unless tabulated-list--original-order + ;; Store the original order so that we can restore it later. + (setq tabulated-list--original-order (make-hash-table)) + (cl-loop for elem in tabulated-list-entries + for i from 0 + do (setf (gethash elem tabulated-list--original-order) i))) ;; Flip the sort order on a second click. (if (equal name (car tabulated-list-sort-key)) (setcdr tabulated-list-sort-key @@ -720,8 +742,32 @@ Interactively, N is the prefix numeric argument, and defaults to (setq-local tabulated-list--current-lnum-width lnum-width) (tabulated-list-init-header))))) +(defun tabulated-list-next-column (&optional arg) + "Go to the start of the next column after point on the current line. +If ARG is provided, move that many columns." + (interactive "p") + (dotimes (_ (or arg 1)) + (let ((next (or (next-single-property-change + (point) 'tabulated-list-column-name) + (point-max)))) + (when (<= next (line-end-position)) + (goto-char next))))) + +(defun tabulated-list-previous-column (&optional arg) + "Go to the start of the column point is in on the current line. +If ARG is provided, move that many columns." + (interactive "p") + (dotimes (_ (or arg 1)) + (let ((prev (or (previous-single-property-change + (point) 'tabulated-list-column-name) + 1))) + (unless (< prev (line-beginning-position)) + (goto-char prev))))) + ;;; The mode definition: +(defvar tabulated-list--original-order nil) + (define-derived-mode tabulated-list-mode special-mode "Tabulated" "Generic major mode for browsing a list of items. This mode is usually not used directly; instead, other major @@ -761,6 +807,8 @@ as the ewoc pretty-printer." (setq-local revert-buffer-function #'tabulated-list-revert) (setq-local glyphless-char-display (tabulated-list-make-glyphless-char-display-table)) + (setq-local text-scale-remap-header-line t) + (setq-local tabulated-list--original-order nil) ;; Avoid messing up the entries' display just because the first ;; column of the first entry happens to begin with a R2L letter. (setq bidi-paragraph-direction 'left-to-right) |