anchor.diff:                                         :href (lisp-url `(nyxt::delete-bookmark ,url-href)) "Delete"))
                                  (:hr ""))))))))))
   
  -(declaim (ftype (function (quri:uri) string) url-bookmark-tags))
   (export-always 'url-bookmark-tags)
   (defun url-bookmark-tags (url)
  -  "Return the space-separated string of tags of the bookmark corresponding to
  -URL."
  +  "Return the list of tags of the bookmark corresponding to URL."
     (with-data-unsafe (bookmarks (bookmarks-path (current-buffer)))
  -    (the (values string &optional)
  -        (let ((existing-bm (find url bookmarks :key #'url :test #'equal-url)))
  -          (if existing-bm
  -              (str:join " " (tags existing-bm))
  -              "")))))
  +    (alex:when-let ((existing (find url bookmarks :key #'url :test #'equal-url)))
  +      (tags existing))))
   
   (define-command bookmark-current-page (&optional (buffer (current-buffer)))
     "Bookmark the URL of BUFFER."
  -  (flet ((extract-keywords (html limit)
  -           (sera:take limit (delete "" (mapcar #'first
  -                                               (analysis:keywords
  -                                                (make-instance
  -                                                 'analysis:document
  -                                                 :string-contents (plump:text (plump:parse html)))))
  -                                    :test #'string=)))
  -         (make-tags (name-list)
  -           (mapcar (lambda (name) (make-tag :name name :description "suggestion"))
  -                   name-list)))
  -    (if (url-empty-p (url buffer))
  -        (echo "Buffer has no URL.")
  -        (let* ((body (with-current-buffer buffer
  -                       (ffi-buffer-get-document buffer)))
  -               (tags (prompt
  -                      :prompt "Tag(s)"
  -                      ;; :default-modes '(set-tag-mode minibuffer-mode) ; TODO: Replace completion.
  -                      :input (url-bookmark-tags (url buffer))
  -                      :sources (list
  -                                (make-instance 'prompter:word-source
  -                                               :name "New tags"
  -                                               :multi-selection-p t)
  -                                (make-instance 'tag-source
  -                                               :extra-tags (make-tags (extract-keywords body 5)))))))
  -          (bookmark-add (url buffer)
  -                        :title (title buffer)
  -                        :tags tags)
  -          (echo "Bookmarked ~a." (object-display (url buffer)))))))
  +  ;; TODO: Re-use extract-keywords to implement tag suggestion source.
  +  ;; (flet ((extract-keywords (html limit)
  +  ;;          (sera:take limit (delete "" (mapcar #'first
  +  ;;                                              (analysis:keywords
  +  ;;                                               (make-instance
  +  ;;                                                'analysis:document
  +  ;;                                                :string-contents (plump:text (plump:parse html)))))
  +  ;;                                   :test #'string=)))))
  +  (if (url-empty-p (url buffer))
  +      (echo "Buffer has no URL.")
  +      (let* (;; (body (with-current-buffer buffer
  +             ;;         (ffi-buffer-get-document buffer)))
  +             (tags (prompt
  +                    :prompt "Tag(s)"
  +                    :sources (list
  +                              (make-instance 'prompter:word-source
  +                                             :name "New tags"
  +                                             :multi-selection-p t)
  +                              (make-instance 'tag-source
  +                                             ;; TODO: This seems to rarely work, why?
  +                                             :marks (url-bookmark-tags (url buffer))
  +                                             ;; TODO: Move extra-tags to a separate source.
  +                                             ;; :extra-tags (extract-keywords body 5)
  +                                             )))))
  +        (bookmark-add (url buffer)
  +                      :title (title buffer)
  +                      :tags tags)
  +        (echo "Bookmarked ~a." (object-display (url buffer))))))
   
   (define-command bookmark-page ()
     "Bookmark the currently opened page(s) in the active buffer."
  
positive.code:                                                  (when (equal-url (url b) url)
                                                     (setf entry b)))
                                                 bookmarks))
               (tags (mapcar (lambda (tag)
                               (if (stringp tag) tag (tag-name tag)))
                             ;; TODO: We should not need ensure-list.  Make sure
                             ;; prompter does not return "" on empty input.
                             (uiop:ensure-list tags))))
          (unless entry
            (setf entry (make-instance 'bookmark-entry
                                       :url url)))
  
negative.code:    (prompter:constructor (get-data (bookmarks-path (current-buffer))))
     (prompter:active-properties '(:url :title :tags))))
  
  (defun tag-suggestions ()
    (with-data-unsafe (bookmarks (bookmarks-path (current-buffer)))
      (let ((tags (sort (delete-duplicates
                         (apply #'append
                                (mapcar #'tags bookmarks))
                         :test #'string-equal)
                        #'string-lessp)))
        tags)))
  
  (defun last-word (s)
  