diff options
| author | Stefan Monnier | 2010-03-24 20:06:08 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2010-03-24 20:06:08 -0400 |
| commit | 18c812bde51dacabb16caa58475263974dc1af1a (patch) | |
| tree | 8904993329e593042b742e284b8fca9ced8fc6bd | |
| parent | 9586c41ae5d5841bc30f23ebb9eac3c4b42a495c (diff) | |
| download | emacs-18c812bde51dacabb16caa58475263974dc1af1a.tar.gz emacs-18c812bde51dacabb16caa58475263974dc1af1a.zip | |
Add "union tags" in mpc.el.
* mpc.el: Remove backward compatibility code.
(mpc-browser-tags): Change default.
(mpc--find-memoize-union-tags): New var.
(mpc-cmd-flush, mpc-cmd-special-tag-p): New fun.
(mpc-cmd-find): Handle the case where the playlist does not exist.
Handle union-tags.
(mpc-cmd-list): Use mpc-cmd-special-tag-p. Handle union-tags.
(mpc-cmd-add): Use mpc-cmd-flush.
(mpc-tagbrowser-tag-name): New fun.
(mpc-tagbrowser-buf): Use it.
(mpc-songs-refresh): Use cond. Move to point-min as a fallback.
| -rw-r--r-- | etc/NEWS | 1 | ||||
| -rw-r--r-- | lisp/ChangeLog | 15 | ||||
| -rw-r--r-- | lisp/mpc.el | 128 |
3 files changed, 87 insertions, 57 deletions
| @@ -45,6 +45,7 @@ Use `set-scroll-bar-mode' to change this. | |||
| 45 | 45 | ||
| 46 | * Changes in Specialized Modes and Packages in Emacs 24.1 | 46 | * Changes in Specialized Modes and Packages in Emacs 24.1 |
| 47 | 47 | ||
| 48 | ** mpc.el: Can use pseudo tags of the form tag1|tag2 as a union of two tags. | ||
| 48 | ** Customize | 49 | ** Customize |
| 49 | 50 | ||
| 50 | *** Customize buffers now contain a search field. | 51 | *** Customize buffers now contain a search field. |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 4e7b8905796..15975452117 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,18 @@ | |||
| 1 | 2010-03-25 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | Add "union tags" in mpc.el. | ||
| 4 | * mpc.el: Remove backward compatibility code. | ||
| 5 | (mpc-browser-tags): Change default. | ||
| 6 | (mpc--find-memoize-union-tags): New var. | ||
| 7 | (mpc-cmd-flush, mpc-cmd-special-tag-p): New fun. | ||
| 8 | (mpc-cmd-find): Handle the case where the playlist does not exist. | ||
| 9 | Handle union-tags. | ||
| 10 | (mpc-cmd-list): Use mpc-cmd-special-tag-p. Handle union-tags. | ||
| 11 | (mpc-cmd-add): Use mpc-cmd-flush. | ||
| 12 | (mpc-tagbrowser-tag-name): New fun. | ||
| 13 | (mpc-tagbrowser-buf): Use it. | ||
| 14 | (mpc-songs-refresh): Use cond. Move to point-min as a fallback. | ||
| 15 | |||
| 1 | 2010-03-24 Stefan Monnier <monnier@iro.umontreal.ca> | 16 | 2010-03-24 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 17 | ||
| 3 | Misc cleanup. | 18 | Misc cleanup. |
diff --git a/lisp/mpc.el b/lisp/mpc.el index 23157635d98..97c5573face 100644 --- a/lisp/mpc.el +++ b/lisp/mpc.el | |||
| @@ -94,54 +94,17 @@ | |||
| 94 | 94 | ||
| 95 | (eval-when-compile (require 'cl)) | 95 | (eval-when-compile (require 'cl)) |
| 96 | 96 | ||
| 97 | ;;; Backward compatibility. | ||
| 98 | ;; This code is meant for Emacs-CVS, so to get it to run on anything else, | ||
| 99 | ;; we need to define some more things. | ||
| 100 | |||
| 101 | (unless (fboundp 'tool-bar-local-item) | ||
| 102 | (defun tool-bar-local-item (icon def key map &rest props) | ||
| 103 | (define-key-after map (vector key) | ||
| 104 | `(menu-item ,(symbol-name key) ,def | ||
| 105 | :image ,(find-image | ||
| 106 | `((:type xpm :file ,(concat icon ".xpm")))) | ||
| 107 | ,@props)))) | ||
| 108 | |||
| 109 | (unless (fboundp 'process-put) | ||
| 110 | (defconst mpc-process-hash (make-hash-table :weakness 'key)) | ||
| 111 | (defun process-put (proc prop val) | ||
| 112 | (let ((sym (gethash proc mpc-process-hash))) | ||
| 113 | (unless sym | ||
| 114 | (setq sym (puthash proc (make-symbol "mpc-proc-sym") mpc-process-hash))) | ||
| 115 | (put sym prop val))) | ||
| 116 | (defun process-get (proc prop) | ||
| 117 | (let ((sym (gethash proc mpc-process-hash))) | ||
| 118 | (when sym (get sym prop)))) | ||
| 119 | (defun process-plist (proc) | ||
| 120 | (let ((sym (gethash proc mpc-process-hash))) | ||
| 121 | (when sym (symbol-plist sym))))) | ||
| 122 | (unless (fboundp 'with-local-quit) | ||
| 123 | (defmacro with-local-quit (&rest body) | ||
| 124 | `(condition-case nil (let ((inhibit-quit nil)) ,@body) | ||
| 125 | (quit (setq quit-flag t) nil)))) | ||
| 126 | (unless (fboundp 'balance-windows-area) | ||
| 127 | (defalias 'balance-windows-area 'balance-windows)) | ||
| 128 | (unless (fboundp 'posn-object) (defalias 'posn-object 'ignore)) | ||
| 129 | (unless (fboundp 'buffer-local-value) | ||
| 130 | (defun buffer-local-value (var buf) | ||
| 131 | (with-current-buffer buf (symbol-value var)))) | ||
| 132 | |||
| 133 | |||
| 134 | ;;; Main code starts here. | ||
| 135 | |||
| 136 | (defgroup mpc () | 97 | (defgroup mpc () |
| 137 | "A Client for the Music Player Daemon." | 98 | "A Client for the Music Player Daemon." |
| 138 | :prefix "mpc-" | 99 | :prefix "mpc-" |
| 139 | :group 'multimedia | 100 | :group 'multimedia |
| 140 | :group 'applications) | 101 | :group 'applications) |
| 141 | 102 | ||
| 142 | (defcustom mpc-browser-tags '(Genre Artist Album Playlist) | 103 | (defcustom mpc-browser-tags '(Genre Artist|Composer|Performer |
| 104 | Album|Playlist) | ||
| 143 | "Tags for which a browser buffer should be created by default." | 105 | "Tags for which a browser buffer should be created by default." |
| 144 | :type '(repeat string)) | 106 | ;; FIXME: provide a list of tags, for completion. |
| 107 | :type '(repeat symbol)) | ||
| 145 | 108 | ||
| 146 | ;;; Misc utils ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 109 | ;;; Misc utils ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 147 | 110 | ||
| @@ -620,6 +583,19 @@ Any call to `mpc-status-refresh' may cause it to be restarted." | |||
| 620 | ;; (mpc--queue-head))) | 583 | ;; (mpc--queue-head))) |
| 621 | ;; (message "MPC's queue is out of sync")))))) | 584 | ;; (message "MPC's queue is out of sync")))))) |
| 622 | 585 | ||
| 586 | (defvar mpc--find-memoize-union-tags nil) | ||
| 587 | |||
| 588 | (defun mpc-cmd-flush (tag value) | ||
| 589 | (puthash (cons tag value) nil mpc--find-memoize) | ||
| 590 | (dolist (uniontag mpc--find-memoize-union-tags) | ||
| 591 | (if (member (symbol-name tag) (split-string (symbol-name uniontag) "|")) | ||
| 592 | (puthash (cons uniontag value) nil mpc--find-memoize)))) | ||
| 593 | |||
| 594 | |||
| 595 | (defun mpc-cmd-special-tag-p (tag) | ||
| 596 | (or (memq tag '(Playlist Search Directory)) | ||
| 597 | (string-match "|" (symbol-name tag)))) | ||
| 598 | |||
| 623 | (defun mpc-cmd-find (tag value) | 599 | (defun mpc-cmd-find (tag value) |
| 624 | "Return a list of all songs whose tag TAG has value VALUE. | 600 | "Return a list of all songs whose tag TAG has value VALUE. |
| 625 | The songs are returned as alists." | 601 | The songs are returned as alists." |
| @@ -628,8 +604,12 @@ The songs are returned as alists." | |||
| 628 | (cond | 604 | (cond |
| 629 | ((eq tag 'Playlist) | 605 | ((eq tag 'Playlist) |
| 630 | ;; Special case for pseudo-tag playlist. | 606 | ;; Special case for pseudo-tag playlist. |
| 631 | (let ((l (mpc-proc-buf-to-alists | 607 | (let ((l (condition-case err |
| 632 | (mpc-proc-cmd (list "listplaylistinfo" value)))) | 608 | (mpc-proc-buf-to-alists |
| 609 | (mpc-proc-cmd (list "listplaylistinfo" value))) | ||
| 610 | (mpc-proc-error | ||
| 611 | ;; "[50@0] {listplaylistinfo} No such playlist" | ||
| 612 | nil))) | ||
| 633 | (i 0)) | 613 | (i 0)) |
| 634 | (mapcar (lambda (s) | 614 | (mapcar (lambda (s) |
| 635 | (prog1 (cons (cons 'Pos (number-to-string i)) s) | 615 | (prog1 (cons (cons 'Pos (number-to-string i)) s) |
| @@ -648,6 +628,14 @@ The songs are returned as alists." | |||
| 648 | (if (eq (car pair) 'directory) | 628 | (if (eq (car pair) 'directory) |
| 649 | nil pair)) | 629 | nil pair)) |
| 650 | pairs))))) | 630 | pairs))))) |
| 631 | ((string-match "|" (symbol-name tag)) | ||
| 632 | (add-to-list 'mpc--find-memoize-union-tags tag) | ||
| 633 | (let ((tag1 (intern (substring (symbol-name tag) | ||
| 634 | 0 (match-beginning 0)))) | ||
| 635 | (tag2 (intern (substring (symbol-name tag) | ||
| 636 | (match-end 0))))) | ||
| 637 | (mpc-union (mpc-cmd-find tag1 value) | ||
| 638 | (mpc-cmd-find tag2 value)))) | ||
| 651 | (t | 639 | (t |
| 652 | (condition-case err | 640 | (condition-case err |
| 653 | (mpc-proc-buf-to-alists | 641 | (mpc-proc-buf-to-alists |
| @@ -675,7 +663,7 @@ The songs are returned as alists." | |||
| 675 | (when other-tag | 663 | (when other-tag |
| 676 | (dolist (pl (prog1 pls (setq pls nil))) | 664 | (dolist (pl (prog1 pls (setq pls nil))) |
| 677 | (let ((plsongs (mpc-cmd-find 'Playlist pl))) | 665 | (let ((plsongs (mpc-cmd-find 'Playlist pl))) |
| 678 | (if (not (member other-tag '(Playlist Search Directory))) | 666 | (if (not (mpc-cmd-special-tag-p other-tag)) |
| 679 | (when (member (cons other-tag value) | 667 | (when (member (cons other-tag value) |
| 680 | (apply 'append plsongs)) | 668 | (apply 'append plsongs)) |
| 681 | (push pl pls)) | 669 | (push pl pls)) |
| @@ -743,6 +731,14 @@ The songs are returned as alists." | |||
| 743 | ;; useful that would be tho. | 731 | ;; useful that would be tho. |
| 744 | ((eq tag 'Search) (error "Not supported")) | 732 | ((eq tag 'Search) (error "Not supported")) |
| 745 | 733 | ||
| 734 | ((string-match "|" (symbol-name tag)) | ||
| 735 | (let ((tag1 (intern (substring (symbol-name tag) | ||
| 736 | 0 (match-beginning 0)))) | ||
| 737 | (tag2 (intern (substring (symbol-name tag) | ||
| 738 | (match-end 0))))) | ||
| 739 | (mpc-union (mpc-cmd-list tag1 other-tag value) | ||
| 740 | (mpc-cmd-list tag2 other-tag value)))) | ||
| 741 | |||
| 746 | ((null other-tag) | 742 | ((null other-tag) |
| 747 | (condition-case nil | 743 | (condition-case nil |
| 748 | (mapcar 'cdr (mpc-proc-cmd-to-alist (list "list" (symbol-name tag)))) | 744 | (mapcar 'cdr (mpc-proc-cmd-to-alist (list "list" (symbol-name tag)))) |
| @@ -754,7 +750,7 @@ The songs are returned as alists." | |||
| 754 | (mpc-assq-all tag (mpc-proc-cmd-to-alist "listallinfo"))))) | 750 | (mpc-assq-all tag (mpc-proc-cmd-to-alist "listallinfo"))))) |
| 755 | (t | 751 | (t |
| 756 | (condition-case nil | 752 | (condition-case nil |
| 757 | (if (member other-tag '(Search Playlist Directory)) | 753 | (if (mpc-cmd-special-tag-p other-tag) |
| 758 | (signal 'mpc-proc-error "Not implemented") | 754 | (signal 'mpc-proc-error "Not implemented") |
| 759 | (mapcar 'cdr | 755 | (mapcar 'cdr |
| 760 | (mpc-proc-cmd-to-alist | 756 | (mpc-proc-cmd-to-alist |
| @@ -801,7 +797,7 @@ If PLAYLIST is t or nil or missing, use the main playlist." | |||
| 801 | (list "add" file))) | 797 | (list "add" file))) |
| 802 | files))) | 798 | files))) |
| 803 | (if (stringp playlist) | 799 | (if (stringp playlist) |
| 804 | (puthash (cons 'Playlist playlist) nil mpc--find-memoize))) | 800 | (mpc-cmd-flush 'Playlist playlist))) |
| 805 | 801 | ||
| 806 | (defun mpc-cmd-delete (song-poss &optional playlist) | 802 | (defun mpc-cmd-delete (song-poss &optional playlist) |
| 807 | "Delete the songs at positions SONG-POSS from PLAYLIST. | 803 | "Delete the songs at positions SONG-POSS from PLAYLIST. |
| @@ -928,6 +924,10 @@ If PLAYLIST is t or nil or missing, use the main playlist." | |||
| 928 | ;;; Formatter ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 924 | ;;; Formatter ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 929 | 925 | ||
| 930 | (defun mpc-secs-to-time (secs) | 926 | (defun mpc-secs-to-time (secs) |
| 927 | ;; We could use `format-seconds', but it doesn't seem worth the trouble | ||
| 928 | ;; because we'd still need to check (>= secs (* 60 100)) since the special | ||
| 929 | ;; %z only allows us to drop the large units for small values but | ||
| 930 | ;; not to drop the small units for large values. | ||
| 931 | (if (stringp secs) (setq secs (string-to-number secs))) | 931 | (if (stringp secs) (setq secs (string-to-number secs))) |
| 932 | (if (>= secs (* 60 100)) ;More than 100 minutes. | 932 | (if (>= secs (* 60 100)) ;More than 100 minutes. |
| 933 | (format "%dh%02d" ;"%d:%02d:%02d" | 933 | (format "%dh%02d" ;"%d:%02d:%02d" |
| @@ -1432,6 +1432,20 @@ when constructing the set of constraints." | |||
| 1432 | (with-current-buffer buf (with-local-quit (mpc-tagbrowser-refresh))))) | 1432 | (with-current-buffer buf (with-local-quit (mpc-tagbrowser-refresh))))) |
| 1433 | (with-local-quit (mpc-songs-refresh)))) | 1433 | (with-local-quit (mpc-songs-refresh)))) |
| 1434 | 1434 | ||
| 1435 | (defun mpc-tagbrowser-tag-name (tag) | ||
| 1436 | (cond | ||
| 1437 | ((string-match "|" (symbol-name tag)) | ||
| 1438 | (let ((tag1 (intern (substring (symbol-name tag) | ||
| 1439 | 0 (match-beginning 0)))) | ||
| 1440 | (tag2 (intern (substring (symbol-name tag) | ||
| 1441 | (match-end 0))))) | ||
| 1442 | (concat (mpc-tagbrowser-tag-name tag1) | ||
| 1443 | " | " | ||
| 1444 | (mpc-tagbrowser-tag-name tag2)))) | ||
| 1445 | ((string-match "y\\'" (symbol-name tag)) | ||
| 1446 | (concat (substring (symbol-name tag) 0 -1) "ies")) | ||
| 1447 | (t (concat (symbol-name tag) "s")))) | ||
| 1448 | |||
| 1435 | (defun mpc-tagbrowser-buf (tag) | 1449 | (defun mpc-tagbrowser-buf (tag) |
| 1436 | (let ((buf (mpc-proc-buffer (mpc-proc) tag))) | 1450 | (let ((buf (mpc-proc-buffer (mpc-proc) tag))) |
| 1437 | (if (buffer-live-p buf) buf | 1451 | (if (buffer-live-p buf) buf |
| @@ -1446,10 +1460,7 @@ when constructing the set of constraints." | |||
| 1446 | (insert mpc-tagbrowser-all-name "\n")) | 1460 | (insert mpc-tagbrowser-all-name "\n")) |
| 1447 | (forward-line -1) | 1461 | (forward-line -1) |
| 1448 | (setq mpc-tag tag) | 1462 | (setq mpc-tag tag) |
| 1449 | (setq mpc-tag-name | 1463 | (setq mpc-tag-name (mpc-tagbrowser-tag-name tag)) |
| 1450 | (if (string-match "y\\'" (symbol-name tag)) | ||
| 1451 | (concat (substring (symbol-name tag) 0 -1) "ies") | ||
| 1452 | (concat (symbol-name tag) "s"))) | ||
| 1453 | (mpc-tagbrowser-all-select) | 1464 | (mpc-tagbrowser-all-select) |
| 1454 | (mpc-tagbrowser-refresh) | 1465 | (mpc-tagbrowser-refresh) |
| 1455 | buf)))) | 1466 | buf)))) |
| @@ -1858,20 +1869,22 @@ This is used so that they can be compared with `eq', which is needed for | |||
| 1858 | (mapcar (lambda (val) | 1869 | (mapcar (lambda (val) |
| 1859 | (mpc-cmd-find (car cst) val)) | 1870 | (mpc-cmd-find (car cst) val)) |
| 1860 | (cdr cst))))) | 1871 | (cdr cst))))) |
| 1861 | (setq active (if (null active) | 1872 | (setq active (cond |
| 1862 | (progn | 1873 | ((null active) |
| 1863 | (if (eq (car cst) 'Playlist) | 1874 | (if (eq (car cst) 'Playlist) |
| 1864 | (setq dontsort t)) | 1875 | (setq dontsort t)) |
| 1865 | vals) | 1876 | vals) |
| 1866 | (if (or dontsort | 1877 | ((or dontsort |
| 1867 | ;; Try to preserve ordering and | 1878 | ;; Try to preserve ordering and |
| 1868 | ;; repetitions from playlists. | 1879 | ;; repetitions from playlists. |
| 1869 | (not (eq (car cst) 'Playlist))) | 1880 | (not (eq (car cst) 'Playlist))) |
| 1870 | (mpc-intersection active vals | 1881 | (mpc-intersection active vals |
| 1871 | (lambda (x) (assq 'file x))) | 1882 | (lambda (x) (assq 'file x)))) |
| 1883 | (t | ||
| 1872 | (setq dontsort t) | 1884 | (setq dontsort t) |
| 1873 | (mpc-intersection vals active | 1885 | (mpc-intersection vals active |
| 1874 | (lambda (x) (assq 'file x))))))))) | 1886 | (lambda (x) |
| 1887 | (assq 'file x))))))))) | ||
| 1875 | (mpc-select-save | 1888 | (mpc-select-save |
| 1876 | (erase-buffer) | 1889 | (erase-buffer) |
| 1877 | ;; Sorting songs is surprisingly difficult: when comparing two | 1890 | ;; Sorting songs is surprisingly difficult: when comparing two |
| @@ -1902,9 +1915,10 @@ This is used so that they can be compared with `eq', which is needed for | |||
| 1902 | )) | 1915 | )) |
| 1903 | (goto-char (point-min)) | 1916 | (goto-char (point-min)) |
| 1904 | (forward-line (car curline)) | 1917 | (forward-line (car curline)) |
| 1905 | (when (or (search-forward (cdr curline) nil t) | 1918 | (if (or (search-forward (cdr curline) nil t) |
| 1906 | (search-backward (cdr curline) nil t)) | 1919 | (search-backward (cdr curline) nil t)) |
| 1907 | (beginning-of-line)) | 1920 | (beginning-of-line) |
| 1921 | (goto-char (point-min))) | ||
| 1908 | (set (make-local-variable 'mpc-songs-totaltime) | 1922 | (set (make-local-variable 'mpc-songs-totaltime) |
| 1909 | (unless (zerop totaltime) | 1923 | (unless (zerop totaltime) |
| 1910 | (list " " (mpc-secs-to-time totaltime)))) | 1924 | (list " " (mpc-secs-to-time totaltime)))) |