X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/bd358779861f265a7acff31ead40172735af693e..79a90058ec11dbb56665e85a6631e4b8b5e7a6c6:/lisp/mpc.el diff --git a/lisp/mpc.el b/lisp/mpc.el index ad7381bb4b..3dac7f9901 100644 --- a/lisp/mpc.el +++ b/lisp/mpc.el @@ -1,6 +1,6 @@ -;;; mpc.el --- A client for the Music Player Daemon -*- coding: utf-8; lexical-binding: t -*- +;;; mpc.el --- A client for the Music Player Daemon -*- lexical-binding: t -*- -;; Copyright (C) 2006-2013 Free Software Foundation, Inc. +;; Copyright (C) 2006-2014 Free Software Foundation, Inc. ;; Author: Stefan Monnier ;; Keywords: multimedia @@ -209,8 +209,7 @@ defaults to 6600 and HOST defaults to localhost." (defconst mpc--proc-end-re "^\\(?:OK\\(?: MPD .*\\)?\\|ACK \\(.*\\)\\)\n") -(put 'mpc-proc-error 'error-conditions '(mpc-proc-error error)) -(put 'mpc-proc-error 'error-message "MPD error") +(define-error 'mpc-proc-error "MPD error") (defun mpc--debug (format &rest args) (if (get-buffer "*MPC-debug*") @@ -492,10 +491,13 @@ to call FUN for any change whatsoever.") (cancel-timer mpc--status-timer) (setq mpc--status-timer nil))) (defun mpc--status-timer-run () - (condition-case err - (when (process-get (mpc-proc) 'ready) - (with-local-quit (mpc-status-refresh))) - (error (message "MPC: %s" err)))) + (with-demoted-errors "MPC: %S" + (when (process-get (mpc-proc) 'ready) + (let* ((buf (mpc-proc-buffer (mpc-proc) 'status)) + (win (get-buffer-window buf t))) + (if (not win) + (mpc--status-timer-stop) + (with-local-quit (mpc-status-refresh))))))) (defvar mpc--status-idle-timer nil) (defun mpc--status-idle-timer-start () @@ -520,11 +522,8 @@ to call FUN for any change whatsoever.") ;; client starts playback, we may get a chance to notice it. (run-with-idle-timer 10 t 'mpc--status-idle-timer-run)))) (defun mpc--status-idle-timer-run () - (when (process-get (mpc-proc) 'ready) - (condition-case err - (with-local-quit (mpc-status-refresh)) - (error (message "MPC: %s" err)))) - (mpc--status-timer-start)) + (mpc--status-timer-start) + (mpc--status-timer-run)) (defun mpc--status-timers-refresh () "Start/stop the timers according to whether a song is playing." @@ -892,9 +891,7 @@ If PLAYLIST is t or nil or missing, use the main playlist." :type '(choice (const nil) directory)) (defcustom mpc-data-directory - (if (and (not (file-directory-p "~/.mpc")) - (file-directory-p "~/.emacs.d")) - "~/.emacs.d/mpc" "~/.mpc") + (locate-user-emacs-file "mpc" ".mpc") "Directory where MPC.el stores auxiliary data." :type 'directory) @@ -1000,9 +997,8 @@ If PLAYLIST is t or nil or missing, use the main playlist." (`Cover (let* ((dir (file-name-directory (cdr (assq 'file info)))) (cover (concat dir "cover.jpg")) - (file (condition-case err - (mpc-file-local-copy cover) - (error (message "MPC: %s" err)))) + (file (with-demoted-errors "MPC: %s" + (mpc-file-local-copy cover))) image) ;; (debug) (push `(equal ',dir (file-name-directory (cdr (assq 'file info)))) pred) @@ -1026,7 +1022,12 @@ If PLAYLIST is t or nil or missing, use the main playlist." (when (and (null val) (eq tag 'Title)) (setq val (cdr (assq 'file info)))) (push `(equal ',val (cdr (assq ',tag info))) pred) - val))))) + (cond + ((not (and (eq tag 'Date) (stringp val))) val) + ;; For "date", only keep the year! + ((string-match "[0-9]\\{4\\}" val) + (match-string 0 val)) + (t val))))))) (space (when size (setq size (string-to-number size)) (propertize " " 'display @@ -1143,7 +1144,8 @@ If PLAYLIST is t or nil or missing, use the main playlist." "Major mode for the features common to all buffers of MPC." (buffer-disable-undo) (setq buffer-read-only t) - (setq-local tool-bar-map mpc-tool-bar-map) + (if (boundp 'tool-bar-map) ; not if --without-x + (setq-local tool-bar-map mpc-tool-bar-map)) (setq-local truncate-lines t)) ;;; The mpc-status-mode buffer ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1513,7 +1515,7 @@ when constructing the set of constraints." (let* ((newbuf (mpc-tagbrowser-buf tag)) (win (get-buffer-window newbuf 0))) (if win (select-window win) - (if (with-current-buffer (window-buffer (selected-window)) + (if (with-current-buffer (window-buffer) (derived-mode-p 'mpc-tagbrowser-mode)) (setq win (selected-window)) ;; Find a tagbrowser-mode buffer. @@ -1620,7 +1622,7 @@ Return non-nil if a selection was deactivated." (setq active (if (listp active) (mpc-intersection active vals) vals)))) - (when (and (listp active)) + (when (listp active) ;; Remove the selections if they are all in conflict with ;; other constraints. (let ((deactivate t)) @@ -1634,8 +1636,14 @@ Return non-nil if a selection was deactivated." (setq selection nil) (mapc 'delete-overlay mpc-select) (setq mpc-select nil) - (mpc-tagbrowser-all-select))))) - + (mpc-tagbrowser-all-select)))) + + ;; Don't bother splitting the "active" elements to the first part if + ;; they're the same as the selection. + (when (equal (sort (copy-sequence active) #'string-lessp) + (sort (copy-sequence selection) #'string-lessp)) + (setq active 'all))) + ;; FIXME: This `mpc-sort' takes a lot of time. Maybe we should ;; be more clever and presume the buffer is mostly sorted already. (mpc-sort (if (listp active) active)) @@ -1797,7 +1805,9 @@ A value of t means the main playlist.") ;; Maintain the volume. (setq mpc-volume (mpc-volume-widget - (string-to-number (cdr (assq 'volume mpc-status)))))) + (string-to-number (cdr (assq 'volume mpc-status))))) + (let ((status-buf (mpc-proc-buffer (mpc-proc) 'status))) + (when status-buf (with-current-buffer status-buf (force-mode-line-update))))) (defvar mpc-volume-step 5) @@ -1812,9 +1822,14 @@ A value of t means the main playlist.") (char-after (posn-point posn)))) '(?◁ ?<)) (- mpc-volume-step) mpc-volume-step)) - (newvol (+ (string-to-number (cdr (assq 'volume mpc-status))) diff))) - (mpc-proc-cmd (list "setvol" newvol) 'mpc-status-refresh) - (message "Set MPD volume to %s%%" newvol))) + (curvol (string-to-number (cdr (assq 'volume mpc-status)))) + (newvol (max 0 (min 100 (+ curvol diff))))) + (if (= newvol curvol) + (progn + (message "MPD volume already at %s%%" newvol) + (ding)) + (mpc-proc-cmd (list "setvol" newvol) 'mpc-status-refresh) + (message "Set MPD volume to %s%%" newvol)))) (defun mpc-volume-widget (vol &optional size) (unless size (setq size 12.5)) @@ -1862,7 +1877,7 @@ This is used so that they can be compared with `eq', which is needed for `text-property-any'.") (defun mpc-songs-hashcons (name) (or (gethash name mpc-songs-hashcons) (puthash name name mpc-songs-hashcons))) -(defcustom mpc-songs-format "%2{Disc--}%3{Track} %-5{Time} %25{Title} %20{Album} %20{Artist} %10{Date}" +(defcustom mpc-songs-format "%2{Disc--}%3{Track} %-5{Time} %25{Title} %20{Album} %20{Artist} %5{Date}" "Format used to display each song in the list of songs." :type 'string) @@ -2012,14 +2027,16 @@ This is used so that they can be compared with `eq', which is needed for posn)))) (let* ((plbuf (mpc-proc-cmd "playlist")) (re (if song-file - (concat "^\\([0-9]+\\):" (regexp-quote song-file) "$"))) + ;; Newer MPCs apparently include "file: " in the buffer. + (concat "^\\([0-9]+\\):\\(?:file: \\)?" + (regexp-quote song-file) "$"))) (sn (with-current-buffer plbuf (goto-char (point-min)) (when (and re (re-search-forward re nil t)) (match-string 1))))) (cond ((null re) (posn-set-point posn)) - ((null sn) (error "This song is not in the playlist")) + ((null sn) (user-error "This song is not in the playlist")) ((null (with-current-buffer plbuf (re-search-forward re nil t))) ;; song-file only appears once in the playlist: no ambiguity, ;; we're good to go! @@ -2329,7 +2346,7 @@ This is used so that they can be compared with `eq', which is needed for (if (mpc-playlist-add) (if (member (cdr (assq 'state (mpc-cmd-status))) '("stop")) (mpc-cmd-play)) - (error "Don't know what to play")))) + (user-error "Don't know what to play")))) (defun mpc-next () "Jump to the next song in the queue." @@ -2593,7 +2610,8 @@ This is used so that they can be compared with `eq', which is needed for (mpc-cmd-move (let ((poss '())) (dotimes (i (length songs)) (push (+ i (length pl)) poss)) - (nreverse poss)) dest-pos mpc-songs-playlist) + (nreverse poss)) + dest-pos mpc-songs-playlist) (message "Added %d songs" (length songs))))) (mpc-songs-refresh)) (t @@ -2618,8 +2636,7 @@ This is used so that they can be compared with `eq', which is needed for (song-win (get-buffer-window song-buf 0))) (if song-win (select-window song-win) - (if (or (window-dedicated-p (selected-window)) - (window-minibuffer-p)) + (if (or (window-dedicated-p) (window-minibuffer-p)) (ignore-errors (select-frame (make-frame mpc-frame-alist))) (with-current-buffer song-buf (setq-local mpc-previous-window-config