More tweaks of skeleton documentation wrt \n behavior at bol/eol.
[bpt/emacs.git] / lisp / mpc.el
index 9d9da27..d569610 100644 (file)
@@ -1,6 +1,6 @@
 ;;; mpc.el --- A client for the Music Player Daemon   -*- coding: utf-8; lexical-binding: t -*-
 
-;; Copyright (C) 2006-2013 Free Software Foundation, Inc.
+;; Copyright (C) 2006-2014 Free Software Foundation, Inc.
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; 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*")
@@ -320,10 +319,11 @@ defaults to 6600 and HOST defaults to localhost."
     (if tmp (push (nreverse tmp) alists))
     (nreverse alists)))
 
-(defun mpc-proc ()
+(defun mpc-proc (&optional restart)
   (unless (and mpc-proc
                (buffer-live-p (process-buffer mpc-proc))
-               (not (memq (process-status mpc-proc) '(closed))))
+               (not (and restart
+                         (memq (process-status mpc-proc) '(closed)))))
     (mpc--proc-connect mpc-host))
   mpc-proc)
 
@@ -356,7 +356,7 @@ otherwise return immediately and call CALLBACK with no argument
 when the command terminates.
 CMD can be a string which is passed as-is to MPD or a list of strings
 which will be concatenated with proper quoting before passing them to MPD."
-  (let ((proc (mpc-proc)))
+  (let ((proc (mpc-proc 'restart)))
     (if (and callback (not (process-get proc 'ready)))
         (let ((old (process-get proc 'callback)))
           (process-put proc 'callback
@@ -491,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 ()
-  (when (process-get (mpc-proc) 'ready)
-    (condition-case err
-        (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 ()
@@ -519,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."
@@ -999,9 +999,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)
@@ -1142,7 +1141,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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1177,14 +1177,15 @@ If PLAYLIST is t or nil or missing, use the main playlist."
 
 (defun mpc-status-buffer-show ()
   (interactive)
-  (let* ((buf (mpc-proc-buffer (mpc-proc) 'status))
-         (songs-buf (mpc-proc-buffer (mpc-proc) 'songs))
+  (let* ((proc (mpc-proc))
+         (buf (mpc-proc-buffer proc 'status))
+         (songs-buf (mpc-proc-buffer proc 'songs))
          (songs-win (if songs-buf (get-buffer-window songs-buf 0))))
     (unless (buffer-live-p buf)
       (setq buf (get-buffer-create "*MPC-Status*"))
       (with-current-buffer buf
         (mpc-status-mode))
-      (mpc-proc-buffer (mpc-proc) 'status buf))
+      (mpc-proc-buffer proc 'status buf))
     (if (null songs-win) (pop-to-buffer buf)
       (let ((_win (split-window songs-win 20 t)))
         (set-window-dedicated-p songs-win nil)
@@ -1511,7 +1512,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.
@@ -1692,13 +1693,14 @@ Return non-nil if a selection was deactivated."
   (mpc-event-set-point event)
   (let ((name (buffer-substring (line-beginning-position)
                                 (line-end-position)))
-        (prop (intern mpc-tag)))
-    (if (not (member name (process-get (mpc-proc) prop)))
-        (process-put (mpc-proc) prop
-                     (cons name (process-get (mpc-proc) prop)))
-      (let ((new (delete name (process-get (mpc-proc) prop))))
+        (prop (intern mpc-tag))
+        (proc (mpc-proc)))
+    (if (not (member name (process-get proc prop)))
+        (process-put proc prop
+                     (cons name (process-get proc prop)))
+      (let ((new (delete name (process-get proc prop))))
         (setq name (concat name "/"))
-        (process-put (mpc-proc) prop
+        (process-put proc prop
                      (delq nil
                            (mapcar (lambda (x)
                                      (if (string-prefix-p name x)
@@ -1809,9 +1811,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))
@@ -2009,7 +2016,9 @@ 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))
@@ -2615,8 +2624,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