Index: sbbs.el ================================================================== --- sbbs.el +++ sbbs.el @@ -268,12 +268,12 @@ (when sbbs-jump-to-link (forward-button 1) (when (invisible-p (point)) (goto-char point))))))) -(defun sbbs--insert-link (text link) - "Insert link to LINK as TEXT into buffer. +(defun sbbs--process-link (text link) + "Process TEXT that refers to LINK. If LINK is a (board, thread or site) local link, modify opening behaviour accordingly." (save-match-data (let ((match (string-match sbbs--link-regexp link)) @@ -302,34 +302,58 @@ ((/= id sbbs--thread-id) (let ((sbbs--board board)) (sbbs-view-open id range))) ;; this thread (range (sbbs--limit-to-range range)))))) - (insert-button (propertize text 'face 'sbbs--variable-pitch) - 'action func 'sbbs-ref range))))) + (propertize text 'action func 'sbbs-ref range))))) + +(defun sbbs--process-sxml (sxml) + "Process SXML into a formatted string." + (message "%S" sxml) + (let (processed) + (dolist (it (if (listp sxml) sxml (list sxml))) + (push (cond ((stringp it) + (propertize it 'face 'sbbs--variable-pitch)) + ((eq (car it) 'br) + "\n") + ((eq (car it) 'b) + (propertize (sbbs--process-sxml (cdr it)) + 'face '(bold sbbs--variable-pitch))) + ((eq (car it) 'i) + (propertize (sbbs--process-sxml (cdr it)) + 'face '(italic sbbs--variable-pitch))) + ((eq (car it) 'code) + (propertize (sbbs--process-sxml (cdr it)) + 'face 'fixed-pitch)) + ((eq (car it) 'del) + (propertize (sbbs--process-sxml (cdr it)) + 'face 'sbbs--spoiler-face)) + ((eq (car it) 'a) + (let* ((text (sbbs--process-sxml (caddr it))) + (link (plist-get (cadadr it) 'href))) + (sbbs--process-link text link))) + (t (prin1-to-string it))) + processed)) + (apply #'concat (nreverse processed)))) (defun sbbs--insert-sxml-par (sxml) "Insert paragraph contents SXML at point." - (dolist (it sxml) - (cond ((stringp it) - (insert (propertize it 'face 'sbbs--variable-pitch))) - ((eq (car it) 'br) - (newline)) - ((eq (car it) 'b) - (insert (propertize (cadr it) 'face '(bold sbbs--variable-pitch)))) - ((eq (car it) 'i) - (insert (propertize (cadr it) 'face '(italic sbbs--variable-pitch)))) - ((eq (car it) 'code) - (insert (propertize (cadr it) 'face 'fixed-pitch))) - ((eq (car it) 'del) - (insert (propertize (cadr it) 'face 'sbbs--spoiler-face))) - ((eq (car it) 'a) - (let* ((text (caddr it)) - (link (plist-get (cadadr it) 'href))) - (sbbs--insert-link text link))) - (t (insert (prin1-to-string it))))) - (insert ?\n)) + (save-restriction + (narrow-to-region (point) (point)) + (insert (sbbs--process-sxml sxml)) + (let (match) + (goto-char (point-min)) + (while (setq match (text-property-search-forward 'action)) + ;; Buttons use overlays that cannot be passed in + ;; strings. Therefore whenever a `activity' property was + ;; inserted into the buffer, `make-button' has to be called + ;; once more to add the actual overlay. + (make-button (prop-match-beginning match) + (prop-match-end match) + 'action (prop-match-value match))) + (goto-char (point-max))) + (newline))) (defun sbbs--insert-sxml (sxml) "Insert top level SXML into buffer at point." (dolist (par sxml) (cond ((eq (car par) 'p)