bbj: -> bbj-
parent
c30627a604
commit
68087a1c87
283
bbj.el
283
bbj.el
|
@ -1,49 +1,49 @@
|
||||||
(require 'json)
|
(require 'json)
|
||||||
(require 'cl)
|
(require 'cl)
|
||||||
|
|
||||||
(defvar bbj:host "localhost")
|
(defvar bbj-host "localhost")
|
||||||
(defvar bbj:port "7066")
|
(defvar bbj-port "7066")
|
||||||
(defvar bbj:width 80)
|
(defvar bbj-width 80)
|
||||||
|
|
||||||
;; blah blah user servicable parts blah blaheiu hre ;;;;;;;;;;r;r;r;r;;;q;q;;;
|
;; blah blah user servicable parts blah blaheiu hre ;;;;;;;;;;r;r;r;r;;;q;q;;;
|
||||||
(defvar bbj:old-p (eq emacs-major-version 24))
|
(defvar bbj-old-p (eq emacs-major-version 24))
|
||||||
(defvar bbj:logged-in nil)
|
(defvar bbj-logged-in nil)
|
||||||
(defvar bbj:user nil)
|
(defvar bbj-user nil)
|
||||||
(defvar bbj:hash nil)
|
(defvar bbj-hash nil)
|
||||||
(make-variable-buffer-local
|
(make-variable-buffer-local
|
||||||
(defvar bbj:*usermap* nil))
|
(defvar bbj-*usermap* nil))
|
||||||
(make-variable-buffer-local
|
(make-variable-buffer-local
|
||||||
(defvar bbj:buffer-type nil))
|
(defvar bbj-buffer-type nil))
|
||||||
(make-variable-buffer-local
|
(make-variable-buffer-local
|
||||||
(defvar bbj:aux-callback #'ignore))
|
(defvar bbj-aux-callback #'ignore))
|
||||||
|
|
||||||
|
|
||||||
(define-derived-mode bbj-mode fundamental-mode "BBJ"
|
(define-derived-mode bbj-mode fundamental-mode "BBJ"
|
||||||
"Mode for browsing and posting to BBJ."
|
"Mode for browsing and posting to BBJ."
|
||||||
:group 'bbj-mode
|
:group 'bbj-mode
|
||||||
(local-set-key (kbd "SPC") 'bbj:next-post)
|
(local-set-key (kbd "SPC") 'bbj-next-post)
|
||||||
(local-set-key (kbd "j") 'bbj:next-post)
|
(local-set-key (kbd "j") 'bbj-next-post)
|
||||||
(local-set-key (kbd "n") 'bbj:next-post)
|
(local-set-key (kbd "n") 'bbj-next-post)
|
||||||
(local-set-key (kbd "<down>") 'bbj:next-post)
|
(local-set-key (kbd "<down>") 'bbj-next-post)
|
||||||
|
|
||||||
(local-set-key (kbd "DEL") 'bbj:prev-post)
|
(local-set-key (kbd "DEL") 'bbj-prev-post)
|
||||||
(local-set-key (kbd "k") 'bbj:prev-post)
|
(local-set-key (kbd "k") 'bbj-prev-post)
|
||||||
(local-set-key (kbd "p") 'bbj:prev-post)
|
(local-set-key (kbd "p") 'bbj-prev-post)
|
||||||
(local-set-key (kbd "<up>") 'bbj:prev-post)
|
(local-set-key (kbd "<up>") 'bbj-prev-post)
|
||||||
|
|
||||||
(local-set-key (kbd "RET") 'bbj:enter)
|
(local-set-key (kbd "RET") 'bbj-enter)
|
||||||
(local-set-key (kbd "l") 'bbj:enter)
|
(local-set-key (kbd "l") 'bbj-enter)
|
||||||
(local-set-key (kbd "o") 'bbj:enter)
|
(local-set-key (kbd "o") 'bbj-enter)
|
||||||
(local-set-key (kbd "<right>") 'bbj:enter)
|
(local-set-key (kbd "<right>") 'bbj-enter)
|
||||||
|
|
||||||
(local-set-key (kbd "q") 'quit-window)
|
(local-set-key (kbd "q") 'quit-window)
|
||||||
(local-set-key (kbd "<left>") 'quit-window)
|
(local-set-key (kbd "<left>") 'quit-window)
|
||||||
|
|
||||||
(local-set-key (kbd "+") 'bbj:compose)
|
(local-set-key (kbd "+") 'bbj-compose)
|
||||||
(local-set-key (kbd "c") 'bbj:compose)
|
(local-set-key (kbd "c") 'bbj-compose)
|
||||||
|
|
||||||
(local-set-key (kbd "C-c C-c") 'bbj:aux)
|
(local-set-key (kbd "C-c C-c") 'bbj-aux)
|
||||||
(local-set-key (kbd "r") 'bbj:quote-current-post))
|
(local-set-key (kbd "r") 'bbj-quote-current-post))
|
||||||
|
|
||||||
(ignore-errors
|
(ignore-errors
|
||||||
(evil-set-initial-state 'bbj-mode 'emacs))
|
(evil-set-initial-state 'bbj-mode 'emacs))
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
|
|
||||||
;;;; network shit ;;;;
|
;;;; network shit ;;;;
|
||||||
|
|
||||||
(defun bbj:descend (alist &rest keys)
|
(defun bbj-descend (alist &rest keys)
|
||||||
"Recursively retrieve symbols from a nested alist. A required beverage
|
"Recursively retrieve symbols from a nested alist. A required beverage
|
||||||
for all JSON tourists."
|
for all JSON tourists."
|
||||||
(while keys
|
(while keys
|
||||||
|
@ -83,13 +83,13 @@ for all JSON tourists."
|
||||||
alist)
|
alist)
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:request (method &rest pairs)
|
(defun bbj-request (method &rest pairs)
|
||||||
"Poke netcat to poke the server who will hopefully poke us back"
|
"Poke netcat to poke the server who will hopefully poke us back"
|
||||||
;; json-false/json-nil are bound as nil here to stop them from being silly keywords
|
;; json-false/json-nil are bound as nil here to stop them from being silly keywords
|
||||||
(let (json message json-false json-null
|
(let (json message json-false json-null
|
||||||
(data (list
|
(data (list
|
||||||
(cons 'user bbj:user)
|
(cons 'user bbj-user)
|
||||||
(cons 'auth_hash bbj:hash)
|
(cons 'auth_hash bbj-hash)
|
||||||
(cons 'method method))))
|
(cons 'method method))))
|
||||||
;; populate a query with our hash and username, then the func arguments
|
;; populate a query with our hash and username, then the func arguments
|
||||||
(while pairs
|
(while pairs
|
||||||
|
@ -100,61 +100,61 @@ for all JSON tourists."
|
||||||
(call-process-region
|
(call-process-region
|
||||||
(point-min) (point-max)
|
(point-min) (point-max)
|
||||||
shell-file-name t t nil ;; meow meow
|
shell-file-name t t nil ;; meow meow
|
||||||
"-c" (format "nc %s %s" bbj:host bbj:port))
|
"-c" (format "nc %s %s" bbj-host bbj-port))
|
||||||
(setq json (progn (goto-char (point-min)) (json-read))))
|
(setq json (progn (goto-char (point-min)) (json-read))))
|
||||||
|
|
||||||
(if (eq json t) t ;; a few enpoints just return true/false
|
(if (eq json t) t ;; a few enpoints just return true/false
|
||||||
(setq message (bbj:descend json 'error 'description))
|
(setq message (bbj-descend json 'error 'description))
|
||||||
(case (bbj:descend json 'error 'code)
|
(case (bbj-descend json 'error 'code)
|
||||||
;; haha epic handling
|
;; haha epic handling
|
||||||
((4 5 6 7) (error message))
|
((4 5 6 7) (error message))
|
||||||
(otherwise json)))))
|
(otherwise json)))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:sethash (&optional password)
|
(defun bbj-sethash (&optional password)
|
||||||
"Either prompt for or take the arg `PASSWORD', and then sha256-hash it.
|
"Either prompt for or take the arg `PASSWORD', and then sha256-hash it.
|
||||||
Sets it globally and also returns it."
|
Sets it globally and also returns it."
|
||||||
(interactive)
|
(interactive)
|
||||||
(unless password (setq password
|
(unless password (setq password
|
||||||
(read-from-minibuffer "(Password)> ")))
|
(read-from-minibuffer "(Password)> ")))
|
||||||
(setq bbj:hash (secure-hash 'sha256 password)))
|
(setq bbj-hash (secure-hash 'sha256 password)))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:login ()
|
(defun bbj-login ()
|
||||||
"Prompts the user for a name and password. If it isn't registered, we'll take
|
"Prompts the user for a name and password. If it isn't registered, we'll take
|
||||||
care of that. Jumps to the index afterward. This function only needs to be used
|
care of that. Jumps to the index afterward. This function only needs to be used
|
||||||
once per emacs session."
|
once per emacs session."
|
||||||
(interactive)
|
(interactive)
|
||||||
(setq bbj:user (read-from-minibuffer "(BBJ Username)> "))
|
(setq bbj-user (read-from-minibuffer "(BBJ Username)> "))
|
||||||
(cond
|
(cond
|
||||||
((bbj:request "is_registered" 'target_user bbj:user)
|
((bbj-request "is_registered" 'target_user bbj-user)
|
||||||
(bbj:sethash)
|
(bbj-sethash)
|
||||||
(if (bbj:request "check_auth")
|
(if (bbj-request "check_auth")
|
||||||
(progn
|
(progn
|
||||||
(setq bbj:logged-in t)
|
(setq bbj-logged-in t)
|
||||||
(bbj:browse-index)
|
(bbj-browse-index)
|
||||||
(message "Logged in as %s!" bbj:user))
|
(message "Logged in as %s!" bbj-user))
|
||||||
(message "(Invalid Password!)")
|
(message "(Invalid Password!)")
|
||||||
(run-at-time 1 nil #'bbj:login)))
|
(run-at-time 1 nil #'bbj-login)))
|
||||||
((y-or-n-p (format "Register for BBJ as %s? " bbj:user))
|
((y-or-n-p (format "Register for BBJ as %s? " bbj-user))
|
||||||
(bbj:sethash)
|
(bbj-sethash)
|
||||||
(let ((response
|
(let ((response
|
||||||
(bbj:request "user_register"
|
(bbj-request "user_register"
|
||||||
;; need to add some cute prompts for these
|
;; need to add some cute prompts for these
|
||||||
'quip "" 'bio "")))
|
'quip "" 'bio "")))
|
||||||
(if (alist-get 'error response)
|
(if (alist-get 'error response)
|
||||||
(message "%s" (alist-get 'error response))
|
(message "%s" (alist-get 'error response))
|
||||||
(setq bbj:logged-in t)
|
(setq bbj-logged-in t)
|
||||||
(bbj:browse-index)
|
(bbj-browse-index)
|
||||||
(message "Logged in as %s!" bbj:user))))))
|
(message "Logged in as %s!" bbj-user))))))
|
||||||
|
|
||||||
|
|
||||||
;;;; user navigation shit. a LOT of user navigation shit. ;;;;
|
;;;; user navigation shit. a LOT of user navigation shit. ;;;;
|
||||||
(defun bbj:next-pos (string &optional regex prop backward group bound)
|
(defun bbj-next-pos (string &optional regex prop backward group bound)
|
||||||
;; haha yes i ripped this from one of my other projects
|
;; haha yes i ripped this from one of my other projects
|
||||||
"Takes a STRING and returns the char position of the beginning of its
|
"Takes a STRING and returns the char position of the beginning of its
|
||||||
next occurence from point in `current-buffer'. Returns nil if not found.
|
next occurence from point in `current-buffer'. Returns nil if not found.
|
||||||
A simpler way to call this is to use `bbj:next-prop'.
|
A simpler way to call this is to use `bbj-next-prop'.
|
||||||
|
|
||||||
When REGEX is non-nil, STRING is interpreted as a regular expression.
|
When REGEX is non-nil, STRING is interpreted as a regular expression.
|
||||||
|
|
||||||
|
@ -186,129 +186,129 @@ BOUND can be a buffer position (integer) that the search will not exceed."
|
||||||
(match-beginning group)))))
|
(match-beginning group)))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:next-prop (prop &optional backward bound)
|
(defun bbj-next-prop (prop &optional backward bound)
|
||||||
"Like the `bbj:next-pos', but doesnt care about strings and
|
"Like the `bbj-next-pos', but doesnt care about strings and
|
||||||
just hunts for a specific text property."
|
just hunts for a specific text property."
|
||||||
(bbj:next-pos "." t prop backward nil bound))
|
(bbj-next-pos "." t prop backward nil bound))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:post-prop (prop &optional id)
|
(defun bbj-post-prop (prop &optional id)
|
||||||
"retrieve PROP from the current post. needs ID-seeking support"
|
"retrieve PROP from the current post. needs ID-seeking support"
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(bbj:assert-post-start)
|
(bbj-assert-post-start)
|
||||||
(get-char-property (point) prop)))
|
(get-char-property (point) prop)))
|
||||||
|
|
||||||
|
|
||||||
;; returns positions of the next head and ending seps, respectively
|
;; returns positions of the next head and ending seps, respectively
|
||||||
(defun bbj:head-pos (&optional backward)
|
(defun bbj-head-pos (&optional backward)
|
||||||
(bbj:next-prop 'head backward))
|
(bbj-next-prop 'head backward))
|
||||||
(defun bbj:sep-pos (&optional backward)
|
(defun bbj-sep-pos (&optional backward)
|
||||||
(bbj:next-prop 'end backward))
|
(bbj-next-prop 'end backward))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:assert-post-start ()
|
(defun bbj-assert-post-start ()
|
||||||
(unless (eql 'head (get-char-property (point) 'type))
|
(unless (eql 'head (get-char-property (point) 'type))
|
||||||
(goto-char (bbj:head-pos t))))
|
(goto-char (bbj-head-pos t))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:point-to-post (dir &optional nocenter)
|
(defun bbj-point-to-post (dir &optional nocenter)
|
||||||
"Move the cursor from the head of one post to another, in (symbol) DIR"
|
"Move the cursor from the head of one post to another, in (symbol) DIR"
|
||||||
(let ((check (case dir
|
(let ((check (case dir
|
||||||
(prev (bbj:head-pos t))
|
(prev (bbj-head-pos t))
|
||||||
(next (save-excursion ;; or else point will stick
|
(next (save-excursion ;; or else point will stick
|
||||||
(while (eq 'head (get-char-property (point) 'type))
|
(while (eq 'head (get-char-property (point) 'type))
|
||||||
(goto-char (next-property-change (point))))
|
(goto-char (next-property-change (point))))
|
||||||
(bbj:head-pos))))))
|
(bbj-head-pos))))))
|
||||||
(when check
|
(when check
|
||||||
(goto-char check)
|
(goto-char check)
|
||||||
(back-to-indentation)
|
(back-to-indentation)
|
||||||
(unless nocenter (recenter 1)))))
|
(unless nocenter (recenter 1)))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:next-post ()
|
(defun bbj-next-post ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(bbj:point-to-post 'next))
|
(bbj-point-to-post 'next))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:prev-post ()
|
(defun bbj-prev-post ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(bbj:point-to-post 'prev))
|
(bbj-point-to-post 'prev))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:first-post ()
|
(defun bbj-first-post ()
|
||||||
;; does interactive work like this? i never checked tbh
|
;; does interactive work like this? i never checked tbh
|
||||||
(interactive (push-mark))
|
(interactive (push-mark))
|
||||||
(goto-char (+ 1 bbj:width (point-min))))
|
(goto-char (+ 1 bbj-width (point-min))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:aux ()
|
(defun bbj-aux ()
|
||||||
"just some random lazy callback shitty thing for C-c C-c"
|
"just some random lazy callback shitty thing for C-c C-c"
|
||||||
(interactive)
|
(interactive)
|
||||||
(funcall bbj:aux-callback))
|
(funcall bbj-aux-callback))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:enter ()
|
(defun bbj-enter ()
|
||||||
"Handles the RETURN key (and other similar binds) depending on
|
"Handles the RETURN key (and other similar binds) depending on
|
||||||
content type. Currently only opens threads."
|
content type. Currently only opens threads."
|
||||||
(interactive)
|
(interactive)
|
||||||
(case bbj:buffer-type
|
(case bbj-buffer-type
|
||||||
(index
|
(index
|
||||||
(bbj:enter-thread
|
(bbj-enter-thread
|
||||||
(alist-get 'thread_id (bbj:post-prop 'data))))))
|
(alist-get 'thread_id (bbj-post-prop 'data))))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:quote-current-post ()
|
(defun bbj-quote-current-post ()
|
||||||
"Pop a composer, and insert the post number at point as a quote."
|
"Pop a composer, and insert the post number at point as a quote."
|
||||||
(interactive)
|
(interactive)
|
||||||
(case bbj:buffer-type
|
(case bbj-buffer-type
|
||||||
(thread
|
(thread
|
||||||
(let ((id (alist-get 'post_id (bbj:post-prop 'data))))
|
(let ((id (alist-get 'post_id (bbj-post-prop 'data))))
|
||||||
(bbj:compose)
|
(bbj-compose)
|
||||||
(insert (format ">>%s\n\n" id))))
|
(insert (format ">>%s\n\n" id))))
|
||||||
(index
|
(index
|
||||||
;; recursion haha yes
|
;; recursion haha yes
|
||||||
(let ((buffer (current-buffer)))
|
(let ((buffer (current-buffer)))
|
||||||
(bbj:enter)
|
(bbj-enter)
|
||||||
(unless (equal buffer (current-buffer))
|
(unless (equal buffer (current-buffer))
|
||||||
(bbj:quote-current-post))))))
|
(bbj-quote-current-post))))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:compose ()
|
(defun bbj-compose ()
|
||||||
"Construct an appropriate callback to either create a thread or
|
"Construct an appropriate callback to either create a thread or
|
||||||
reply to one. Pops a new window; window is killed and the message
|
reply to one. Pops a new window; window is killed and the message
|
||||||
is sent using C-c C-c."
|
is sent using C-c C-c."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((params (case bbj:buffer-type
|
(let ((params (case bbj-buffer-type
|
||||||
(index
|
(index
|
||||||
`("Composing a new thread (C-c C-c to send)"
|
`("Composing a new thread (C-c C-c to send)"
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(let* ((message (bbj:consume-window (current-buffer)))
|
(let* ((message (bbj-consume-window (current-buffer)))
|
||||||
(request (bbj:request "thread_create"
|
(request (bbj-request "thread_create"
|
||||||
'body message
|
'body message
|
||||||
'title ,(read-from-minibuffer "(Thread Title)> ")
|
'title ,(read-from-minibuffer "(Thread Title)> ")
|
||||||
'tags ,(read-from-minibuffer "(Comma-seperated tags, if any)> "))))
|
'tags ,(read-from-minibuffer "(Comma-seperated tags, if any)> "))))
|
||||||
(if (numberp (bbj:descend request 'error 'code))
|
(if (numberp (bbj-descend request 'error 'code))
|
||||||
(message "%s" request)
|
(message "%s" request)
|
||||||
(message "thread submitted")
|
(message "thread submitted")
|
||||||
(bbj:browse-index))))))
|
(bbj-browse-index))))))
|
||||||
(thread
|
(thread
|
||||||
`("Replying to thread (C-c C-c to send)"
|
`("Replying to thread (C-c C-c to send)"
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(let* ((message (bbj:consume-window (current-buffer)))
|
(let* ((message (bbj-consume-window (current-buffer)))
|
||||||
(request (bbj:request "thread_reply"
|
(request (bbj-request "thread_reply"
|
||||||
'body message 'thread_id ,thread-id)))
|
'body message 'thread_id ,thread-id)))
|
||||||
(if (numberp (bbj:descend request 'error 'code))
|
(if (numberp (bbj-descend request 'error 'code))
|
||||||
(message "%s" request)
|
(message "%s" request)
|
||||||
(message "reply submitted")
|
(message "reply submitted")
|
||||||
(bbj:enter-thread ,thread-id)
|
(bbj-enter-thread ,thread-id)
|
||||||
(goto-char (point-max))
|
(goto-char (point-max))
|
||||||
(bbj:point-to-post 'prev)
|
(bbj-point-to-post 'prev)
|
||||||
(recenter nil)))))))))
|
(recenter nil)))))))))
|
||||||
|
|
||||||
(apply #'bbj:compose-in-window params)))
|
(apply #'bbj-compose-in-window params)))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:compose-in-window (title callback &rest cbargs)
|
(defun bbj-compose-in-window (title callback &rest cbargs)
|
||||||
"Create a new buffer, pop it, set TITLE as the header line, and
|
"Create a new buffer, pop it, set TITLE as the header line, and
|
||||||
assign CALLBACK to C-c C-c."
|
assign CALLBACK to C-c C-c."
|
||||||
(let ((buffer (get-buffer-create "*BBJ: Compose*")))
|
(let ((buffer (get-buffer-create "*BBJ: Compose*")))
|
||||||
|
@ -317,12 +317,12 @@ assign CALLBACK to C-c C-c."
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(text-mode)
|
(text-mode)
|
||||||
(use-local-map (copy-keymap text-mode-map))
|
(use-local-map (copy-keymap text-mode-map))
|
||||||
(local-set-key (kbd "C-c C-c") 'bbj:aux)
|
(local-set-key (kbd "C-c C-c") 'bbj-aux)
|
||||||
(setq header-line-format title
|
(setq header-line-format title
|
||||||
bbj:aux-callback callback))))
|
bbj-aux-callback callback))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:consume-window (buffer)
|
(defun bbj-consume-window (buffer)
|
||||||
"Consume all text in the current buffer, delete the window if
|
"Consume all text in the current buffer, delete the window if
|
||||||
it is one, and kill the buffer. Returns property-free string."
|
it is one, and kill the buffer. Returns property-free string."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -333,21 +333,21 @@ it is one, and kill the buffer. Returns property-free string."
|
||||||
content)))
|
content)))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:postprocess ()
|
(defun bbj-postprocess ()
|
||||||
"Makes all the whitespace in and between posts consistent."
|
"Makes all the whitespace in and between posts consistent."
|
||||||
(bbj:first-post)
|
(bbj-first-post)
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(while (re-search-forward "\n\n\n+" nil t)
|
(while (re-search-forward "\n\n\n+" nil t)
|
||||||
(replace-match "\n\n"))))
|
(replace-match "\n\n"))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:render-body (string &optional return-string notrim)
|
(defun bbj-render-body (string &optional return-string notrim)
|
||||||
"takes an html STRING. If RETURN-STRING is non nil, it renders
|
"takes an html STRING. If RETURN-STRING is non nil, it renders
|
||||||
it in a temp buffer and returns the string. Otherwise, inserts
|
it in a temp buffer and returns the string. Otherwise, inserts
|
||||||
and renders the content in the current buffer."
|
and renders the content in the current buffer."
|
||||||
(let* ((shr-width bbj:width)
|
(let* ((shr-width bbj-width)
|
||||||
(shr-external-rendering-functions
|
(shr-external-rendering-functions
|
||||||
'((span . bbj:render-tag-span)))
|
'((span . bbj-render-tag-span)))
|
||||||
result)
|
result)
|
||||||
(if (not return-string)
|
(if (not return-string)
|
||||||
(let ((start (point)))
|
(let ((start (point)))
|
||||||
|
@ -362,15 +362,15 @@ and renders the content in the current buffer."
|
||||||
(if notrim result (string-trim result)))))
|
(if notrim result (string-trim result)))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:timestring (epoch)
|
(defun bbj-timestring (epoch)
|
||||||
"Make a cute timestring out of the epoch (for post heads)"
|
"Make a cute timestring out of the epoch (for post heads)"
|
||||||
(format-time-string "%H:%M %a %m/%d/%y" (seconds-to-time epoch)))
|
(format-time-string "%H:%M %a %m/%d/%y" (seconds-to-time epoch)))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:render-post (object)
|
(defun bbj-render-post (object)
|
||||||
"Render an API object into the current buffer. Can be either the parent object
|
"Render an API object into the current buffer. Can be either the parent object
|
||||||
or any of its children."
|
or any of its children."
|
||||||
(let* ((userdata (cdr (assoc-string (alist-get 'author object) bbj:*usermap*)))
|
(let* ((userdata (cdr (assoc-string (alist-get 'author object) bbj-*usermap*)))
|
||||||
(title (alist-get 'title object))
|
(title (alist-get 'title object))
|
||||||
(indicator (format ">>%s " (or title (alist-get 'post_id object)))))
|
(indicator (format ">>%s " (or title (alist-get 'post_id object)))))
|
||||||
(insert (propertize indicator
|
(insert (propertize indicator
|
||||||
|
@ -380,22 +380,22 @@ or any of its children."
|
||||||
(insert (propertize
|
(insert (propertize
|
||||||
(concat "~" (alist-get 'name userdata) " ")
|
(concat "~" (alist-get 'name userdata) " ")
|
||||||
'face 'font-lock-keyword-face))
|
'face 'font-lock-keyword-face))
|
||||||
(insert (if (eq bbj:buffer-type 'index)
|
(insert (if (eq bbj-buffer-type 'index)
|
||||||
(propertize (format "@ %s\n%s replies; last active %s\n"
|
(propertize (format "@ %s\n%s replies; last active %s\n"
|
||||||
(bbj:timestring (alist-get 'created object))
|
(bbj-timestring (alist-get 'created object))
|
||||||
(alist-get 'reply_count object)
|
(alist-get 'reply_count object)
|
||||||
(bbj:timestring (alist-get 'lastmod object)))
|
(bbj-timestring (alist-get 'lastmod object)))
|
||||||
'face 'font-lock-comment-face)
|
'face 'font-lock-comment-face)
|
||||||
(propertize (format "@ %s\n\n" (bbj:timestring (alist-get 'created object)))
|
(propertize (format "@ %s\n\n" (bbj-timestring (alist-get 'created object)))
|
||||||
'face 'font-lock-comment-face)))
|
'face 'font-lock-comment-face)))
|
||||||
(when (eq bbj:buffer-type 'thread)
|
(when (eq bbj-buffer-type 'thread)
|
||||||
(bbj:render-body (alist-get 'body object)))
|
(bbj-render-body (alist-get 'body object)))
|
||||||
(bbj:insert-sep)))
|
(bbj-insert-sep)))
|
||||||
|
|
||||||
|
|
||||||
;; (defun bbj:render-tag-span (dom)
|
;; (defun bbj-render-tag-span (dom)
|
||||||
;; "A slightly modified version of `shr-tag-span' which handles quotes and stuff."
|
;; "A slightly modified version of `shr-tag-span' which handles quotes and stuff."
|
||||||
;; (let ((class (if bbj:old-p
|
;; (let ((class (if bbj-old-p
|
||||||
;; (assq :class (cdr dom))
|
;; (assq :class (cdr dom))
|
||||||
;; (dom-attr dom 'class))))
|
;; (dom-attr dom 'class))))
|
||||||
;; (dolist (sub (if (consp (car dom)) (cddr (car dom)) (cddr dom)))
|
;; (dolist (sub (if (consp (car dom)) (cddr (car dom)) (cddr dom)))
|
||||||
|
@ -412,12 +412,13 @@ or any of its children."
|
||||||
;; (t (shr-insert sub)))
|
;; (t (shr-insert sub)))
|
||||||
;; (shr-descend sub)))))
|
;; (shr-descend sub)))))
|
||||||
|
|
||||||
(defun bbj:render-tag-span (dom)
|
(defun bbj-render-tag-span (dom)
|
||||||
"A slightly modified version of `shr-tag-span' which handles quotes and stuff."
|
"A highly bastardized version of `shr-tag-span', beaten and maimed until
|
||||||
(let ((class (if bbj:old-p
|
it worked on emacs 24."
|
||||||
|
(let ((class (if bbj-old-p
|
||||||
(alist-get :class dom)
|
(alist-get :class dom)
|
||||||
(dom-attr dom 'class)))
|
(dom-attr dom 'class)))
|
||||||
(text (if bbj:old-p
|
(text (if bbj-old-p
|
||||||
(alist-get 'text dom)
|
(alist-get 'text dom)
|
||||||
(car (last dom)))))
|
(car (last dom)))))
|
||||||
(cond
|
(cond
|
||||||
|
@ -433,52 +434,52 @@ or any of its children."
|
||||||
(text (shr-insert text)))))
|
(text (shr-insert text)))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:mksep ()
|
(defun bbj-mksep ()
|
||||||
(format "\n%s\n" (make-string bbj:width ?\-)))
|
(format "\n%s\n" (make-string bbj-width ?\-)))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:insert-sep (&optional drop-newline)
|
(defun bbj-insert-sep (&optional drop-newline)
|
||||||
(let ((sep (bbj:mksep)))
|
(let ((sep (bbj-mksep)))
|
||||||
(insert (propertize
|
(insert (propertize
|
||||||
(if drop-newline (subseq sep 1) sep)
|
(if drop-newline (subseq sep 1) sep)
|
||||||
'face 'font-lock-comment-face
|
'face 'font-lock-comment-face
|
||||||
'type 'end))))
|
'type 'end))))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:browse-index ()
|
(defun bbj-browse-index ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((inhibit-read-only t)
|
(let* ((inhibit-read-only t)
|
||||||
(buffer (get-buffer-create "*BBJ Index*"))
|
(buffer (get-buffer-create "*BBJ Index*"))
|
||||||
(response (bbj:request "thread_index"))
|
(response (bbj-request "thread_index"))
|
||||||
(bbj:*usermap* (alist-get 'usermap response)))
|
(bbj-*usermap* (alist-get 'usermap response)))
|
||||||
(with-current-buffer buffer
|
(with-current-buffer buffer
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(bbj-mode)
|
(bbj-mode)
|
||||||
(setq bbj:buffer-type 'index
|
(setq bbj-buffer-type 'index
|
||||||
bbj:*usermap* (alist-get 'usermap response))
|
bbj-*usermap* (alist-get 'usermap response))
|
||||||
(bbj:insert-sep t)
|
(bbj-insert-sep t)
|
||||||
(loop for thread across (alist-get 'threads response) do
|
(loop for thread across (alist-get 'threads response) do
|
||||||
(bbj:render-post thread))
|
(bbj-render-post thread))
|
||||||
(bbj:postprocess))
|
(bbj-postprocess))
|
||||||
(switch-to-buffer buffer)
|
(switch-to-buffer buffer)
|
||||||
(setq buffer-read-only t)))
|
(setq buffer-read-only t)))
|
||||||
|
|
||||||
|
|
||||||
(defun bbj:enter-thread (id)
|
(defun bbj-enter-thread (id)
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((inhibit-read-only t)
|
(let* ((inhibit-read-only t)
|
||||||
(response (bbj:request "thread_load" 'thread_id id))
|
(response (bbj-request "thread_load" 'thread_id id))
|
||||||
(buffer (get-buffer-create (format "BBJ: %s" (alist-get 'title response)))))
|
(buffer (get-buffer-create (format "BBJ: %s" (alist-get 'title response)))))
|
||||||
(with-current-buffer buffer
|
(with-current-buffer buffer
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(bbj-mode)
|
(bbj-mode)
|
||||||
(setq bbj:buffer-type 'thread
|
(setq bbj-buffer-type 'thread
|
||||||
bbj:*usermap* (alist-get 'usermap response))
|
bbj-*usermap* (alist-get 'usermap response))
|
||||||
(setq-local thread-id id)
|
(setq-local thread-id id)
|
||||||
(bbj:insert-sep t)
|
(bbj-insert-sep t)
|
||||||
(bbj:render-post response)
|
(bbj-render-post response)
|
||||||
(loop for reply across (alist-get 'replies response) do
|
(loop for reply across (alist-get 'replies response) do
|
||||||
(bbj:render-post reply))
|
(bbj-render-post reply))
|
||||||
(bbj:postprocess))
|
(bbj-postprocess))
|
||||||
(switch-to-buffer buffer)
|
(switch-to-buffer buffer)
|
||||||
(setq buffer-read-only t)))
|
(setq buffer-read-only t)))
|
||||||
|
|
Loading…
Reference in New Issue