diff options
Diffstat (limited to 'emms-browser.el')
-rw-r--r-- | emms-browser.el | 655 |
1 files changed, 414 insertions, 241 deletions
diff --git a/emms-browser.el b/emms-browser.el index 7ba603d..b581733 100644 --- a/emms-browser.el +++ b/emms-browser.el @@ -52,19 +52,26 @@ ;; If you just want access to the browser, try M-x ;; emms-browse-by-TYPE, where TYPE is one of artist, album, genre or -;; year. +;; year. These commands can also be used while smart browsing to +;; change the browsing category. ;; If you don't want to activate the code with (emms-devel), you can ;; activate it manually with: ;; (require 'emms-browser) +;; Note this code is very new and is still prone to big changes in the +;; API and breakage. Bug reports are welcome. + ;;; Code: (require 'emms) (require 'emms-cache) (require 'emms-source-file) +(eval-when-compile + (require 'cl)) + ;; -------------------------------------------------- ;; Variables and configuration ;; -------------------------------------------------- @@ -81,6 +88,22 @@ :group 'emms-browser :type 'function) +(defcustom emms-browser-make-name-function + 'emms-browser-make-name-standard + "A function to make names for entries and subentries. +Overriding this function allows you to customise how various elements +are displayed. It is called with two arguments - track and type." + :group 'emms-browser + :type 'function) + +(defcustom emms-browser-insert-track-function + 'emms-browser-insert-track-standard + "A function to insert a track into the playlist. +The default behaviour indents tracks depending on whether you're +adding an album, artist, etc." + :group 'emms-browser + :type 'function) + (defcustom emms-browser-comparison-test 'case-fold "A method for comparing entries in the cache. @@ -123,13 +146,9 @@ Use nil for no sorting." (defvar emms-browser-buffer-name "*EMMS Browser*" "The default buffer name.") -(defvar emms-browser-current-mapping nil +(defvar emms-browser-top-level-hash nil "The current mapping db, eg. artist -> track.") -(make-variable-buffer-local 'emms-browser-current-mapping) - -(defvar emms-browser-current-mapping-type nil - "The current mapping type, eg. 'info-artist") -(make-variable-buffer-local 'emms-browser-current-mapping-type) +(make-variable-buffer-local 'emms-browser-top-level-hash) (defconst emms-browser-mode-map (let ((map (make-sparse-keymap))) @@ -267,10 +286,14 @@ example function is `emms-browse-by-artist'." (bury-buffer)) ;; -------------------------------------------------- -;; Browsing methods - by artist/album/etc +;; Top-level browsing methods - by artist/album/etc ;; -------------------------------------------------- -(defmacro emms-browser-add-category (name track-type &optional expand-func) +;; Since the number of tracks may be rather large, we use a hash to +;; sort the top level elements into various categories. All +;; subelements will be stored in a bdata alist structure. + +(defmacro emms-browser-add-category (name type) "Create an interactive function emms-browse-by-NAME." (let ((funname (intern (concat "emms-browse-by-" name))) (modedesc (concat "Browsing by: " name)) @@ -278,47 +301,42 @@ example function is `emms-browse-by-artist'." `(defun ,funname () ,funcdesc (interactive) - (emms-browser-clear) - (rename-buffer ,modedesc) - (emms-browser-display-by ,track-type ,expand-func) - (goto-char (point-min))))) - -(emms-browser-add-category "artist" 'info-artist 'emms-browser-show-albums) -(emms-browser-add-category "album" 'info-album 'emms-browser-show-titles) -(emms-browser-add-category "genre" 'info-genre 'emms-browser-show-artists) -(emms-browser-add-category "year" 'info-year 'emms-browser-show-artists) - -(defun emms-browser-make-by (field-type) - "Make a mapping with FIELD-TYPE, eg artist -> tracks." - (let ((db (make-hash-table + (let ((hash (emms-browser-make-hash-by ,type))) + (emms-browser-clear) + (rename-buffer ,modedesc) + (emms-browser-render-hash hash ,type) + (setq emms-browser-top-level-hash hash) + (goto-char (point-min)))))) + +(emms-browser-add-category "artist" 'info-artist) +(emms-browser-add-category "album" 'info-album) +(emms-browser-add-category "genre" 'info-genre) +(emms-browser-add-category "year" 'info-year) + +(defun emms-browser-make-hash-by (type) + "Make a hash, mapping with TYPE, eg artist -> tracks." + (let ((hash (make-hash-table :test emms-browser-comparison-test)) field existing-entry) (maphash (lambda (path track) - (setq field (emms-track-get track field-type "misc")) - (setq existing-entry (gethash field db)) + (setq field (emms-track-get track type "misc")) + (setq existing-entry (gethash field hash)) (if existing-entry - (puthash field (cons track existing-entry) db) - (puthash field (list track) db))) + (puthash field (cons track existing-entry) hash) + (puthash field (list track) hash))) emms-cache-db) - db)) - -(defun emms-browser-display-by (field-type &optional expand-func) - "Render a mapping into a browser buffer. -Optional EXPAND-FUNC is a function to call when expanding a -line." - (let ((db (emms-browser-make-by field-type))) - (maphash (lambda (desc data) - (emms-browser-insert-entry desc data expand-func)) - db) - ;; sort - (setq emms-browser-current-mapping db) - ;; FIXME: currently we use a hash for the 'level 1' information, - ;; and an alist for subinfo. that means that this sorting is done - ;; differently to subinfo.. - ;; should we use emms-browser-alpha-sort-function instead? - (emms-with-inhibit-read-only-t - (let ((sort-fold-case t)) - (sort-lines nil (point-min) (point-max)))))) + hash)) + +(defun emms-browser-render-hash (db type) + "Render a mapping (DB) into a browser buffer." + (maphash (lambda (desc data) + ;; reverse the entries so that unsorted tracks are displayed in + ;; ascending order + (emms-browser-insert-top-level-entry desc (nreverse data) type)) + db) + (emms-with-inhibit-read-only-t + (let ((sort-fold-case t)) + (sort-lines nil (point-min) (point-max))))) (defun case-fold-string= (a b) (compare-strings a nil nil b nil nil t)) @@ -329,130 +347,248 @@ line." (define-hash-table-test 'case-fold 'case-fold-string= 'case-fold-string-hash) -;; -------------------------------------------------- -;; Operations on individual lines -;; -------------------------------------------------- - -(defun emms-browser-insert-entry (entry tracks &optional expand-func) - "Add a single ENTRY -> TRACKS mapping to the buffer. -EXPAND-FUNC is an optional func to call when expanding a line." +(defun emms-browser-insert-top-level-entry (entry tracks type) + "Insert a single top level entry into the buffer." (emms-browser-ensure-browser-buffer) (emms-with-inhibit-read-only-t - (insert (emms-propertize entry - 'emms-browser-data tracks - 'emms-browser-level 1 - 'emms-browser-expand-func expand-func - 'face 'emms-browser-tracks-face) "\n"))) + (insert (emms-propertize + entry + 'emms-browser-bdata + (emms-browser-make-bdata-tree + type 1 tracks) + 'face 'emms-browser-tracks-face) "\n"))) -(defun emms-browser-add-tracks () - "Add all the tracks on the current line to the playlist." - (interactive) - (let ((tracks (emms-browser-data-at)) - (count 0) - old-max new-max type name) - (unless tracks - (error "No tracks on current line!")) - (with-current-emms-playlist - (setq old-max (point-max))) - ;; add each of the tracks +;; -------------------------------------------------- +;; Building a subitem tree +;; -------------------------------------------------- + +(defun emms-browser-next-mapping-type (current-mapping) + "Return the next sensible mapping. +Eg. if current-mapping is currently 'info-artist, return 'info-album." + (cond + ((eq current-mapping 'info-artist) 'info-album) + ((eq current-mapping 'info-album) 'info-title) + ((eq current-mapping 'info-genre) 'info-artist) + ((eq current-mapping 'info-year) 'info-artist))) + +(defun emms-browser-make-bdata-tree (type level tracks) + "Build a tree of browser DB elements for tracks." + (emms-browser-make-bdata + (emms-browser-make-bdata-tree-recurse + type level tracks) + ;; with the current hash code, we're guaranteed to have only one + ;; element at the top + (emms-track-get (car tracks) type) + type level)) + +(defun emms-browser-make-bdata-tree-recurse (type level tracks) + "Build a tree of alists based on a list of tracks, TRACKS. +For example, if TYPE is 'info-year, return an alist like: +artist1 -> album1 -> *track* 1.." + (let* ((next-type (emms-browser-next-mapping-type type)) + (next-level (1+ level)) + alist name new-db new-tracks) + ;; if we're at a leaf, the db data is a list of tracks + (if (eq type 'info-title) + tracks + ;; otherwise, make DBs from the sub elements + (setq alist + (emms-browser-make-sorted-alist + next-type tracks)) + (mapcar (lambda (entry) + (setq name (emms-browser-make-name + entry next-type)) + (setq new-tracks (cdr entry)) + (emms-browser-make-bdata + (emms-browser-make-bdata-tree-recurse + next-type next-level new-tracks) + name next-type next-level)) + alist)))) + +(defun emms-browser-make-name (entry type) + "Return a name for ENTRY, used for making a bdata object. +This uses `emms-browser-make-name-function'" + ;; we use cadr because we are guaranteed only one track in entry. + (funcall emms-browser-make-name-function entry type)) + +(defun emms-browser-make-name-standard (entry type) + "Add track numbers to track names. +Apart from tracks, names are displayed without modification." + (if (eq type 'info-title) + (emms-browser-make-name-with-track-number (cadr entry)) + (car entry))) + +(defun emms-browser-make-name-with-track-number (track) + "Concat a track number to the name of track, if one exists." + (let ((tracknum (emms-track-get track 'info-tracknumber))) + (concat + (if (string= tracknum "0") + "" + (concat + (if (eq (length tracknum) 1) + (concat "0" tracknum) + tracknum) + ". ")) + (emms-track-get track 'info-title)))) + +(defun emms-browser-make-bdata (data name type level) + "Return a browser data item from ALIST. +DATA should be a list of DB items, or a list of tracks. +NAME is a name for the DB item. +TYPE is a category the data is organised by, such as 'info-artist. +LEVEL is the number of the sublevel the db item will be placed in." + (list (cons 'type type) + (cons 'level level) + (cons 'name name) + (cons 'data data))) + +(defun emms-browser-make-alist (type tracks) + "Make an alist mapping of TYPE -> TRACKS. +Items with no metadata for TYPE will be placed in 'misc'" + (let (db key existing) (dolist (track tracks) - (setq type (emms-track-get track 'type)) - (setq name (emms-track-get track 'name)) - (cond - ((eq type 'file) - (emms-add-file name)) - ((eq type 'url) - (emms-add-url name))) - (setq count (1+ count))) - (run-mode-hooks 'emms-browser-tracks-added-hook) - (message "Added %d tracks." count))) + (setq key (emms-track-get track type "misc")) + (setq existing (assoc key db)) + (if existing + (setcdr existing (cons track (cdr existing))) + (push (cons key (list track)) db))) + ;; sort the entries we've built + (dolist (item db) + (setcdr item (nreverse (cdr item)))) + db)) -(defun emms-browser-add-tracks-and-play () - "Add all the tracks on the current line, play the first file." - (interactive) - (let (old-pos) - (with-current-emms-playlist - (setq old-pos (point-max))) - (emms-browser-add-tracks) - (with-current-emms-playlist - (goto-char old-pos) - (emms-playlist-select (point))) - ;; FIXME: is there a better way of doing this? - (emms-stop) - (emms-start))) +(defun emms-browser-make-sorted-alist (type tracks) + "Return a sorted alist of TRACKS. +TYPE is the metadata to make the alist by - eg. if it's +'info-artist, an alist of artists will be made." + (emms-browser-sort-alist + (emms-browser-make-alist type tracks) + type)) -(defun emms-browser-data-at (&optional pos) - "Return the tracks at POS (point if not given), or nil if none." - (emms-browser-ensure-browser-buffer) - (save-excursion - ;; move the point to the start of the line, since the trailing new - ;; line is not propertized - (move-beginning-of-line nil) - (emms-with-widened-buffer - (get-text-property (or pos (point)) - 'emms-browser-data)))) +;; -------------------------------------------------- +;; BDATA accessors and predicates +;; -------------------------------------------------- -(defun emms-isearch-buffer () - "Isearch through the buffer." - (interactive) - (goto-char (point-min)) - (when (isearch-forward) - (unless (emms-browser-subitems-visible) - (emms-browser-show-subitems) - (next-line)))) +(defun emms-browser-bdata-level (bdata) + (cdr (assq 'level bdata))) + +(defun emms-browser-bdata-name (bdata) + (cdr (assq 'name bdata))) + +(defun emms-browser-bdata-type (bdata) + (cdr (assq 'type bdata))) + +(defun emms-browser-bdata-data (bdata) + (cdr (assq 'data bdata))) + +(defun emms-browser-bdata-p (obj) + "True if obj is a BDATA object." + (consp (assq 'data obj))) ;; -------------------------------------------------- -;; Expansion/subitem support (experimental) +;; Sorting expanded entries ;; -------------------------------------------------- -(defmacro emms-browser-add-show-category (name field-type &optional - expand-func sort-func) - "Create an interactive function emms-browser-show-FIELD-TYPE. -EXPAND-FUNC is used to further expand subitems if not already -expanded. -SORT-FUNC is called to sort retrieved data." - (let ((fname (intern (concat "emms-browser-show-" name))) - (fdesc (concat "Show " name " under current line"))) - `(defun ,fname () - ,fdesc - (interactive) - (unless (emms-browser-subitems-visible) - (let ((data (emms-browser-make-alist-from-field - ,field-type - (emms-browser-data-at)))) - (when ,sort-func - (setq data (funcall ,sort-func data))) - (emms-browser-insert-subitems data ,expand-func)))))) - -;; -;; create emms-browser-show-* -;; -(emms-browser-add-show-category - "albums" 'info-album - 'emms-browser-show-titles - 'emms-browser-sort-by-name) - -(emms-browser-add-show-category - "artists" 'info-artist - 'emms-browser-show-albums - 'emms-browser-sort-by-name) - -(emms-browser-add-show-category - "titles" 'info-title - nil - 'emms-browser-sort-by-tracks) +(defmacro emms-browser-sort-cadr (sort-func) + "Return a function to sort an alist using SORT-FUNC. +This sorting predicate will compare the cadr of each entry. +SORT-FUNC should be a playlist sorting predicate like +`emms-playlist-sort-by-natural-order'." + `(lambda (a b) + (funcall ,sort-func (cadr a) (cadr b)))) + +(defmacro emms-browser-sort-car (sort-func) + "Return a function to sort an alist using SORT-FUNC. +This sorting predicate will compare the car of each entry. +SORT-FUNC should be a playlist sorting predicate like +`emms-playlist-sort-by-natural-order'." + `(lambda (a b) + (funcall ,sort-func (car a) (car b)))) + +(defun emms-browser-sort-by-track (alist) + "Sort an ALIST by the tracks in each entry. +Uses `emms-browser-track-sort-function'." + (if emms-browser-track-sort-function + (sort alist (emms-browser-sort-cadr + emms-browser-track-sort-function)) + alist)) + +(defun emms-browser-sort-by-name (alist) + "Sort ALIST by keys alphabetically. +Uses `emms-browser-alpha-sort-function'." + (if emms-browser-alpha-sort-function + (sort alist (emms-browser-sort-car + emms-browser-alpha-sort-function)) + alist)) + +(defun emms-browser-sort-alist (alist type) + "Sort ALIST using the sorting function for TYPE." + (let ((sort-func + (cond + ((or + (eq type 'info-album) + (eq type 'info-artist) + (eq type 'info-year) + (eq type 'info-genre)) + 'emms-browser-sort-by-name) + ((eq type 'info-title) + 'emms-browser-sort-by-track) + (t (message "Can't sort unknown mapping!"))))) + (funcall sort-func alist))) + +;; -------------------------------------------------- +;; Subitem operations on the buffer +;; -------------------------------------------------- + +(defun emms-browser-bdata-at-point () + "Return the bdata object at point. +Includes information at point (such as album name), and metadata." + (get-text-property (line-beginning-position) + 'emms-browser-bdata)) + +(defun emms-browser-data-at-point () + "Return the data stored under point. +This will be a list of DB items." + (emms-browser-bdata-data (emms-browser-bdata-at-point))) (defun emms-browser-level-at-point () - "Return the current level at point. -Actually this function returns the value of the first character -on the line, because if point is on a trailing \n it will fail. -Returns 0 if the current line is not an entry." - (let ((val - (get-text-property (line-beginning-position) - 'emms-browser-level))) - (if val - val - 0))) + "Return the current level at point." + (emms-browser-bdata-level (emms-browser-bdata-at-point))) + +(defun emms-browser-expand-one-level () + "Expand the current line by one sublevel." + (interactive) + (let* ((data (emms-browser-data-at-point))) + (save-excursion + (next-line) + (beginning-of-line) + (dolist (data-item data) + (emms-browser-insert-data-item data-item))))) + +(defun emms-browser-insert-data-item (data-item) + "Insert DATA-ITEM into the buffer. +This checks DATA-ITEM's level to determine how much to indent. +The line will have a property emms-browser-bdata storing subitem +information." + (let* ((level (emms-browser-bdata-level data-item)) + (name (emms-browser-bdata-name data-item)) + (indent (emms-browser-make-indent-for-level level))) + (emms-with-inhibit-read-only-t + (insert + (emms-propertize + (concat indent name) + 'emms-browser-bdata data-item + 'face (emms-browser-face-from-level level)) + "\n")))) + +(defun emms-browser-make-indent-for-level (level) + (make-string (* 2 (1- level)) ?\ )) + +(defun emms-browser-face-from-level (level) + "Return a face appropriate for LEVEL." + (intern + (concat "emms-browser-tracks-sub-face-" + (int-to-string (1- level))))) (defun emms-browser-find-entry-more-than-level (level) "Move point to next entry more than LEVEL and return point. @@ -460,14 +596,16 @@ If no entry exits, return nil. Returns point if currently on a an entry more than LEVEL." (let ((old-pos (point)) level-at-point) - (re-search-forward "\n" nil t) - (if (> (emms-browser-level-at-point) level) + (forward-line 1) + (setq level-at-point (emms-browser-level-at-point)) + (if (and level-at-point + (> level-at-point level)) (point) (goto-char old-pos) nil))) (defun emms-browser-subitems-visible () - "True if there are any subentries under point." + "True if there are any subentries visible point." (let ((current-level (emms-browser-level-at-point)) new-level) (save-excursion @@ -475,109 +613,145 @@ Returns point if currently on a an entry more than LEVEL." (when (setq new-level (emms-browser-level-at-point)) (> new-level current-level))))) +(defun emms-browser-subitems-exist () + "True if it's possible to expand the current line." + (not (eq (emms-browser-bdata-type + (emms-browser-bdata-at-point)) + 'info-title))) + +(defun emms-browser-move-up-level () + "Move up one level if possible. +Return true if we were able to move up." + (let ((moved nil) + (continue t) + (current-level (emms-browser-level-at-point))) + (while (and + continue + (zerop (forward-line -1))) + (when (> current-level (emms-browser-level-at-point)) + (setq moved t) + (setq continue nil))) + moved)) + (defun emms-browser-toggle-subitems () "Show or hide (kill) subitems under the current line." (interactive) (if (emms-browser-subitems-visible) (emms-browser-kill-subitems) - (emms-browser-show-subitems))) + (if (emms-browser-subitems-exist) + (emms-browser-show-subitems) + (assert (emms-browser-move-up-level)) + (emms-browser-kill-subitems)))) (defun emms-browser-show-subitems () "Show subitems under the current line." - (let ((func (get-text-property (line-beginning-position) - 'emms-browser-expand-func))) - (if func - (funcall func) - (message "Can't expand further!")))) + (emms-browser-expand-one-level)) (defun emms-browser-kill-subitems () "Remove all subitems under the current line. Stops at the next line at the same level, or EOF." (let ((current-level (emms-browser-level-at-point)) - (kill-whole-line t)) - (save-excursion - (emms-with-inhibit-read-only-t - (while (emms-browser-find-entry-more-than-level current-level) - (kill-line) - (previous-line)))))) - -(defun emms-browser-insert-subitems (subitems &optional expand-func) - "Insert SUBITEMS under the current item. -SUBITEMS is a list of cons cells (desc . data). -emms-browser-level will be set to 1 more than the current level. -Don't add anything if there are already subitems below." - (let ((new-level (1+ (emms-browser-level-at-point))) - desc data) - (save-excursion - (next-line) - (beginning-of-line) - (emms-with-inhibit-read-only-t - (dolist (item subitems) - (setq desc (car item)) - (setq data (cdr item)) - (insert - (emms-propertize (concat (make-string (* 2 (1- new-level)) ?\ ) desc) - 'emms-browser-data data - 'emms-browser-level new-level - 'emms-browser-expand-func expand-func - 'face - (intern - (concat - "emms-browser-tracks-sub-face-" - (int-to-string - (1- new-level))))) - "\n")))))) - -(defun emms-browser-make-alist-from-field (field-type tracks) - "Make an alist mapping of FIELD-TYPE -> TRACKS. -Items with no metadata for FIELD-TYPE will be placed in 'misc'" - (let (db key existing) - (dolist (track tracks) - (setq key (emms-track-get track field-type "misc")) - (setq existing (assoc key db)) - (if existing - (setcdr existing (cons track (cdr existing))) - (push (cons key (list track)) db))) - db)) + (next-line (line-beginning-position 2))) + (emms-with-inhibit-read-only-t + (delete-region next-line + (save-excursion + (while + (emms-browser-find-entry-more-than-level + current-level)) + (line-beginning-position 2)))))) + ;; -------------------------------------------------- -;; Sorting expanded entries +;; Dealing with the playlist (queuing songs, etc) ;; -------------------------------------------------- -(defmacro emms-browser-sort-cadr (sort-func) - "Return a function to sort an alist using SORT-FUNC. -This sorting predicate will compare the cadr of each entry. -SORT-FUNC should be a playlist sorting predicate like -`emms-playlist-sort-by-natural-order'." - `(lambda (a b) - (funcall ,sort-func (cadr a) (cadr b)))) +(defun emms-browser-insert-playlist-group (type group level) + "Insert a group description into the playlist buffer. +Eg. [album] foo bar" + (let ((short-type (substring (symbol-name type) 5))) + (with-current-emms-playlist + (goto-char (point-max)) + (insert + (emms-browser-make-indent-for-level level) + (format "[%s] %s\n" short-type group))))) + +(defun emms-browser-insert-track (track name level) + "Insert a track into the playlist buffer, called NAME. +LEVEL is used to control indentation." + (funcall emms-browser-insert-track-function track name level)) + +(defun emms-browser-insert-track-standard (track name level) + (with-current-emms-playlist + (goto-char (point-max)) + (insert (emms-propertize + (concat + (emms-browser-make-indent-for-level level) + name) + 'face 'emms-playlist-track-face + 'emms-track track) + "\n"))) -(defmacro emms-browser-sort-car (sort-func) - "Return a function to sort an alist using SORT-FUNC. -This sorting predicate will compare the car of each entry. -SORT-FUNC should be a playlist sorting predicate like -`emms-playlist-sort-by-natural-order'." - `(lambda (a b) - (funcall ,sort-func (car a) (car b)))) +(defun emms-browser-add-tracks () + "Add all tracks at point." + (interactive) + (let ((bdata (emms-browser-bdata-at-point))) + (emms-browser-add-bdata-to-playlist + bdata (emms-browser-bdata-level bdata))) + (run-hooks 'emms-browser-tracks-added-hook)) -(defun emms-browser-sort-by-tracks (data) - "Sort an alist DATA by the tracks in each entry. -Uses `emms-browser-track-sort-function'." - (if emms-browser-track-sort-function - (sort data (emms-browser-sort-cadr - emms-browser-track-sort-function)) - data)) +(defun emms-browser-add-tracks-and-play () + "Add all tracks at point, and play the first added track." + (interactive) + (let (old-pos) + (with-current-emms-playlist + (setq old-pos (point-max))) + (emms-browser-add-tracks) + (with-current-emms-playlist + (goto-char old-pos) + (emms-playlist-next) + (emms-playlist-select (point))) + ;; FIXME: is there a better way of doing this? + (emms-stop) + (emms-start))) -(defun emms-browser-sort-by-name (data) - "Sort an alist DATA by keys. -Uses `emms-browser-alpha-sort-function'." - (if emms-browser-alpha-sort-function - (sort data (emms-browser-sort-car - emms-browser-alpha-sort-function)) - data)) +(defun emms-browser-add-bdata-to-playlist (bdata starting-level) + "Add all tracks in BDATA to the playlist." + (let ((type (emms-browser-bdata-type bdata)) + (name (emms-browser-bdata-name bdata)) + (level (emms-browser-bdata-level bdata))) + + ;; adjust the indentation relative to the starting level + (when starting-level + (setq level (- level (1- starting-level)))) + + (unless (eq type 'info-title) + (emms-browser-insert-playlist-group + type name level)) + + (dolist (item (emms-browser-bdata-data bdata)) + (if (not (eq type 'info-title)) + (emms-browser-add-bdata-to-playlist item starting-level) + ;; add full track name as there may not be enough context + (setq name (concat (emms-track-get item 'info-artist) + " - " + ;; track numbers don't make much sense + ;; for individual files + (or (and (> level 1) + name) + (emms-track-get item 'info-title)))) + (emms-browser-insert-track + item name level))))) + +(defun emms-isearch-buffer () + "Isearch through the buffer." + (interactive) + (goto-char (point-min)) + (when (isearch-forward) + (unless (emms-browser-subitems-visible) + (emms-browser-show-subitems)))) ;; -------------------------------------------------- -;; Linked browser and playlist windows (experimental) +;; Linked browser and playlist windows ;; -------------------------------------------------- (defcustom emms-browser-switch-to-playlist-on-add @@ -689,6 +863,5 @@ Returns the playlist window." ;; linked buffer (bury-buffer other-buf))) -;(defun emms (provide 'emms-browser) ;;; emms-browser.el ends here |