From fe7e31a55cdd9c25f3d0c1fba088d5499a887af9 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Thu, 12 Feb 2015 15:00:05 -0200 Subject: Sort answers with O --- sx-question-mode.el | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sx-question-mode.el') diff --git a/sx-question-mode.el b/sx-question-mode.el index 6125416..846ad7f 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -214,6 +214,7 @@ Letters do not insert themselves; instead, they are commands. ("v" sx-visit-externally) ("u" sx-upvote) ("d" sx-downvote) + ("O" sx-question-mode-order-by) ("q" quit-window) (" " scroll-up-command) ("a" sx-answer) @@ -256,6 +257,18 @@ query the api." (unless (derived-mode-p 'sx-question-mode) (error "Not in `sx-question-mode'"))) +(defun sx-question-mode-order-by (sort) + "Order answers in the current buffer by the method SORT. +Sets `sx-question-list--order' and then calls +`sx-question-list-refresh' with `redisplay'." + (interactive + (list (let ((order (sx-completing-read "Order answers by: " + (mapcar #'car sx-question-mode--sort-methods)))) + (cdr-safe (assoc-string order sx-question-mode--sort-methods))))) + (when (and sort (functionp sort)) + (setq sx-question-mode-answer-sort-function sort) + (sx-question-mode-refresh 'no-update))) + (provide 'sx-question-mode) ;;; sx-question-mode.el ends here -- cgit v1.2.3 From 25f8929c91050332f972dca42862e65bc22608b3 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Thu, 12 Feb 2015 20:32:39 -0200 Subject: Refactor fill-and-fontify to sx-question-mode--insert-markdown --- sx-question-mode.el | 2 +- sx-question-print.el | 94 +++++++++++++++++++++++++++++++--------------------- 2 files changed, 57 insertions(+), 39 deletions(-) (limited to 'sx-question-mode.el') diff --git a/sx-question-mode.el b/sx-question-mode.el index 6125416..44e96a5 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -195,7 +195,7 @@ Letters do not insert themselves; instead, they are commands. (set-window-parameter nil 'quit-restore `(other window nil ,(current-buffer)))) - ;; We call font-lock-region manually. See `sx-question-mode--fill-and-fontify' + ;; We call font-lock-region manually. See `sx-question-mode--insert-markdown'. (font-lock-mode -1) (remove-hook 'after-change-functions 'markdown-check-change-for-wiki-link t) (remove-hook 'window-configuration-change-hook diff --git a/sx-question-print.el b/sx-question-print.el index e21c998..e47bc3a 100644 --- a/sx-question-print.el +++ b/sx-question-print.el @@ -246,10 +246,9 @@ DATA can represent a question or an answer." 'face 'sx-question-mode-header)) (sx--wrap-in-overlay '(face sx-question-mode-content-face) + (insert "\n") + (sx-question-mode--insert-markdown .body_markdown) (insert "\n" - (sx-question-mode--fill-and-fontify - .body_markdown) - "\n" (propertize sx-question-mode-separator 'face 'sx-question-mode-header))) ;; Comments have their own `sx--data-here' property (so they can @@ -296,10 +295,13 @@ The comment is indented, filled, and then printed according to (format sx-question-mode-comments-format (sx-user--format "%d" .owner) (substring - ;; We fill with three spaces at the start, so the comment is - ;; slightly indented. - (sx-question-mode--fill-and-fontify - (concat " " .body_markdown)) + ;; We use temp buffer, so that image overlays don't get + ;; inserted with the comment. + (with-temp-buffer + ;; We fill with three spaces at the start, so the comment is + ;; slightly indented. + (sx-question-mode--insert-markdown (concat " " .body_markdown)) + (buffer-string)) ;; Then we remove the spaces from the first line, since we'll ;; add the username there anyway. 3)))))) @@ -345,37 +347,53 @@ E.g.: (>= 2 (any lower numeric "/._%&#?=;")))))) "Regexp matching markdown links.") -(defun sx-question-mode--fill-and-fontify (text) - "Return TEXT filled according to `markdown-mode'." - (with-temp-buffer - (insert text) - (delay-mode-hooks (markdown-mode)) - (font-lock-mode -1) - (when sx-question-mode-bullet-appearance - (font-lock-add-keywords ;; Bullet items. - nil - `((,(rx line-start (0+ blank) (group-n 1 (any "*+-")) blank) - 1 '(face nil display ,sx-question-mode-bullet-appearance) prepend)))) - (font-lock-add-keywords ;; Highlight usernames. - nil - `((,(rx (or blank line-start) - (group-n 1 (and "@" (1+ (not space)))) - symbol-end) - 1 font-lock-builtin-face))) - ;; Everything. - (font-lock-fontify-region (point-min) (point-max)) - ;; Compact links. - (sx-question-mode--process-links-in-buffer) - ;; And now the filling - (goto-char (point-min)) - (while (null (eobp)) - ;; Don't fill pre blocks. - (unless (sx-question-mode--dont-fill-here) - (let ((beg (point))) - (skip-chars-forward "\r\n[:blank:]") - (forward-paragraph) - (fill-region beg (point))))) - (replace-regexp-in-string "[[:blank:]]+\\'" "" (buffer-string)))) +(defun sx-question-mode--process-markdown-in-region (beg end) + "Process Markdown text between BEG and END. +This does not do Markdown font-locking. Instead, it fills text, +propertizes links, inserts images, cleans up html comments, and +font-locks code-blocks according to mode." + (save-restriction + (save-excursion + (narrow-to-region beg end) + ;; Compact links. + (sx-question-mode--process-links-in-buffer) + ;; And now the filling and other handlings. + (goto-char (point-min)) + (while (null (eobp)) + ;; Don't fill pre blocks. + (unless (sx-question-mode--dont-fill-here) + (let ((beg (point))) + (skip-chars-forward "\r\n[:blank:]") + (forward-paragraph) + (fill-region beg (point)))))))) + +(defun sx-question-mode--insert-markdown (text) + "Return TEXT fontified according to `markdown-mode'." + (let ((beg (point))) + (insert + ;; Font-locking needs to be done in a temp buffer, because it + ;; affects the entire buffer even if we narrow. + (with-temp-buffer + (insert text) + (delay-mode-hooks (markdown-mode)) + (font-lock-mode -1) + (when sx-question-mode-bullet-appearance + (font-lock-add-keywords ;; Bullet items. + nil + `((,(rx line-start (0+ blank) (group-n 1 (any "*+-")) blank) + 1 '(face nil display ,sx-question-mode-bullet-appearance) prepend)))) + (font-lock-add-keywords ;; Highlight usernames. + nil + `((,(rx (or blank line-start) + (group-n 1 (and "@" (1+ (not space)))) + symbol-end) + 1 font-lock-builtin-face))) + ;; Everything. + (font-lock-fontify-region (point-min) (point-max)) + (replace-regexp-in-string "[[:blank:]]+\\'" "" (buffer-string)))) + ;; This part can and should be done in place, this way it can + ;; create overlays. + (sx-question-mode--process-markdown-in-region beg (point)))) ;;; Handling links -- cgit v1.2.3 From 755322c4ba96c6ce5a836cfa601da993f8031ac1 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 21 Feb 2015 10:43:00 -0200 Subject: Configure question-mode mode-line --- sx-question-mode.el | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'sx-question-mode.el') diff --git a/sx-question-mode.el b/sx-question-mode.el index 6125416..2d06e5b 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -69,6 +69,7 @@ Returns the question buffer." (defun sx-question-mode--erase-and-print-question (data) "Erase contents of buffer and print question given by DATA. Also marks the question as read with `sx-question--mark-read'." + (sx--ensure-site data) (sx-question--mark-read data) (let ((inhibit-read-only t)) (erase-buffer) @@ -183,6 +184,34 @@ property." ": Quit") "Header-line used on the question list.") +(defconst sx-question-mode--mode-line + '(" " + ;; `sx-question-mode--data' is guaranteed to have through + ;; `sx--ensure-site' already, so we use `let-alist' instead of + ;; `sx-assoc-let' to improve performance (since the mode-line is + ;; updated a lot). + (:propertize + (:eval (let-alist sx-question-mode--data .site_par)) + face mode-line-buffer-id) + " " mode-name + " [" + "Answers: " + (:propertize + (:eval (number-to-string (let-alist sx-question-mode--data .answer_count))) + face mode-line-buffer-id) + ", " + "Stars: " + (:propertize + (:eval (number-to-string (or (let-alist sx-question-mode--data .favorite_count) 0))) + face mode-line-buffer-id) + ", " + "Views: " + (:propertize + (:eval (number-to-string (let-alist sx-question-mode--data .view_count))) + face mode-line-buffer-id) + "] ") + "Mode-line construct to use in `sx-question-mode' buffers.") + (define-derived-mode sx-question-mode special-mode "Question" "Major mode to display and navigate a question and its answers. Letters do not insert themselves; instead, they are commands. @@ -190,6 +219,7 @@ Letters do not insert themselves; instead, they are commands. \\ \\{sx-question-mode}" (setq header-line-format sx-question-mode--header-line) + (setq header-line-format sx-question-mode--mode-line) ;; Determine how to close this window. (unless (window-parameter nil 'quit-restore) (set-window-parameter -- cgit v1.2.3 From d73ba0621e1e73df155a09126ecef8df8c2d232a Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 21 Feb 2015 10:48:28 -0200 Subject: Standardize prettification of site names. --- sx-question-list.el | 4 +--- sx-question-mode.el | 9 +++++++-- sx.el | 6 ++++++ 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'sx-question-mode.el') diff --git a/sx-question-list.el b/sx-question-list.el index def490b..32bc140 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -397,9 +397,7 @@ Non-interactively, DATA is a question alist." (defconst sx-question-list--mode-line-format '(" " (:propertize - (:eval (mapconcat #'capitalize - (split-string sx-question-list--site "\\.") - " ")) + (:eval (sx--pretty-site-parameter sx-question-list--site)) face mode-line-buffer-id) " " mode-name ": " (:propertize sx-question-list--current-tab diff --git a/sx-question-mode.el b/sx-question-mode.el index 2d06e5b..d4b7f8d 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -191,7 +191,8 @@ property." ;; `sx-assoc-let' to improve performance (since the mode-line is ;; updated a lot). (:propertize - (:eval (let-alist sx-question-mode--data .site_par)) + (:eval (sx--pretty-site-parameter + (let-alist sx-question-mode--data .site_par))) face mode-line-buffer-id) " " mode-name " [" @@ -216,10 +217,14 @@ property." "Major mode to display and navigate a question and its answers. Letters do not insert themselves; instead, they are commands. +Don't activate this mode directly. Instead, to print a question +on the current buffer use +`sx-question-mode--erase-and-print-question'. + \\ \\{sx-question-mode}" (setq header-line-format sx-question-mode--header-line) - (setq header-line-format sx-question-mode--mode-line) + (setq mode-line-format sx-question-mode--mode-line) ;; Determine how to close this window. (unless (window-parameter nil 'quit-restore) (set-window-parameter diff --git a/sx.el b/sx.el index 73d874f..fc0af92 100644 --- a/sx.el +++ b/sx.el @@ -187,6 +187,12 @@ If ALIST doesn't have a `site' property, one is created using the ,(macroexpand `(let-alist ,alist ,@body)))) +(defun sx--pretty-site-parameter (site) + "Returned a pretty and capitalized version of string SITE." + (mapconcat #'capitalize + (split-string site "\\.") + " ")) + ;;; Utility Functions (defun sx-completing-read (&rest args) -- cgit v1.2.3 From 83538b215f75256b86987b999504a2d87d0db307 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 21 Feb 2015 16:23:37 -0200 Subject: Make question-mode--data buffer local --- sx-question-mode.el | 1 + 1 file changed, 1 insertion(+) (limited to 'sx-question-mode.el') diff --git a/sx-question-mode.el b/sx-question-mode.el index d4b7f8d..6d62e80 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -48,6 +48,7 @@ Common values for this variable are `pop-to-buffer' and `switch-to-buffer'." (defvar sx-question-mode--data nil "The data of the question being displayed.") +(make-variable-buffer-local 'sx-question-mode--data) (defun sx-question-mode--get-window () "Return a window displaying a question, or nil." -- cgit v1.2.3 From 435a7d910ea930aa9055b9e91c121cc339f0e980 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 21 Feb 2015 17:29:51 -0200 Subject: Define and use sx-question-mode--key-definitions --- sx-question-mode.el | 80 +++++++++++++++++++++++------------------------------ 1 file changed, 35 insertions(+), 45 deletions(-) (limited to 'sx-question-mode.el') diff --git a/sx-question-mode.el b/sx-question-mode.el index 6125416..dd231bc 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -161,28 +161,40 @@ property." pos 'sx-question-mode--section-content nil))) -;;; Major-mode +;;; Major-mode constants +(defconst sx-question-mode--key-definitions + '( + ("" sx-question-mode-next-section) + ("" sx-question-mode-previous-section) + ("n" sx-question-mode-next-section "Navigate") + ("p" sx-question-mode-previous-section "Navigate") + ("g" sx-question-mode-refresh) + ("v" sx-visit-externally) + ("u" sx-upvote "upvote") + ("d" sx-downvote "downvote") + ("q" quit-window) + ("SPC" scroll-up-command) + ("c" sx-comment "comment") + ("a" sx-answer "answer") + ("e" sx-edit "edit") + ("S" sx-search "Search") + ("s" sx-switchto-map "switch-to") + ("*" sx-favorite "star") + ("TAB" forward-button "Navigate") + ("" backward-button) + ("" backward-button) + ("" backward-button)) + "List of key definitions for `sx-question-mode'. +This list must follow the form described in +`sx--key-definitions-to-header-line'.") + (defconst sx-question-mode--header-line - '(" " - (:propertize "n p TAB" face mode-line-buffer-id) - ": Navigate" - " " - (:propertize "u d" face mode-line-buffer-id) - ": Up/Down Vote" - " " - (:propertize "c" face mode-line-buffer-id) - ": Comment" - " " - (:propertize "a" face mode-line-buffer-id) - ": Answer" - " " - (:propertize "e" face mode-line-buffer-id) - ": Edit" - " " - (:propertize "q" face mode-line-buffer-id) - ": Quit") + (sx--key-definitions-to-header-line + sx-question-mode--key-definitions) "Header-line used on the question list.") + +;;; Major-mode definition (define-derived-mode sx-question-mode special-mode "Question" "Major mode to display and navigate a question and its answers. Letters do not insert themselves; instead, they are commands. @@ -201,32 +213,10 @@ Letters do not insert themselves; instead, they are commands. (remove-hook 'window-configuration-change-hook 'markdown-fontify-buffer-wiki-links t)) -(mapc - (lambda (x) (define-key sx-question-mode-map - (car x) (cadr x))) - `( - ([down] sx-question-mode-next-section) - ([up] sx-question-mode-previous-section) - ("n" sx-question-mode-next-section) - ("p" sx-question-mode-previous-section) - ("g" sx-question-mode-refresh) - ("c" sx-comment) - ("v" sx-visit-externally) - ("u" sx-upvote) - ("d" sx-downvote) - ("q" quit-window) - (" " scroll-up-command) - ("a" sx-answer) - ("e" sx-edit) - ("S" sx-search) - ("s" sx-switchto-map) - ("*" sx-favorite) - (,(kbd "S-SPC") scroll-down-command) - ([backspace] scroll-down-command) - ([tab] forward-button) - (,(kbd "") backward-button) - (,(kbd "") backward-button) - (,(kbd "") backward-button))) +;; We need this quote+eval combo because `kbd' was a macro in 24.2. +(mapc (lambda (x) (eval `(define-key sx-question-mode-map + (kbd ,(car x)) #',(cadr x)))) + sx-question-mode--key-definitions) (defun sx-question-mode-refresh (&optional no-update) "Refresh currently displayed question. -- cgit v1.2.3 From d13f4115beeda50a598f2161100a16fa21455e62 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 21 Feb 2015 18:23:03 -0200 Subject: Bind delete to K --- sx-question-mode.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sx-question-mode.el') diff --git a/sx-question-mode.el b/sx-question-mode.el index dd231bc..fd7f026 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -177,9 +177,10 @@ property." ("c" sx-comment "comment") ("a" sx-answer "answer") ("e" sx-edit "edit") - ("S" sx-search "Search") - ("s" sx-switchto-map "switch-to") + ("S" sx-search) ("*" sx-favorite "star") + ("K" sx-delete "Delete") + ("s" sx-switchto-map "switch-to") ("TAB" forward-button "Navigate") ("" backward-button) ("" backward-button) -- cgit v1.2.3