From ade5fe434b5fd031db8cd4e601f26f2933354ab2 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Thu, 12 Feb 2015 14:18:55 -0200 Subject: Compiler warnings --- sx.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sx.el') diff --git a/sx.el b/sx.el index 33b36b6..73d874f 100644 --- a/sx.el +++ b/sx.el @@ -204,7 +204,7 @@ is intentionally skipped." (while (and ;; We're not at the end. (cdr-safe tail) ;; We're not at the right place. - (,(or predicate #'<) x (cadr tail))) + (funcall (or ,predicate #'<) x (cadr tail))) (setq tail (cdr tail))) (setcdr tail (cons x (cdr tail))))) -- cgit v1.2.3 From 85109b7dd2ffb896151ccef2c014c7d9ea33e682 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Thu, 12 Feb 2015 14:59:46 -0200 Subject: Define possible values for answer sorting --- sx-question-print.el | 19 +++++++++++++++---- sx.el | 6 ++++++ 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'sx.el') diff --git a/sx-question-print.el b/sx-question-print.el index 778b580..4f50560 100644 --- a/sx-question-print.el +++ b/sx-question-print.el @@ -153,13 +153,24 @@ replaced with the comment." :type 'boolean :group 'sx-question-mode) +(defconst sx-question-mode--sort-methods + (let ((methods + '(("Higher-scoring" . sx-answer-higher-score-p) + ("Newer" . sx-answer-newer-p) + ("More active" . sx-answer-more-active-p)))) + (append (mapcar (lambda (x) (cons (concat (car x) " first") (cdr x))) + methods) + (mapcar (lambda (x) (cons (concat (car x) " last") + (sx--invert-predicate (cdr x)))) + methods)))) + (defcustom sx-question-mode-answer-sort-function #'sx-answer-higher-score-p "Function used to sort answers in the question buffer." - :type '(choice - (const :tag "Higher-scoring first" sx-answer-higher-score-p) - (const :tag "Newer first" sx-answer-newer-p) - (const :tag "More active first" sx-answer-more-active-p)) + :type + (cons 'choice + (mapcar (lambda (x) `(const :tag ,(car x) ,(cdr x))) + sx-question-mode--sort-methods)) :group 'sx-question-mode) diff --git a/sx.el b/sx.el index 33b36b6..381f78e 100644 --- a/sx.el +++ b/sx.el @@ -335,6 +335,12 @@ GET-FUNC and performs the actual comparison." "Return STRING with consecutive whitespace squashed together." (replace-regexp-in-string "[ \r\n]+" " " string)) +(defun sx--invert-predicate (predicate) + "Return PREDICATE function with arguments inverted. +For instance (sx--invert-predicate #'<) is the same as #'>. +Note this is not the same as negating PREDICATE." + (lambda (&rest args) (apply predicate (reverse args)))) + ;;; Printing request data (defvar sx--overlays nil -- 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.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 0b8a09dadb3f90303e7c77ac0e644bc393c00700 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 21 Feb 2015 15:29:53 -0200 Subject: Don't print deleted posts. --- sx-interaction.el | 6 +++++- sx-question-print.el | 55 +++++++++++++++++++++++++++++----------------------- sx.el | 4 ++++ 3 files changed, 40 insertions(+), 25 deletions(-) (limited to 'sx.el') diff --git a/sx-interaction.el b/sx-interaction.el index 8eae96f..d2129f8 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -278,7 +278,11 @@ guessed from context at point. With UNDO prefix argument, undelete instead." (interactive (list (sx--error-if-unread (sx--data-here)) current-prefix-arg)) - (sx-method-post-from-data data (if undo 'delete/undo 'delete))) + (sx-method-post-from-data data (if undo 'delete/undo 'delete)) + ;; Indicate to ourselves this has been deleted. + (setcdr data (cons (car data) (cdr data))) + (setcar data 'deleted) + (sx--maybe-update-display)) ;;; Commenting diff --git a/sx-question-print.el b/sx-question-print.el index abf3236..39aad20 100644 --- a/sx-question-print.el +++ b/sx-question-print.el @@ -163,6 +163,8 @@ replaced with the comment." (defun sx-question-mode--print-question (question) "Print a buffer describing QUESTION. QUESTION must be a data structure returned by `json-read'." + (when (sx--deleted-p question) + (sx-user-error "This is a deleted question")) (setq sx-question-mode--data question) ;; Clear the overlays (mapc #'delete-overlay sx--overlays) @@ -171,7 +173,9 @@ QUESTION must be a data structure returned by `json-read'." (sx-question-mode--print-section question) (sx-assoc-let question (mapc #'sx-question-mode--print-section - (cl-sort .answers sx-question-mode-answer-sort-function))) + (cl-remove-if + #'sx--deleted-p + (cl-sort .answers sx-question-mode-answer-sort-function)))) (insert "\n\n ") (insert-text-button "Write an Answer" :type 'sx-button-answer) ;; Go up @@ -182,9 +186,9 @@ QUESTION must be a data structure returned by `json-read'." "Print a section corresponding to DATA. DATA can represent a question or an answer." ;; This makes `data' accessible through `sx--data-here'. - (sx-assoc-let data - (sx--wrap-in-overlay - (list 'sx--data-here data) + (sx--wrap-in-overlay + (list 'sx--data-here data) + (sx-assoc-let data (insert sx-question-mode-header-title) (insert-text-button ;; Questions have title, Answers don't @@ -237,29 +241,32 @@ DATA can represent a question or an answer." "\n" (propertize sx-question-mode-separator 'face 'sx-question-mode-header))) - ;; Comments have their own `sx--data-here' property (so they can - ;; be upvoted too). - (when .comments - (insert "\n") - (insert-text-button - sx-question-mode-comments-title - 'face 'sx-question-mode-title-comments - 'sx-question-mode--section 3 - 'sx-button-copy .share_link - :type 'sx-question-mode-title) - (sx--wrap-in-overlay - '(sx-question-mode--section-content t) + ;; Clean up commments manually deleted. The `append' call is + ;; to ensure `comments' is a list and not a vector. + (let ((comments (cl-remove-if #'sx--deleted-p (append .comments nil)))) + (when comments (insert "\n") + (insert-text-button + sx-question-mode-comments-title + 'face 'sx-question-mode-title-comments + 'sx-question-mode--section 3 + 'sx-button-copy .share_link + :type 'sx-question-mode-title) (sx--wrap-in-overlay - '(face sx-question-mode-content-face) - (mapc #'sx-question-mode--print-comment .comments)) - ;; If there are comments, we want part of this margin to go - ;; inside them, so the button get's placed beside the - ;; "Comments" header when you hide them. + '(sx-question-mode--section-content t) + (insert "\n") + (sx--wrap-in-overlay + '(face sx-question-mode-content-face) + ;; Comments have their own `sx--data-here' property (so they can + ;; be upvoted too). + (mapc #'sx-question-mode--print-comment comments)) + ;; If there are comments, we want part of this margin to go + ;; inside them, so the button get's placed beside the + ;; "Comments" header when you hide them. + (insert " "))) + ;; If there are no comments, we have to add this margin here. + (unless comments (insert " "))) - ;; If there are no comments, we have to add this margin here. - (unless .comments - (insert " ")) (insert " ") ;; This is where the "add a comment" button is printed. (insert-text-button "Add a Comment" diff --git a/sx.el b/sx.el index 33b36b6..9ad9744 100644 --- a/sx.el +++ b/sx.el @@ -335,6 +335,10 @@ GET-FUNC and performs the actual comparison." "Return STRING with consecutive whitespace squashed together." (replace-regexp-in-string "[ \r\n]+" " " string)) +(defun sx--deleted-p (data) + "Return non-nil if DATA represents a deleted object." + (eq (car data) 'deleted)) + ;;; Printing request data (defvar sx--overlays nil -- cgit v1.2.3 From fcd6d94743a59cd51f7ac1fbed8eaba87ed2e5b6 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 21 Feb 2015 17:28:44 -0200 Subject: Define sx--key-definitions-to-header-line --- sx.el | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'sx.el') diff --git a/sx.el b/sx.el index 33b36b6..0ea8e4d 100644 --- a/sx.el +++ b/sx.el @@ -418,6 +418,39 @@ if ALIST contains a different string at the ?% entry." (delete-char 1))) (buffer-string)))) + +;;; Key definitions +(defun sx--key-definitions-to-header-line (definitions) + "Return a `header-line-format' from DEFINITIONS. +DEFINITIONS is a list where each element has one of the following two forms + (KEY COMMAND) + (KEY COMMAND DESCRIPTION) + +The latter are used to build the return value, the former are +ignored." + (let ((ptize (lambda (x) `(:propertize ,x face mode-line-buffer-id))) + alist out) + (dolist (it definitions) + (when (> (length it) 2) + (let* ((key (car it)) + (desc (elt it 2)) + (cell (assoc desc alist))) + (if cell (push key (cdr cell)) + (push (cons desc (list key)) alist))))) + (dolist (it alist out) + (let ((desc (car it)) + (keys (cdr it))) + (push (list " " + (cons (funcall ptize (car keys)) + (mapcar (lambda (k) `("," ,(funcall ptize k))) (cdr keys))) + (let ((match + (and (= 1 (length keys)) + (string-match (regexp-quote (car keys)) desc)))) + (if (and (numberp match) (= 0 match)) + (substring desc (length (car keys))) + (concat ":" desc)))) + out))))) + (defcustom sx-init-hook nil "Hook run when SX initializes. -- cgit v1.2.3 From 24090d48422233b31f9eef041814e99c47c2534d Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Thu, 26 Feb 2015 11:28:48 -0300 Subject: Manually string-trim for older emacsen. Fix #267 --- sx-compose.el | 6 ++---- sx.el | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'sx.el') diff --git a/sx-compose.el b/sx-compose.el index eb5e2eb..ae13fb6 100644 --- a/sx-compose.el +++ b/sx-compose.el @@ -193,8 +193,7 @@ tags. Return a list of already inserted tags." 'noerror) (error "No Tags header found")) (save-match-data - (split-string (match-string 1) (rx (any space ",;")) - 'omit-nulls (rx space)))) + (sx--split-string (match-string 1) (rx (any space ",;"))))) (defun sx-compose--check-tags () "Check if tags in current compose buffer are valid." @@ -313,8 +312,7 @@ other keywords are read from the header " (unless (search-forward-regexp "^Tags : *\\([^[:space:]].*\\) *$" header-end 'noerror) (error "No Tags header found")) - (push (cons 'tags (split-string (match-string 1) - "[[:space:],;]" 'omit-nulls)) + (push (cons 'tags (sx--split-string (match-string 1) "[[:space:],;]")) keywords) ;; And erase the header so it doesn't get sent. (delete-region diff --git a/sx.el b/sx.el index 33b36b6..ee7f0a6 100644 --- a/sx.el +++ b/sx.el @@ -189,6 +189,11 @@ If ALIST doesn't have a `site' property, one is created using the ;;; Utility Functions +(defun sx--split-string (string &optional separators) + "Split STRING into substrings bounded by matches for SEPARATORS." + (mapcar (lambda (s) (replace-regexp-in-string "\\` +\\| +\\'" "" s)) + (split-string string separators 'omit-nulls))) + (defun sx-completing-read (&rest args) "Like `completing-read', but possibly use ido. All ARGS are passed to `completing-read' or `ido-completing-read'." -- cgit v1.2.3