fordon_greeman / voidfiles

Branch: main
Switch branches/tags
main
theidioticdev add emacs 2079ec5 23h ago
685 lines · 24.1 KB Raw Blame History
1 ;;; emms-playlist-mode.el --- Playlist mode for Emms. -*- lexical-binding: t; -*-
2
3 ;; Copyright (C) 2005-2024 Free Software Foundation, Inc.
4
5 ;; Author: Yoni Rabkin <yrk@gnu.org>
6
7 ;; This file is part of EMMS.
8
9 ;; EMMS is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 3, or (at your option)
12 ;; any later version.
13 ;;
14 ;; EMMS is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18 ;;
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with EMMS; if not, write to the Free Software Foundation,
21 ;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
22
23 ;;; Commentary:
24 ;;;
25 ;; This is a method of displaying and manipulating the different Emms
26 ;; playlist buffers.
27 ;;
28 ;; Emms developer's motto: "When forcer says (require 'jump) we say
29 ;; (funcall #'jump height)"
30
31 ;;; Code:
32
33
34 ;;; --------------------------------------------------------
35 ;;; Variables
36 ;;; --------------------------------------------------------
37 (require 'emms)
38 (condition-case nil
39 (require 'overlay)
40 (error nil))
41 (require 'emms-source-playlist)
42
43 (defvar emms-playlist-mode-hook nil
44 "Emms playlist mode hook.")
45
46 (defvar emms-playlist-mode-selected-overlay nil
47 "Last selected track. Use for updating the display.")
48
49 (defvar emms-playlist-mode-switched-buffer nil
50 "Last buffer visited before calling `emms-playlist-mode-switch-buffer'.")
51
52 (defvar emms-playlist-mode-popup-enabled nil
53 "True when the playlist was called as a popup window.")
54
55 (defvar emms-playlist-mode-kill-whole-line-p t
56 "When true line kills behave like a typical music player.")
57
58 (make-variable-buffer-local
59 'emms-playlist-mode-selected-overlay)
60
61 (defgroup emms-playlist-mode nil
62 "*The Emacs Multimedia System playlist mode."
63 :prefix "emms-playlist-mode-"
64 :group 'emms)
65
66 (defcustom emms-playlist-mode-open-playlists nil
67 "Determine whether to open playlists in a new EMMS buffer on RET.
68 This is useful if you have a master playlist buffer that is
69 composed of other playlists."
70 :type 'boolean)
71
72 (defcustom emms-playlist-mode-window-width 25
73 "Determine the width of the Emms popup window.
74 The value should a positive integer."
75 :type 'integer)
76
77 (defcustom emms-playlist-mode-center-when-go nil
78 "Determine whether to center on the currently selected track.
79 This is true for every invocation of `emms-playlist-mode-go'."
80 :type 'boolean)
81
82
83 ;;; --------------------------------------------------------
84 ;;; Faces
85 ;;; --------------------------------------------------------
86 (defface emms-playlist-track-face
87 '((((class color) (background dark))
88 (:foreground "DarkSeaGreen"))
89 (((class color) (background light))
90 (:foreground "Blue"))
91 (((type tty) (class mono))
92 (:inverse-video t))
93 (t (:background "Blue")))
94 "Face for the tracks in a playlist buffer.")
95
96 (defface emms-playlist-selected-face
97 '((((class color) (background dark))
98 (:foreground "SteelBlue3"))
99 (((class color) (background light))
100 (:background "blue3" :foreground "white"))
101 (((type tty) (class mono))
102 (:inverse-video t))
103 (t (:background "blue3")))
104 "Face for highlighting the selected track.")
105
106
107 ;;; --------------------------------------------------------
108 ;;; Keys
109 ;;; --------------------------------------------------------
110 (defvar emms-playlist-mode-map
111 (let ((map (make-sparse-keymap)))
112 (set-keymap-parent map text-mode-map)
113 (define-key map (kbd "C-x C-s") #'emms-playlist-save)
114 (define-key map (kbd "C-y") #'emms-playlist-mode-yank)
115 (define-key map (kbd "C-k") #'emms-playlist-mode-kill-track)
116 (define-key map (kbd "C-w") #'emms-playlist-mode-kill)
117 (define-key map (kbd "C-_") #'emms-playlist-mode-undo)
118 (define-key map (kbd "C-/") #'emms-playlist-mode-undo)
119 (define-key map (kbd "C-x u") #'emms-playlist-mode-undo)
120 (define-key map (kbd "C-n") #'next-line)
121 (define-key map (kbd "C-p") #'previous-line)
122 (define-key map (kbd "C-j") #'emms-playlist-mode-insert-newline)
123 (define-key map (kbd "C-i") #'emms-playlist-mode-shift-track-up)
124 (define-key map (kbd "C-o") #'emms-playlist-mode-shift-track-down)
125 (define-key map (kbd "M-y") #'emms-playlist-mode-yank-pop)
126 (define-key map (kbd "M-<") #'emms-playlist-mode-first)
127 (define-key map (kbd "M->") #'emms-playlist-mode-last)
128 (define-key map (kbd "M-n") #'emms-playlist-mode-next)
129 (define-key map (kbd "M-p") #'emms-playlist-mode-previous)
130 (define-key map (kbd "a") #'emms-playlist-mode-add-contents)
131 (define-key map (kbd "b") #'emms-playlist-set-playlist-buffer)
132 (define-key map (kbd "D") #'emms-playlist-mode-kill-track)
133 (define-key map (kbd "n") #'emms-next)
134 (define-key map (kbd "p") #'emms-previous)
135 (define-key map (kbd "SPC") #'scroll-up)
136 (define-key map (kbd ">") #'emms-seek-forward)
137 (define-key map (kbd "<") #'emms-seek-backward)
138 (define-key map (kbd "P") #'emms-pause)
139 (define-key map (kbd "s") #'emms-stop)
140 (define-key map (kbd "f") #'emms-show)
141 (define-key map (kbd "c") #'emms-playlist-mode-center-current)
142 (define-key map (kbd "q") #'emms-playlist-mode-bury-buffer)
143 (define-key map (kbd "K") #'emms-playlist-mode-current-kill)
144 (define-key map (kbd "?") #'describe-mode)
145 (define-key map (kbd "r") #'emms-random)
146 (define-key map (kbd "C") #'emms-playlist-clear)
147 (define-key map (kbd "d") #'emms-playlist-mode-goto-dired-at-point)
148 (define-key map (kbd "<mouse-2>") #'emms-playlist-mode-play-current-track)
149 (define-key map (kbd "RET") #'emms-playlist-mode-play-smart)
150 (define-key map (kbd "i") #'emms-playlist-playlist-insert-track)
151 map)
152 "Keymap for `emms-playlist-mode'.")
153
154 (defmacro emms-playlist-mode-move-wrapper (name fun)
155 "Create a function NAME which is an `interactive' version of FUN.
156
157 NAME should be a symbol.
158 FUN should be a function."
159 `(defun ,name ()
160 ,(format "Interactive wrapper around `%s' for playlist-mode."
161 fun)
162 (interactive)
163 (,fun)))
164
165 (emms-playlist-mode-move-wrapper emms-playlist-mode-first
166 emms-playlist-first)
167
168 (emms-playlist-mode-move-wrapper emms-playlist-mode-select-next
169 emms-playlist-next)
170
171 (emms-playlist-mode-move-wrapper emms-playlist-mode-select-previous
172 emms-playlist-previous)
173
174 (defun emms-playlist-mode-bury-buffer ()
175 "Wrapper around `bury-buffer' for popup windows."
176 (interactive)
177 (if emms-playlist-mode-popup-enabled
178 (unwind-protect
179 (delete-window)
180 (setq emms-playlist-mode-popup-enabled nil))
181 (bury-buffer)))
182
183 (defun emms-playlist-mode-current-kill ()
184 "If the current buffer is an EMMS playlist buffer, kill it.
185 Otherwise, kill the current EMMS playlist buffer."
186 (interactive)
187 (if (and emms-playlist-buffer-p
188 (not (eq (current-buffer) emms-playlist-buffer)))
189 (kill-buffer (current-buffer))
190 (emms-playlist-current-kill)))
191
192 (defun emms-playlist-mode-last ()
193 "Move to directly after the last track in the current buffer."
194 (interactive)
195 (emms-playlist-ensure-playlist-buffer)
196 (let ((last (condition-case nil
197 (save-excursion
198 (goto-char (point-max))
199 (point))
200 (error
201 nil))))
202 (if last
203 (goto-char last)
204 (error "No last track"))))
205
206 (defun emms-playlist-mode-center-current ()
207 "Move point to the currently selected track."
208 (interactive)
209 (goto-char (if emms-playlist-mode-selected-overlay
210 (overlay-start emms-playlist-mode-selected-overlay)
211 (point-min))))
212
213 (defun emms-playlist-mode-play-current-track ()
214 "Start playing track at point."
215 (interactive)
216 (emms-playlist-set-playlist-buffer (current-buffer))
217 (unless (emms-playlist-track-at (point))
218 (emms-playlist-next))
219 (emms-playlist-select (point))
220 (when emms-player-playing-p
221 (emms-stop))
222 (emms-start))
223
224 (defun emms-playlist-mode-play-smart ()
225 "Determine the best operation to take on the current track.
226
227 If on a playlist, and `emms-playlist-mode-open-playlists' is
228 non-nil, load the playlist at point into a new buffer.
229
230 Otherwise play the track immediately."
231 (interactive)
232 (save-excursion
233 ;; move to the start of the line, in case the point is on the \n,
234 ;; which isn't propertized
235 (emms-move-beginning-of-line nil)
236 (if (not emms-playlist-mode-open-playlists)
237 (emms-playlist-mode-play-current-track)
238 (unless (emms-playlist-track-at)
239 (emms-playlist-next))
240 (let* ((track (emms-playlist-track-at))
241 (name (emms-track-get track 'name))
242 (type (emms-track-get track 'type)))
243 (if (or (eq type 'playlist)
244 (and (eq type 'file)
245 (string-match "\\.\\(m3u\\|pls\\)\\'" name)))
246 (emms-playlist-mode-load-playlist)
247 (emms-playlist-mode-play-current-track))))))
248
249 (defun emms-playlist-mode-switch-buffer ()
250 "Switch to the playlist buffer and then switch back if called again.
251
252 This function switches to the current Emms playlist buffer and
253 remembers the buffer switched from. When called again the
254 function switches back to the remembered buffer."
255 (interactive)
256 (if (eq (current-buffer)
257 emms-playlist-buffer)
258 (switch-to-buffer emms-playlist-mode-switched-buffer)
259 (setq emms-playlist-mode-switched-buffer (current-buffer))
260 (switch-to-buffer emms-playlist-buffer)))
261
262 (defun emms-playlist-mode-insert-newline ()
263 "Insert a newline at point."
264 (interactive)
265 (emms-with-inhibit-read-only-t
266 (newline)))
267
268 (defun emms-playlist-mode-undo ()
269 "Wrapper around `undo'."
270 (interactive)
271 (emms-with-inhibit-read-only-t
272 (undo)))
273
274 (defun emms-playlist-mode-add-after-current (dir)
275 "Insert tracks from directory tree DIR after current track."
276 (interactive (list
277 (emms-read-directory-name "Add directory after current track: "
278 (emms-source-file-directory-hint)
279 emms-source-file-default-directory
280 t)))
281 (let ((p (if emms-playlist-mode-selected-overlay
282 (overlay-start emms-playlist-mode-selected-overlay)
283 (error "no current track"))))
284 (goto-char p)
285 (forward-line 1)
286 (emms-insert-directory-tree dir)))
287
288 (defun emms-playlist-mode-add-contents ()
289 "Add files in the playlist at point to the current playlist buffer.
290
291 If we are in the current playlist, make a new playlist buffer and
292 set it as current."
293 (interactive)
294 (save-excursion
295 (emms-move-beginning-of-line nil)
296 (unless (emms-playlist-track-at)
297 (emms-playlist-next))
298 (let* ((track (emms-playlist-track-at))
299 (name (emms-track-get track 'name))
300 (type (emms-track-get track 'type))
301 (playlist-p (or (eq type 'playlist)
302 (and (eq type 'file)
303 (save-match-data
304 (string-match "\\.\\(m3u\\|pls\\)\\'"
305 name))))))
306 (emms-playlist-select (point))
307 (unless (and (buffer-live-p emms-playlist-buffer)
308 (not (eq (current-buffer) emms-playlist-buffer)))
309 (setq emms-playlist-buffer
310 (emms-playlist-set-playlist-buffer (emms-playlist-new))))
311 (with-current-emms-playlist
312 (goto-char (point-max))
313 (when playlist-p
314 (insert (emms-track-force-description track) "\n"))
315 (let ((beg (point)))
316 (if playlist-p
317 (emms-add-playlist name)
318 (let ((func (intern (concat "emms-add-" (symbol-name type)))))
319 (if (functionp func)
320 (funcall func name)
321 ;; fallback
322 (emms-add-file name))))
323 (when playlist-p
324 (goto-char (point-max))
325 (while (progn
326 (forward-line -1)
327 (>= (point) beg))
328 (insert " ")))
329 (goto-char (point-min))
330 (message "Added %s" (symbol-name type)))))))
331
332 (defun emms-playlist-mode-goto-dired-at-point (&optional other-window)
333 "Visit the track at point in a `dired' buffer.
334
335 With a prefix arg, open the `dired' buffer in OTHER-WINDOW."
336 (interactive "P")
337 (let ((track (emms-playlist-track-at)))
338 (if track
339 (let ((name (emms-track-get track 'name))
340 (type (emms-track-get track 'type)))
341 (if (eq type 'file)
342 (dired-jump other-window name)
343 (error "Can't visit this track type in Dired")))
344 (error "No track at point"))))
345
346
347 ;;; --------------------------------------------------------
348 ;;; Killing and yanking
349 ;;; --------------------------------------------------------
350 (defun emms-playlist-mode-between-p (p a b)
351 "Return t if P is a point between points A and B."
352 (and (<= a p)
353 (<= p b)))
354
355 ;; D
356 (defun emms-playlist-mode-kill-entire-track ()
357 "Kill track at point, including newline."
358 (interactive)
359 (let ((kill-whole-line t))
360 (emms-playlist-mode-kill-track)))
361
362 ;; C-k
363 (defun emms-playlist-mode-kill-track ()
364 "Kill track at point."
365 (interactive)
366 (emms-with-inhibit-read-only-t
367 (let ((track (emms-playlist-track-at)))
368 (when track
369 (when (and emms-player-playing-p
370 (emms-playlist-selected-track-at-p))
371 (emms-stop)
372 (delete-overlay emms-playlist-mode-selected-overlay)
373 (setq emms-playlist-mode-selected-overlay nil)))
374 (let ((kill-whole-line emms-playlist-mode-kill-whole-line-p))
375 (goto-char (line-beginning-position))
376 (kill-line)))))
377
378 ;; C-w
379 (defun emms-playlist-mode-kill ()
380 "Kill from mark to point."
381 (interactive)
382 (emms-with-inhibit-read-only-t
383 ;; Are we killing the playing/selected track?
384 (when (and (markerp emms-playlist-selected-marker)
385 (emms-playlist-mode-between-p
386 (marker-position emms-playlist-selected-marker)
387 (region-beginning)
388 (region-end)))
389 (emms-stop)
390 (delete-overlay emms-playlist-mode-selected-overlay)
391 (setq emms-playlist-mode-selected-overlay nil))
392 (kill-region (region-beginning)
393 (region-end))))
394
395 (defun emms-playlist-mode-correct-previous-yank ()
396 "Fix the previous yank if needed."
397 (when (and (< (line-beginning-position) (point))
398 (< (point) (line-end-position)))
399 (newline)))
400
401 ;; C-y
402 (defun emms-playlist-mode-yank ()
403 "Yank into the playlist buffer."
404 (interactive)
405 (emms-with-inhibit-read-only-t
406 (goto-char (line-beginning-position))
407 (yank)
408 (emms-playlist-mode-correct-previous-yank)))
409
410 ;; M-y
411 (defun emms-playlist-mode-yank-pop ()
412 "Cycle through the kill-ring."
413 (interactive)
414 (emms-with-inhibit-read-only-t
415 (yank-pop nil)
416 (emms-playlist-mode-correct-previous-yank)))
417
418 ;; Don't assume that the first track is at the top of the buffer (the
419 ;; same goes for the `emms-playlist-mode-track-below-p'.)
420 (defun emms-playlist-mode-track-above-p ()
421 "Return t if there is a track above this one in the buffer."
422 (previous-property-change (line-beginning-position)))
423
424 (defun emms-playlist-mode-track-below-p ()
425 "Return t if there is a track below this one in the buffer."
426 (next-property-change (line-end-position)))
427
428 ;; The need to avoid killing a playing track causes the code to be
429 ;; written in a bit of a convoluted manner.
430 (defun emms-playlist-mode-shift-track (num)
431 "Shift the track at point by one line.
432
433 If NUM is 0 or a positive number, shift the track at point down
434 one line. Otherwise shift the track up by one line."
435 (emms-playlist-ensure-playlist-buffer)
436 (let ((track (emms-playlist-track-at (point)))
437 (dir (if (>= num 0) 1 -1)))
438 (when (not track)
439 (error "no track at point."))
440 (when (and (< num 0)
441 (not (emms-playlist-mode-track-above-p)))
442 (error "already the first track"))
443 (when (and (> num 0)
444 (not (emms-playlist-mode-track-below-p)))
445 (error "already the last track"))
446 (forward-line dir)
447 (if (emms-playlist-selected-track-at-p)
448 (progn
449 (emms-playlist-mode-shift-track (if (= dir 1) -1 1))
450 (forward-line (if (= dir 1) 1 -1)))
451 (let ((shift (emms-playlist-track-at (point))))
452 (emms-playlist-mode-kill-track)
453 (when (not emms-playlist-mode-kill-whole-line-p)
454 (emms-with-inhibit-read-only-t
455 (kill-line)))
456 (forward-line (* dir -1))
457 (emms-playlist-mode-insert-track shift)
458 (when (= dir -1) (forward-line -2))))))
459
460 (defun emms-playlist-mode-shift-track-down ()
461 "Shift the track at point down one line."
462 (interactive)
463 (emms-playlist-mode-shift-track 0))
464
465 (defun emms-playlist-mode-shift-track-up ()
466 "Shift the track at point up one line."
467 (interactive)
468 (emms-playlist-mode-shift-track -1))
469
470
471 ;;; --------------------------------------------------------
472 ;;; Overlay
473 ;;; --------------------------------------------------------
474 (defun emms-playlist-mode-overlay-selected ()
475 "Place an overlay over the currently selected track."
476 (when emms-playlist-selected-marker
477 (save-excursion
478 (goto-char emms-playlist-selected-marker)
479 (let ((reg (emms-property-region (point) 'emms-track)))
480 (if emms-playlist-mode-selected-overlay
481 (move-overlay emms-playlist-mode-selected-overlay
482 (car reg)
483 (cdr reg))
484 (setq emms-playlist-mode-selected-overlay
485 (make-overlay (car reg)
486 (cdr reg)
487 nil t nil))
488 (overlay-put emms-playlist-mode-selected-overlay
489 'face 'emms-playlist-selected-face)
490 (overlay-put emms-playlist-mode-selected-overlay
491 'evaporate t))))))
492
493
494 ;;; --------------------------------------------------------
495 ;;; Saving/Restoring
496 ;;; --------------------------------------------------------
497 (defun emms-playlist-mode-open-buffer (filename)
498 "Opens a previously saved playlist buffer.
499
500 It creates a buffer called \"filename\", and restores the contents
501 of the saved playlist inside."
502 (interactive "fFile: ")
503 (let* ((s)
504 (buffer (get-buffer-create filename))
505 (name (buffer-name buffer)))
506 (with-current-buffer buffer
507 (emms-insert-file-contents filename)
508 (setq s (read (buffer-string))))
509 (kill-buffer buffer)
510 (with-current-buffer (emms-playlist-new name)
511 (emms-with-inhibit-read-only-t
512 (insert s)
513 (goto-char (point-min))
514 (emms-walk-tracks
515 (emms-playlist-update-track)))
516 (emms-playlist-first)
517 (emms-playlist-select (point))
518 (switch-to-buffer (current-buffer)))))
519
520 (defun emms-playlist-mode-load-playlist ()
521 "Load the playlist into a new EMMS buffer.
522 This preserves the current EMMS buffer."
523 (interactive)
524 (let* ((track (emms-playlist-track-at))
525 (name (emms-track-get track 'name)))
526 (emms-playlist-select (point))
527 (run-hooks 'emms-player-stopped-hook)
528 (switch-to-buffer
529 (emms-playlist-set-playlist-buffer (emms-playlist-new)))
530 (emms-add-playlist name)))
531
532
533 ;;; --------------------------------------------------------
534 ;;; Local functions
535 ;;; --------------------------------------------------------
536 (defun emms-playlist-mode-insert-track (track &optional no-newline)
537 "Insert the description of TRACK at point.
538 When NO-NEWLINE is non-nil, do not insert a newline after the track."
539 (emms-playlist-ensure-playlist-buffer)
540 (emms-with-inhibit-read-only-t
541 (insert (emms-propertize (emms-track-force-description track)
542 'emms-track track
543 'face 'emms-playlist-track-face))
544 (unless no-newline
545 (insert "\n"))))
546
547 (defun emms-playlist-playlist-insert-track ()
548 "Insert the track in playlist at point into the active playlist buffer."
549 (interactive)
550 (let ((track (emms-playlist-track-at)))
551 (with-current-emms-playlist
552 (goto-char (point-max))
553 (emms-playlist-insert-track track))))
554
555 (defun emms-playlist-mode-update-track-function ()
556 "Update the track display at point."
557 (emms-playlist-ensure-playlist-buffer)
558 (emms-with-inhibit-read-only-t
559 (let ((track-region (emms-property-region (point)
560 'emms-track))
561 (track (get-text-property (point)
562 'emms-track))
563 (selectedp (emms-playlist-selected-track-at-p)))
564 (save-excursion
565 (delete-region (car track-region)
566 (cdr track-region))
567 (when selectedp
568 (delete-overlay emms-playlist-mode-selected-overlay)
569 (setq emms-playlist-mode-selected-overlay nil))
570 (emms-playlist-mode-insert-track track t))
571 (when selectedp
572 (emms-playlist-select (point))))))
573
574
575 ;;; --------------------------------------------------------
576 ;;; Entry
577 ;;; --------------------------------------------------------
578 (defun emms-playlist-mode-go ()
579 "Switch to the current emms-playlist buffer and use emms-playlist-mode."
580 (interactive)
581 (if (or (null emms-playlist-buffer)
582 (not (buffer-live-p emms-playlist-buffer)))
583 (error "No current Emms buffer")
584 (switch-to-buffer emms-playlist-buffer)
585 (when (and (not (member major-mode '(emms-playlist-mode emms-mark-mode)))
586 emms-playlist-buffer-p)
587 (emms-playlist-mode))
588 (when emms-playlist-mode-center-when-go
589 (emms-playlist-mode-center-current))))
590
591 (defun emms ()
592 "Switch to the current emms-playlist buffer, use
593 emms-playlist-mode and query for a directory tree to add to the
594 playlist."
595 (interactive)
596 (if (or (null emms-playlist-buffer)
597 (not (buffer-live-p emms-playlist-buffer)))
598 (call-interactively 'emms-add-directory))
599 (emms-playlist-mode-go))
600
601 (defun emms-playlist-mode-go-popup (&optional window-width)
602 "Popup emms-playlist buffer as a side window.
603
604 Default value for WINDOW-WIDTH is `emms-playlist-mode-window-width'.
605 WINDOW-WIDTH should be a positive integer."
606 (interactive)
607 (setq emms-playlist-mode-window-width
608 (round (or window-width emms-playlist-mode-window-width)))
609 (split-window-horizontally (- emms-playlist-mode-window-width))
610 (other-window 1)
611 (emms-playlist-mode-go)
612 (setq emms-playlist-mode-popup-enabled t))
613
614 (defun emms-playlist-mode-next (arg)
615 "Navigate between playlists."
616 (interactive "p")
617 (let ((playlists (emms-playlist-buffer-list))
618 bufs idx)
619 (if playlists
620 ;; if not in playlist mode, switch to emms-playlist-buffer
621 (if (not (member (current-buffer) playlists))
622 (switch-to-buffer (if (and emms-playlist-buffer
623 (buffer-live-p emms-playlist-buffer))
624 emms-playlist-buffer
625 (car playlists)))
626 (setq bufs (member (current-buffer) playlists))
627 (setq idx
628 (+ (- (length playlists) (length bufs))
629 (if (> arg 0) 1 -1)))
630 (switch-to-buffer (nth (mod idx (length playlists)) playlists)))
631 (message "No playlist found!"))))
632 (defun emms-playlist-mode-previous (arg)
633 (interactive "p")
634 (emms-playlist-mode-next (- arg)))
635
636 (defun emms-playlist-mode-startup ()
637 "Instigate emms-playlist-mode on the current buffer."
638 ;; when there is neither a current emms track or a playing one...
639 (when (not (or emms-playlist-selected-marker
640 emms-player-playing-p))
641 ;; ...then stop the player.
642 (emms-stop)
643 ;; why select the first track?
644 (when emms-playlist-buffer-p
645 (emms-playlist-select-first)))
646 ;; when there is a selected track.
647 (when emms-playlist-selected-marker
648 (emms-playlist-mode-overlay-selected))
649 (emms-with-inhibit-read-only-t
650 (add-text-properties (point-min)
651 (point-max)
652 '(face emms-playlist-track-face)))
653 (setq buffer-read-only t)
654 (setq truncate-lines t)
655 (setq buffer-undo-list nil))
656
657 ;;;###autoload
658 (defun emms-playlist-mode () ;FIXME: Use `define-derived-mode'.
659 "A major mode for Emms playlists.
660 \\{emms-playlist-mode-map}"
661 (interactive)
662 (let ((val emms-playlist-buffer-p))
663 (kill-all-local-variables)
664 (setq emms-playlist-buffer-p val))
665
666 (use-local-map emms-playlist-mode-map)
667 (setq major-mode 'emms-playlist-mode
668 mode-name "EMMS")
669
670 (setq emms-playlist-insert-track-function
671 #'emms-playlist-mode-insert-track)
672 (setq emms-playlist-update-track-function
673 #'emms-playlist-mode-update-track-function)
674 (add-hook 'emms-playlist-selection-changed-hook
675 #'emms-playlist-mode-overlay-selected)
676
677 (emms-playlist-mode-startup)
678
679 (run-hooks 'emms-playlist-mode-hook))
680
681
682 (provide 'emms-playlist-mode)
683
684
685 ;;; emms-playlist-mode.el ends here