aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2010-03-24 20:06:08 -0400
committerStefan Monnier2010-03-24 20:06:08 -0400
commit18c812bde51dacabb16caa58475263974dc1af1a (patch)
tree8904993329e593042b742e284b8fca9ced8fc6bd
parent9586c41ae5d5841bc30f23ebb9eac3c4b42a495c (diff)
downloademacs-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/NEWS1
-rw-r--r--lisp/ChangeLog15
-rw-r--r--lisp/mpc.el128
3 files changed, 87 insertions, 57 deletions
diff --git a/etc/NEWS b/etc/NEWS
index ce3ba7cf153..5bc053a69c7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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 @@
12010-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
12010-03-24 Stefan Monnier <monnier@iro.umontreal.ca> 162010-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.
625The songs are returned as alists." 601The 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))))