4 | 4 |
;; Author: Andreas Politz <politza@fh-trier.de>
|
5 | 5 |
;; Keywords: extensions, lisp
|
6 | 6 |
;; Package: tablist
|
7 | |
;; Version: 0.70
|
|
7 |
;; Version: 1.0
|
8 | 8 |
;; Package-Requires: ((emacs "24.3"))
|
9 | 9 |
|
10 | 10 |
;; This program is free software; you can redistribute it and/or modify
|
|
28 | 28 |
;; It can be used by deriving from tablist-mode and some features by
|
29 | 29 |
;; using tablist-minor-mode inside a tabulated-list-mode buffer.
|
30 | 30 |
;;
|
|
31 |
|
|
32 |
;;; Code:
|
31 | 33 |
|
32 | 34 |
(require 'cl-lib)
|
33 | 35 |
(require 'ring)
|
|
77 | 79 |
(replace-regexp-in-string
|
78 | 80 |
"[\t ]+" "[\t ]*" (regexp-quote
|
79 | 81 |
(or (thing-at-point 'line) ""))
|
80 | |
t t))
|
|
82 |
t t))
|
81 | 83 |
(,id (tabulated-list-get-id))
|
82 | 84 |
(,col (tablist-current-column)))
|
83 | 85 |
(progn
|
|
116 | 118 |
|
117 | 119 |
;;
|
118 | 120 |
;; *Mode Maps
|
119 | |
;;
|
|
121 |
;;
|
120 | 122 |
|
121 | 123 |
(defvar tablist-mode-filter-map
|
122 | 124 |
(let ((kmap (make-sparse-keymap)))
|
|
197 | 199 |
;; (define-key kmap (kbd "C-o") 'tablist-display-item)
|
198 | 200 |
kmap))
|
199 | 201 |
|
200 | |
|
201 | 202 |
;;
|
202 | 203 |
;; *Variables
|
203 | 204 |
;;
|
|
231 | 232 |
should somehow delete these entries and update
|
232 | 233 |
`tabulated-list-entries'.
|
233 | 234 |
|
234 | |
`find-entry'
|
|
235 |
`find-entry'
|
235 | 236 |
|
236 | 237 |
The 2nd argument is the ID of an entry. The function should
|
237 | 238 |
somehow find/display this entry, i.e. a kind of default
|
|
290 | 291 |
;;
|
291 | 292 |
|
292 | 293 |
(defvar savehist-additional-variables)
|
293 | |
(add-hook 'savehist-save-hook
|
294 | |
(lambda nil
|
295 | |
(add-to-list 'savehist-additional-variables 'tablist-named-filter)))
|
|
294 |
(add-hook 'savehist-save-hook
|
|
295 |
(lambda nil
|
|
296 |
(add-to-list 'savehist-additional-variables 'tablist-named-filter)))
|
296 | 297 |
|
297 | 298 |
;;;###autoload
|
298 | 299 |
(define-minor-mode tablist-minor-mode
|
|
343 | 344 |
(selected (tabulated-list-get-id)))
|
344 | 345 |
(unless (eq selected id)
|
345 | 346 |
(setq tablist-selected-id selected)
|
346 | |
(run-hook-with-args
|
|
347 |
(run-hook-with-args
|
347 | 348 |
'tablist-selection-changed-functions
|
348 | 349 |
tablist-selected-id)))))
|
349 | 350 |
|
350 | 351 |
(defvar tablist-context-window-update--timer nil)
|
351 | |
|
|
352 |
|
352 | 353 |
(defun tablist-context-window-update (&optional id)
|
353 | 354 |
(when (and tablist-context-window-function
|
354 | 355 |
(window-live-p tablist-context-window)
|
|
359 | 360 |
(cancel-timer tablist-context-window-update--timer))
|
360 | 361 |
(setq tablist-context-window-update--timer
|
361 | 362 |
(run-with-idle-timer 0.1 nil
|
362 | |
(lambda (fn window)
|
363 | |
(when (window-live-p window)
|
364 | |
(with-selected-window window
|
365 | |
(set-window-dedicated-p nil nil)
|
366 | |
(save-selected-window
|
367 | |
(funcall fn id))
|
368 | |
(when (window-live-p (selected-window))
|
369 | |
(set-window-dedicated-p nil t)))))
|
370 | |
tablist-context-window-function
|
371 | |
tablist-context-window))))
|
|
363 |
(lambda (fn window)
|
|
364 |
(when (window-live-p window)
|
|
365 |
(with-selected-window window
|
|
366 |
(set-window-dedicated-p nil nil)
|
|
367 |
(save-selected-window
|
|
368 |
(funcall fn id))
|
|
369 |
(when (window-live-p (selected-window))
|
|
370 |
(set-window-dedicated-p nil t)))))
|
|
371 |
tablist-context-window-function
|
|
372 |
tablist-context-window))))
|
372 | 373 |
|
373 | 374 |
(defun tablist-display-context-window ()
|
374 | 375 |
(interactive)
|
|
395 | 396 |
(if (window-live-p tablist-context-window)
|
396 | 397 |
(tablist-hide-context-window)
|
397 | 398 |
(tablist-display-context-window)))
|
398 | |
|
399 | |
|
|
399 |
|
400 | 400 |
;;
|
401 | 401 |
;; *Marking
|
402 | 402 |
;;
|
|
414 | 414 |
(if (numberp tablist-major-columns)
|
415 | 415 |
(list tablist-major-columns)
|
416 | 416 |
tablist-major-columns)))
|
417 | |
|
|
417 |
|
418 | 418 |
(defun tablist-put-mark (&optional pos)
|
419 | 419 |
"Put a mark before the entry at POS.
|
420 | 420 |
|
|
538 | 538 |
(pcase new
|
539 | 539 |
(?D
|
540 | 540 |
(tablist-flag-forward 1))
|
541 | |
(t
|
|
541 |
(_
|
542 | 542 |
(let ((tablist-marker-char new)
|
543 | 543 |
(tablist-marked-face
|
544 | 544 |
(and default-mark-p
|
|
646 | 646 |
(list (funcall fn))))
|
647 | 647 |
(t
|
648 | 648 |
(cl-labels ((search (re)
|
649 | |
(let (sucess)
|
650 | |
(tablist-skip-invisible-entries)
|
651 | |
(while (and (setq sucess
|
652 | |
(re-search-forward re nil t))
|
653 | |
(invisible-p (point)))
|
654 | |
(tablist-forward-entry))
|
655 | |
sucess)))
|
|
649 |
(let (sucess)
|
|
650 |
(tablist-skip-invisible-entries)
|
|
651 |
(while (and (setq sucess
|
|
652 |
(re-search-forward re nil t))
|
|
653 |
(invisible-p (point)))
|
|
654 |
(tablist-forward-entry))
|
|
655 |
sucess)))
|
656 | 656 |
(let ((regexp (tablist-marker-regexp))
|
657 | 657 |
next-position results found)
|
658 | 658 |
(save-excursion
|
|
813 | 813 |
:right-align)
|
814 | 814 |
(not (= n (1- (length columns)))))
|
815 | 815 |
(forward-char (1- (car (cdr (elt tabulated-list-format n)))))))))
|
816 | |
|
817 | |
|
818 | 816 |
|
819 | 817 |
(defun tablist-move-to-major-column (&optional first-skip-invisible-p)
|
820 | 818 |
"Move to the first major column."
|
|
880 | 878 |
'invisible nil (point-max)))))
|
881 | 879 |
(not (invisible-p (point))))
|
882 | 880 |
|
883 | |
;;
|
|
881 |
;;
|
884 | 882 |
;; *Operations
|
885 | 883 |
;;
|
886 | 884 |
|
|
906 | 904 |
op-str
|
907 | 905 |
(tablist-mark-prompt arg pp-items)))))
|
908 | 906 |
|
909 | |
|
910 | 907 |
(defun tablist-operation-available-p (op)
|
911 | 908 |
(and (functionp tablist-operations-function)
|
912 | 909 |
(memq op (funcall tablist-operations-function
|
|
949 | 946 |
(message (format "Killed %d line%s"
|
950 | 947 |
(length positions)
|
951 | 948 |
(dired-plural-s (length positions))))))))
|
952 | |
|
|
949 |
|
953 | 950 |
(defun tablist-do-operation (arg fn operation &optional delete-p revert-p)
|
954 | 951 |
"Operate on marked items.
|
955 | 952 |
|
|
972 | 969 |
(tablist-revert))
|
973 | 970 |
(tablist-move-to-major-column))))
|
974 | 971 |
|
975 | |
;;
|
|
972 |
;;
|
976 | 973 |
;; *Editing
|
977 | |
;;
|
|
974 |
;;
|
978 | 975 |
(defvar tablist-edit-column-minor-mode-map
|
979 | 976 |
(let ((kmap (make-sparse-keymap)))
|
980 | 977 |
(set-keymap-parent kmap (current-global-map))
|
|
989 | 986 |
(define-key kmap [remap beginning-of-buffer] 'beginning-of-line)
|
990 | 987 |
(define-key kmap [remap mark-whole-buffer] 'tablist-edit-column-mark-field)
|
991 | 988 |
kmap))
|
992 | |
|
|
989 |
|
993 | 990 |
(define-minor-mode tablist-edit-column-minor-mode
|
994 | 991 |
"" nil nil nil
|
995 | 992 |
(unless (or tablist-minor-mode
|
|
1004 | 1001 |
(t
|
1005 | 1002 |
(remove-hook 'post-command-hook 'tablist-edit-column-constrain-point t)
|
1006 | 1003 |
(read-only-mode 1))))
|
1007 | |
|
1008 | |
|
|
1004 |
|
1009 | 1005 |
(defun tablist-edit-column (&optional n)
|
1010 | 1006 |
(interactive "P")
|
1011 | 1007 |
(unless n (setq n (tablist-current-column)))
|
|
1053 | 1049 |
(overlay-put ov 'evaporate t)
|
1054 | 1050 |
(overlay-put ov 'tablist-edit t)
|
1055 | 1051 |
(tablist-edit-column-minor-mode 1)))
|
1056 | |
|
|
1052 |
|
1057 | 1053 |
(defun tablist-edit-column-quit ()
|
1058 | 1054 |
(interactive)
|
1059 | 1055 |
(tablist-edit-column-commit t))
|
|
1090 | 1086 |
(save-excursion
|
1091 | 1087 |
(tabulated-list-print-entry id entry))
|
1092 | 1088 |
(forward-char (nth column (tablist-column-offsets))))))
|
1093 | |
|
|
1089 |
|
1094 | 1090 |
(defun tablist-edit-column-complete ()
|
1095 | 1091 |
(interactive)
|
1096 | 1092 |
(unless (tablist-operation-available-p 'complete)
|
|
1108 | 1104 |
(- (point) beg))))
|
1109 | 1105 |
(unless completions
|
1110 | 1106 |
(error "No completions available"))
|
1111 | |
(completion-in-region beg end completions))))
|
1112 | |
|
|
1107 |
(completion-in-region beg end completions))))
|
|
1108 |
|
1113 | 1109 |
(defun tablist-column-editable (n)
|
1114 | 1110 |
(and (tablist-operation-available-p 'edit-column)
|
1115 | 1111 |
(not (tablist-column-property n :read-only))))
|
|
1154 | 1150 |
(setq end pos
|
1155 | 1151 |
beg (previous-single-property-change
|
1156 | 1152 |
pos 'tablist-edit))))
|
1157 | |
|
|
1153 |
|
1158 | 1154 |
(unless (and beg end (get-text-property beg 'tablist-edit))
|
1159 | 1155 |
(error "Unable to locate edited text"))
|
1160 | 1156 |
(cons beg (if skip-final-space (1- end) end))))
|
1161 | |
|
|
1157 |
|
1162 | 1158 |
(defun tablist-edit-column-mark-field ()
|
1163 | 1159 |
(interactive)
|
1164 | 1160 |
(push-mark (field-beginning))
|
|
1333 | 1329 |
(unless (buffer-live-p outb)
|
1334 | 1330 |
(error "Expected a live buffer: %s" outb))
|
1335 | 1331 |
(cl-labels
|
1336 | |
((printit (entry)
|
1337 | |
(insert
|
1338 | |
(mapconcat
|
1339 | |
(lambda (e)
|
1340 | |
(unless (stringp e)
|
1341 | |
(setq e (car e)))
|
1342 | |
(if (or always-quote-p
|
1343 | |
(string-match escape-re e))
|
1344 | |
(concat "\""
|
1345 | |
(replace-regexp-in-string "\"" "\"\"" e t t)
|
1346 | |
"\"")
|
1347 | |
e))
|
1348 | |
entry separator))
|
1349 | |
(insert ?\n)))
|
|
1332 |
((printit (entry)
|
|
1333 |
(insert
|
|
1334 |
(mapconcat
|
|
1335 |
(lambda (e)
|
|
1336 |
(unless (stringp e)
|
|
1337 |
(setq e (car e)))
|
|
1338 |
(if (or always-quote-p
|
|
1339 |
(string-match escape-re e))
|
|
1340 |
(concat "\""
|
|
1341 |
(replace-regexp-in-string "\"" "\"\"" e t t)
|
|
1342 |
"\"")
|
|
1343 |
e))
|
|
1344 |
entry separator))
|
|
1345 |
(insert ?\n)))
|
1350 | 1346 |
(with-current-buffer outb
|
1351 | 1347 |
(let ((inhibit-read-only t))
|
1352 | 1348 |
(erase-buffer)
|
|
1394 | 1390 |
(tablist-save-marks
|
1395 | 1391 |
(tabulated-list-init-header)
|
1396 | 1392 |
(tabulated-list-print)))))
|
1397 | |
|
1398 | 1393 |
|
1399 | 1394 |
(defun tablist-shrink-column (&optional column width)
|
1400 | 1395 |
(interactive
|
|
1402 | 1397 |
3)))
|
1403 | 1398 |
(tablist-enlarge-column column (- (or width 1))))
|
1404 | 1399 |
|
1405 | |
|
1406 | 1400 |
;; *Sorting
|
1407 | |
;;
|
|
1401 |
;;
|
1408 | 1402 |
|
1409 | 1403 |
(defun tablist-sort (&optional column)
|
1410 | 1404 |
"Sort the tabulated-list by COLUMN.
|
|
1512 | 1506 |
(when (and filter
|
1513 | 1507 |
(null tablist-filter-suspended))
|
1514 | 1508 |
(tablist-with-remembering-entry
|
1515 | |
(tablist-map-with-filter
|
1516 | |
(lambda nil
|
1517 | |
(if tablist-umark-filtered-entries
|
1518 | |
(save-excursion (tablist-unmark-forward)))
|
1519 | |
(tablist-filter-hide-entry))
|
1520 | |
(tablist-filter-negate filter))))
|
|
1509 |
(tablist-map-with-filter
|
|
1510 |
(lambda nil
|
|
1511 |
(if tablist-umark-filtered-entries
|
|
1512 |
(save-excursion (tablist-unmark-forward)))
|
|
1513 |
(tablist-filter-hide-entry))
|
|
1514 |
(tablist-filter-negate filter))))
|
1521 | 1515 |
(force-mode-line-update))
|
1522 | 1516 |
|
1523 | 1517 |
(defadvice tabulated-list-print (after tabulated-list activate)
|
|
1538 | 1532 |
"Call FN for every unfiltered entry matching FILTER."
|
1539 | 1533 |
(prog1
|
1540 | 1534 |
(cl-labels ((search ()
|
1541 | |
(tablist-skip-invisible-entries)
|
1542 | |
(while (and (not (eobp))
|
1543 | |
(not (tablist-eval-filter filter)))
|
1544 | |
(tablist-forward-entry))
|
1545 | |
(unless (eobp)
|
1546 | |
(point-marker))))
|
|
1535 |
(tablist-skip-invisible-entries)
|
|
1536 |
(while (and (not (eobp))
|
|
1537 |
(not (tablist-eval-filter filter)))
|
|
1538 |
(tablist-forward-entry))
|
|
1539 |
(unless (eobp)
|
|
1540 |
(point-marker))))
|
1547 | 1541 |
(let (next-position results)
|
1548 | 1542 |
(save-excursion
|
1549 | 1543 |
(goto-char (point-min))
|
|
1562 | 1556 |
|
1563 | 1557 |
;;
|
1564 | 1558 |
;; **Filter Commands
|
1565 | |
;;
|
|
1559 |
;;
|
1566 | 1560 |
(defun tablist-push-filter (filter &optional interactive or-p)
|
1567 | 1561 |
(setq tablist-current-filter
|
1568 | 1562 |
(tablist-filter-push
|
|
1730 | 1724 |
(when mode-filter
|
1731 | 1725 |
(setcdr mode-filter
|
1732 | 1726 |
(cl-remove name (cdr mode-filter)
|
1733 | |
:test 'equal :key 'car)))))
|
|
1727 |
:test 'equal :key 'car)))))
|
1734 | 1728 |
|
1735 | 1729 |
(defun tablist-name-current-filter (name)
|
1736 | 1730 |
(interactive
|
|
1748 | 1742 |
tablist-current-filter))
|
1749 | 1743 |
(setq tablist-current-filter name)
|
1750 | 1744 |
(force-mode-line-update))
|
1751 | |
|
|
1745 |
|
1752 | 1746 |
(defun tablist-deconstruct-named-filter ()
|
1753 | 1747 |
(interactive)
|
1754 | 1748 |
(let (found)
|
|
1767 | 1761 |
(unless found
|
1768 | 1762 |
(error "No named filter found"))
|
1769 | 1763 |
(force-mode-line-update)))
|
1770 | |
|
1771 | |
|
|
1764 |
|
1772 | 1765 |
(defun tablist-filter-names (&optional mode)
|
1773 | 1766 |
(mapcar 'car (cdr (assq (or mode major-mode)
|
1774 | 1767 |
tablist-named-filter))))
|
|
1825 | 1818 |
"Display the current filter according to FLAG.
|
1826 | 1819 |
|
1827 | 1820 |
If FLAG has the value 'toggle, toggle it's visibility.
|
1828 | |
If FLAG has the 'state, then do nothing but return the current
|
|
1821 |
If FLAG has the 'state, then do nothing but return the current
|
1829 | 1822 |
visibility."
|
1830 | 1823 |
(interactive (list 'toggle))
|
1831 | 1824 |
(let* ((tag 'tablist-display-filter-mode-line-tag)
|
|
1860 | 1853 |
|
1861 | 1854 |
;;
|
1862 | 1855 |
;; **Hiding/Unhiding Entries
|
1863 | |
;;
|
|
1856 |
;;
|
1864 | 1857 |
(defun tablist-filter-set-entry-hidden (flag &optional pos)
|
1865 | 1858 |
(save-excursion
|
1866 | 1859 |
(when pos (goto-char pos))
|
|
1883 | 1876 |
(remove-text-properties
|
1884 | 1877 |
(point-min) (point-max)
|
1885 | 1878 |
'(invisible))))
|
1886 | |
|
1887 | 1879 |
|
1888 | 1880 |
(defun tablist-window-attach (awindow &optional window)
|
1889 | 1881 |
"Attach AWINDOW to WINDOW.
|
|
1923 | 1915 |
(setq newwin (window--display-buffer
|
1924 | 1916 |
buf
|
1925 | 1917 |
(split-window-below height)
|
1926 | |
'window alist display-buffer-mark-dedicated))
|
|
1918 |
'window alist))
|
1927 | 1919 |
(tablist-window-attach newwin window)
|
1928 | 1920 |
newwin))
|
1929 | 1921 |
|