Mercurial > emacs
changeset 107541:d59e6301c2cd
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.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Wed, 24 Mar 2010 20:06:08 -0400 |
parents | bdfbbc1e8374 |
children | 0e139e55fc1b 9ba820e1741a |
files | etc/NEWS lisp/ChangeLog lisp/mpc.el |
diffstat | 3 files changed, 87 insertions(+), 57 deletions(-) [+] |
line wrap: on
line diff
--- a/etc/NEWS Wed Mar 24 19:56:43 2010 -0400 +++ b/etc/NEWS Wed Mar 24 20:06:08 2010 -0400 @@ -45,6 +45,7 @@ * Changes in Specialized Modes and Packages in Emacs 24.1 +** mpc.el: Can use pseudo tags of the form tag1|tag2 as a union of two tags. ** Customize *** Customize buffers now contain a search field.
--- a/lisp/ChangeLog Wed Mar 24 19:56:43 2010 -0400 +++ b/lisp/ChangeLog Wed Mar 24 20:06:08 2010 -0400 @@ -1,3 +1,18 @@ +2010-03-25 Stefan Monnier <monnier@iro.umontreal.ca> + + 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. + 2010-03-24 Stefan Monnier <monnier@iro.umontreal.ca> Misc cleanup.
--- a/lisp/mpc.el Wed Mar 24 19:56:43 2010 -0400 +++ b/lisp/mpc.el Wed Mar 24 20:06:08 2010 -0400 @@ -94,54 +94,17 @@ (eval-when-compile (require 'cl)) -;;; Backward compatibility. -;; This code is meant for Emacs-CVS, so to get it to run on anything else, -;; we need to define some more things. - -(unless (fboundp 'tool-bar-local-item) - (defun tool-bar-local-item (icon def key map &rest props) - (define-key-after map (vector key) - `(menu-item ,(symbol-name key) ,def - :image ,(find-image - `((:type xpm :file ,(concat icon ".xpm")))) - ,@props)))) - -(unless (fboundp 'process-put) - (defconst mpc-process-hash (make-hash-table :weakness 'key)) - (defun process-put (proc prop val) - (let ((sym (gethash proc mpc-process-hash))) - (unless sym - (setq sym (puthash proc (make-symbol "mpc-proc-sym") mpc-process-hash))) - (put sym prop val))) - (defun process-get (proc prop) - (let ((sym (gethash proc mpc-process-hash))) - (when sym (get sym prop)))) - (defun process-plist (proc) - (let ((sym (gethash proc mpc-process-hash))) - (when sym (symbol-plist sym))))) -(unless (fboundp 'with-local-quit) - (defmacro with-local-quit (&rest body) - `(condition-case nil (let ((inhibit-quit nil)) ,@body) - (quit (setq quit-flag t) nil)))) -(unless (fboundp 'balance-windows-area) - (defalias 'balance-windows-area 'balance-windows)) -(unless (fboundp 'posn-object) (defalias 'posn-object 'ignore)) -(unless (fboundp 'buffer-local-value) - (defun buffer-local-value (var buf) - (with-current-buffer buf (symbol-value var)))) - - -;;; Main code starts here. - (defgroup mpc () "A Client for the Music Player Daemon." :prefix "mpc-" :group 'multimedia :group 'applications) -(defcustom mpc-browser-tags '(Genre Artist Album Playlist) +(defcustom mpc-browser-tags '(Genre Artist|Composer|Performer + Album|Playlist) "Tags for which a browser buffer should be created by default." - :type '(repeat string)) + ;; FIXME: provide a list of tags, for completion. + :type '(repeat symbol)) ;;; Misc utils ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -620,6 +583,19 @@ ;; (mpc--queue-head))) ;; (message "MPC's queue is out of sync")))))) +(defvar mpc--find-memoize-union-tags nil) + +(defun mpc-cmd-flush (tag value) + (puthash (cons tag value) nil mpc--find-memoize) + (dolist (uniontag mpc--find-memoize-union-tags) + (if (member (symbol-name tag) (split-string (symbol-name uniontag) "|")) + (puthash (cons uniontag value) nil mpc--find-memoize)))) + + +(defun mpc-cmd-special-tag-p (tag) + (or (memq tag '(Playlist Search Directory)) + (string-match "|" (symbol-name tag)))) + (defun mpc-cmd-find (tag value) "Return a list of all songs whose tag TAG has value VALUE. The songs are returned as alists." @@ -628,8 +604,12 @@ (cond ((eq tag 'Playlist) ;; Special case for pseudo-tag playlist. - (let ((l (mpc-proc-buf-to-alists - (mpc-proc-cmd (list "listplaylistinfo" value)))) + (let ((l (condition-case err + (mpc-proc-buf-to-alists + (mpc-proc-cmd (list "listplaylistinfo" value))) + (mpc-proc-error + ;; "[50@0] {listplaylistinfo} No such playlist" + nil))) (i 0)) (mapcar (lambda (s) (prog1 (cons (cons 'Pos (number-to-string i)) s) @@ -648,6 +628,14 @@ (if (eq (car pair) 'directory) nil pair)) pairs))))) + ((string-match "|" (symbol-name tag)) + (add-to-list 'mpc--find-memoize-union-tags tag) + (let ((tag1 (intern (substring (symbol-name tag) + 0 (match-beginning 0)))) + (tag2 (intern (substring (symbol-name tag) + (match-end 0))))) + (mpc-union (mpc-cmd-find tag1 value) + (mpc-cmd-find tag2 value)))) (t (condition-case err (mpc-proc-buf-to-alists @@ -675,7 +663,7 @@ (when other-tag (dolist (pl (prog1 pls (setq pls nil))) (let ((plsongs (mpc-cmd-find 'Playlist pl))) - (if (not (member other-tag '(Playlist Search Directory))) + (if (not (mpc-cmd-special-tag-p other-tag)) (when (member (cons other-tag value) (apply 'append plsongs)) (push pl pls)) @@ -743,6 +731,14 @@ ;; useful that would be tho. ((eq tag 'Search) (error "Not supported")) + ((string-match "|" (symbol-name tag)) + (let ((tag1 (intern (substring (symbol-name tag) + 0 (match-beginning 0)))) + (tag2 (intern (substring (symbol-name tag) + (match-end 0))))) + (mpc-union (mpc-cmd-list tag1 other-tag value) + (mpc-cmd-list tag2 other-tag value)))) + ((null other-tag) (condition-case nil (mapcar 'cdr (mpc-proc-cmd-to-alist (list "list" (symbol-name tag)))) @@ -754,7 +750,7 @@ (mpc-assq-all tag (mpc-proc-cmd-to-alist "listallinfo"))))) (t (condition-case nil - (if (member other-tag '(Search Playlist Directory)) + (if (mpc-cmd-special-tag-p other-tag) (signal 'mpc-proc-error "Not implemented") (mapcar 'cdr (mpc-proc-cmd-to-alist @@ -801,7 +797,7 @@ (list "add" file))) files))) (if (stringp playlist) - (puthash (cons 'Playlist playlist) nil mpc--find-memoize))) + (mpc-cmd-flush 'Playlist playlist))) (defun mpc-cmd-delete (song-poss &optional playlist) "Delete the songs at positions SONG-POSS from PLAYLIST. @@ -928,6 +924,10 @@ ;;; Formatter ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun mpc-secs-to-time (secs) + ;; We could use `format-seconds', but it doesn't seem worth the trouble + ;; because we'd still need to check (>= secs (* 60 100)) since the special + ;; %z only allows us to drop the large units for small values but + ;; not to drop the small units for large values. (if (stringp secs) (setq secs (string-to-number secs))) (if (>= secs (* 60 100)) ;More than 100 minutes. (format "%dh%02d" ;"%d:%02d:%02d" @@ -1432,6 +1432,20 @@ (with-current-buffer buf (with-local-quit (mpc-tagbrowser-refresh))))) (with-local-quit (mpc-songs-refresh)))) +(defun mpc-tagbrowser-tag-name (tag) + (cond + ((string-match "|" (symbol-name tag)) + (let ((tag1 (intern (substring (symbol-name tag) + 0 (match-beginning 0)))) + (tag2 (intern (substring (symbol-name tag) + (match-end 0))))) + (concat (mpc-tagbrowser-tag-name tag1) + " | " + (mpc-tagbrowser-tag-name tag2)))) + ((string-match "y\\'" (symbol-name tag)) + (concat (substring (symbol-name tag) 0 -1) "ies")) + (t (concat (symbol-name tag) "s")))) + (defun mpc-tagbrowser-buf (tag) (let ((buf (mpc-proc-buffer (mpc-proc) tag))) (if (buffer-live-p buf) buf @@ -1446,10 +1460,7 @@ (insert mpc-tagbrowser-all-name "\n")) (forward-line -1) (setq mpc-tag tag) - (setq mpc-tag-name - (if (string-match "y\\'" (symbol-name tag)) - (concat (substring (symbol-name tag) 0 -1) "ies") - (concat (symbol-name tag) "s"))) + (setq mpc-tag-name (mpc-tagbrowser-tag-name tag)) (mpc-tagbrowser-all-select) (mpc-tagbrowser-refresh) buf)))) @@ -1858,20 +1869,22 @@ (mapcar (lambda (val) (mpc-cmd-find (car cst) val)) (cdr cst))))) - (setq active (if (null active) - (progn + (setq active (cond + ((null active) (if (eq (car cst) 'Playlist) (setq dontsort t)) vals) - (if (or dontsort + ((or dontsort ;; Try to preserve ordering and ;; repetitions from playlists. (not (eq (car cst) 'Playlist))) (mpc-intersection active vals - (lambda (x) (assq 'file x))) + (lambda (x) (assq 'file x)))) + (t (setq dontsort t) (mpc-intersection vals active - (lambda (x) (assq 'file x))))))))) + (lambda (x) + (assq 'file x))))))))) (mpc-select-save (erase-buffer) ;; Sorting songs is surprisingly difficult: when comparing two @@ -1902,9 +1915,10 @@ )) (goto-char (point-min)) (forward-line (car curline)) - (when (or (search-forward (cdr curline) nil t) + (if (or (search-forward (cdr curline) nil t) (search-backward (cdr curline) nil t)) - (beginning-of-line)) + (beginning-of-line) + (goto-char (point-min))) (set (make-local-variable 'mpc-songs-totaltime) (unless (zerop totaltime) (list " " (mpc-secs-to-time totaltime))))