+(defun ampc-tagger-completion-at-point (&optional all-files)
+ "Perform completion at point via `completion-at-point'.
+If optional prefix argument ALL-FILES is non-nil, use all files
+within the files list buffer as source for completion. The
+default behaviour is to use only the selected ones."
+ (interactive "P")
+ (let ((ampc-tagger-completion-all-files all-files))
+ (completion-at-point)))
+
+(defun ampc-tagger-reset (&optional reset-all-tags)
+ "Reset all tag values within the tagger, based on the selection of files.
+If optional prefix argument RESET-ALL-TAGS is non-nil, restore
+all tags."
+ (interactive "P")
+ (when reset-all-tags
+ (ampc-with-buffer 'tagger
+ no-se
+ (erase-buffer)
+ (loop for tag in ampc-tagger-tags
+ do (insert (ampc-pad (list (concat (symbol-name tag) ":") "dummy"))
+ "\n"))
+ (goto-char (point-min))
+ (re-search-forward ":\\( \\)+")))
+ (ampc-with-buffer 'tagger
+ (loop while (search-forward-regexp
+ (concat "^\\([ \t]*\\)\\("
+ (mapconcat 'symbol-name ampc-tagger-tags "\\|")
+ "\\)\\([ \t]*\\):\\([ \t]*.*\\)$")
+ nil
+ t)
+ do (replace-match "" nil nil nil 1)
+ (replace-match "" nil nil nil 3)
+ (replace-match (concat (make-string (- (car tab-stop-list)
+ (1+ (length (match-string 2))))
+ ? )
+ "<keep>")
+ nil nil nil 4)))
+ (ampc-tagger-update)
+ (ampc-with-buffer 'tagger
+ no-se
+ (when (looking-at "[ \t]+")
+ (goto-char (match-end 0)))))
+
+(defun* ampc-tagger-save (&optional quit &aux tags)
+ "Save tags.
+If optional prefix argument QUIT is non-nil, quit tagger
+afterwards. If the numeric value of QUIT is 16, quit tagger and
+do not trigger a database update"
+ (interactive "P")
+ (ampc-with-buffer 'tagger
+ (loop do (loop until (eobp)
+ while (looking-at "^[ \t]*$")
+ do (forward-line))
+ until (eobp)
+ do (unless (and (looking-at
+ (concat "^[ \t]*\\("
+ (mapconcat 'symbol-name
+ ampc-tagger-tags
+ "\\|")
+ "\\)[ \t]*:"
+ "[ \t]*\\(.*\\)[ \t]*$"))
+ (not (assq (intern (match-string 1)) tags)))
+ (error "Malformed line \"%s\""
+ (buffer-substring (line-beginning-position)
+ (line-end-position))))
+ (push (cons (intern (match-string 1))
+ (let ((val (match-string 2)))
+ (if (string= "<keep>" val)
+ t
+ (set-text-properties 0 (length val) nil val)
+ val)))
+ tags)
+ (forward-line)))
+ (callf2 rassq-delete-all t tags)
+ (with-temp-buffer
+ (loop for (tag . value) in tags
+ do (insert (symbol-name tag) "\n"
+ value "\n"))
+ (let ((input-buffer (current-buffer)))
+ (ampc-with-buffer 'files-list
+ no-se
+ (let ((reporter
+ (make-progress-reporter "Storing tags"
+ 0
+ (let ((count (count-matches "^\\* ")))
+ (if (zerop count)
+ 1
+ count))))
+ (step 0))
+ (ampc-with-selection nil
+ (let* ((data (get-text-property (point) 'data))
+ (old-tags (loop for (tag . data) in (cdr data)
+ collect (cons tag data)))
+ (found-changed (ampc-tagger-tags-modified (cdr data) tags)))
+ (let ((pre-hook-tags (cdr data)))
+ (run-hook-with-args 'ampc-tagger-store-hook found-changed data)
+ (setf found-changed
+ (or found-changed
+ (ampc-tagger-tags-modified pre-hook-tags
+ (cdr data)))))
+ (when found-changed
+ (ampc-tagger-log
+ "Storing tags for file "
+ (abbreviate-file-name (car data)) "\n"
+ "\tOld tags:\n"
+ (loop for (tag . value) in old-tags
+ concat (concat "\t\t"
+ (symbol-name tag) ": "
+ value "\n"))
+ "\tNew tags:\n"
+ (loop for (tag . value) in (cdr data)
+ concat (concat "\t\t"
+ (symbol-name tag) ": "
+ value "\n")))
+ (ampc-tagger-make-backup (car data))
+ (ampc-tagger-report
+ (list "--set" (car data))
+ (with-temp-buffer
+ (insert-buffer-substring input-buffer)
+ (prog1
+ (call-process-region (point-min) (point-max)
+ ampc-tagger-executable
+ nil t nil
+ "--set" (car data))
+ (when ampc-debug
+ (message "ampc-tagger: %s"
+ (buffer-substring
+ (point-min) (point))))))))
+ (run-hook-with-args 'ampc-tagger-stored-hook found-changed data)
+ (let ((inhibit-read-only t))
+ (move-beginning-of-line nil)
+ (forward-char 2)
+ (kill-line 1)
+ (insert
+ (ampc-pad (loop for p in (plist-get (cdr ampc-type)
+ :properties)
+ when (eq (car p) 'filename)
+ collect (file-name-nondirectory (car data))
+ else
+ collect (cdr (assq (intern (car p))
+ (cdr data)))
+ end))
+ "\n")
+ (forward-line -1)
+ (put-text-property (line-beginning-position)
+ (1+ (line-end-position))
+ 'data data))
+ (progress-reporter-update reporter (incf step))))
+ (progress-reporter-done reporter)))))
+ (when quit
+ (ampc-tagger-quit (eq (prefix-numeric-value quit) 16))))
+
+(defun ampc-tagger-quit (&optional no-update)
+ "Quit tagger and restore previous window configuration.
+With optional prefix NO-UPDATE, do not trigger a database update."
+ (interactive "P")
+ (set-window-configuration (or (car-safe ampc-tagger-previous-configuration)
+ ampc-tagger-previous-configuration))
+ (when (car-safe ampc-tagger-previous-configuration)
+ (unless no-update
+ (ampc-trigger-update))
+ (setf ampc-windows (cadr ampc-tagger-previous-configuration)))
+ (setf ampc-tagger-previous-configuration nil))
+
+(defun ampc-move-to-tab ()
+ "Move point to next logical tab stop."
+ (interactive)
+ (let ((tab (loop for tab in
+ (or (get-text-property (point) 'tab-stop-list) tab-stop-list)
+ while (>= (current-column) tab)
+ finally return tab)))
+ (when tab
+ (goto-char (min (+ (line-beginning-position) tab) (line-end-position))))))
+
+(defun ampc-mouse-play-this (event)
+ (interactive "e")
+ (select-window (posn-window (event-end event)))
+ (goto-char (posn-point (event-end event)))
+ (ampc-play-this))
+
+(defun ampc-mouse-delete (event)
+ (interactive "e")
+ (select-window (posn-window (event-end event)))
+ (goto-char (posn-point (event-end event)))
+ (ampc-delete 1))
+
+(defun ampc-mouse-add (event)
+ (interactive "e")
+ (select-window (posn-window (event-end event)))
+ (goto-char (posn-point (event-end event)))
+ (ampc-add-impl))
+
+(defun ampc-mouse-delete-playlist (event)
+ (interactive "e")
+ (select-window (posn-window (event-end event)))
+ (goto-char (posn-point (event-end event)))
+ (ampc-delete-playlist t))
+
+(defun ampc-mouse-load (event)
+ (interactive "e")
+ (select-window (posn-window (event-end event)))
+ (goto-char (posn-point (event-end event)))
+ (ampc-load t))
+
+(defun ampc-mouse-toggle-output-enabled (event)
+ (interactive "e")
+ (select-window (posn-window (event-end event)))
+ (goto-char (posn-point (event-end event)))
+ (ampc-toggle-output-enabled 1))
+
+(defun* ampc-mouse-toggle-mark (event &aux (inhibit-read-only t))
+ (interactive "e")
+ (let ((window (posn-window (event-end event))))
+ (when (with-selected-window window
+ (goto-char (posn-point (event-end event)))
+ (unless (eobp)
+ (move-beginning-of-line nil)
+ (ampc-mark-impl (not (eq (char-after) ?*)) 1)
+ t))
+ (select-window window))))
+
+(defun ampc-mouse-align-point (event)
+ (interactive "e")
+ (select-window (posn-window (event-end event)))
+ (goto-char (posn-point (event-end event)))
+ (ampc-align-point))
+
+(defun* ampc-unmark-all (&aux (inhibit-read-only t))