diff options
-rw-r--r-- | sx-babel.el | 2 | ||||
-rw-r--r-- | sx-button.el | 31 | ||||
-rw-r--r-- | sx-filter.el | 4 | ||||
-rw-r--r-- | sx-interaction.el | 21 | ||||
-rw-r--r-- | sx-question-list.el | 21 | ||||
-rw-r--r-- | sx-question-print.el | 51 | ||||
-rw-r--r-- | sx-question.el | 2 | ||||
-rw-r--r-- | sx-search.el | 2 | ||||
-rw-r--r-- | sx-switchto.el | 2 | ||||
-rw-r--r-- | sx-user.el | 203 | ||||
-rw-r--r-- | sx.el | 71 | ||||
-rw-r--r-- | sx.org | 79 | ||||
-rw-r--r-- | test/test-printing.el | 67 |
13 files changed, 410 insertions, 146 deletions
diff --git a/sx-babel.el b/sx-babel.el index e115817..7f84fe0 100644 --- a/sx-babel.el +++ b/sx-babel.el @@ -22,7 +22,7 @@ ;; This file contains functions and a variable for font-locking the ;; content of markdown pre blocks according to their language. The ;; main configuration point, for both the user and the developer is -;; the varuable `sx-babel-major-mode-alist', which see. +;; the variable `sx-babel-major-mode-alist', which see. ;;; Code: diff --git a/sx-button.el b/sx-button.el index 4c0666b..5a2f052 100644 --- a/sx-button.el +++ b/sx-button.el @@ -23,7 +23,7 @@ ;; buttons, see: ;; http://www.gnu.org/software/emacs/manual/html_node/elisp/Buttons.html ;; -;; Most interactible parts of the SX buffers are buttons. Wherever you +;; Most interactive parts of the SX buffers are buttons. Wherever you ;; are, you can always cycle through all buttons by hitting `TAB', ;; that should help identify what's a button in each buffer. ;; @@ -34,7 +34,7 @@ ;; ;; Buttons can then be inserted in their respective files using ;; `insert-text-button'. Give it the string, the `:type' you defined, -;; and any aditional properties that can only be determined at +;; and any additional properties that can only be determined at ;; creation. Existing text can be transformed into a button with ;; `make-text-button' instead. @@ -104,23 +104,29 @@ usually part of a code-block." ;;; Help-echo definitions -(defvar sx-button--help-echo +(defconst sx-button--help-echo (concat "mouse-1, RET" (propertize ": %s -- " 'face 'minibuffer-prompt) "w" (propertize ": copy %s" 'face 'minibuffer-prompt)) "Base help-echo on which others can be written.") -(defvar sx-button--question-title-help-echo +(defconst sx-button--user-help-echo (format sx-button--help-echo - (propertize "hide content" 'face 'minibuffer-prompt) - (propertize "link" 'face 'minibuffer-prompt)) + "visit user page" + "link") + "Help echoed in the minibuffer when point is on a user.") + +(defconst sx-button--question-title-help-echo + (format sx-button--help-echo + "hide content" + "link") "Help echoed in the minibuffer when point is on a section.") -(defvar sx-button--link-help-echo +(defconst sx-button--link-help-echo (format sx-button--help-echo - (propertize "visit %s" 'face 'minibuffer-prompt) - (propertize "URL" 'face 'minibuffer-prompt)) + "visit %s" + "URL") "Help echoed in the minibuffer when point is on a section.") @@ -145,6 +151,13 @@ usually part of a code-block." 'action #'sx-button-follow-link :supertype 'sx-button) +(define-button-type 'sx-button-user + 'action #'sx-button-follow-link + 'help-echo sx-button--user-help-echo + ;; We use different faces on different parts of the user button. + 'face 'sx-user-name + :supertype 'sx-button) + (define-button-type 'sx-button-comment 'help-echo (concat "mouse-1, RET" (propertize ": write a comment" diff --git a/sx-filter.el b/sx-filter.el index a3f6861..af3717f 100644 --- a/sx-filter.el +++ b/sx-filter.el @@ -128,8 +128,12 @@ return the compiled filter." question_id share_link) (user display_name + link + accept_rate reputation) (shallow_user display_name + link + accept_rate reputation) (comment owner body_markdown diff --git a/sx-interaction.el b/sx-interaction.el index 4d71c17..97c68b6 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -272,7 +272,7 @@ TEXT is a string. Interactively, it is read from the minibufer." (setq text (read-string "Comment text: " (when .comment_id - (concat (sx--user-@name .owner) " ")))) + (substring-no-properties (sx-user--format "%@ " .owner))))) (while (not (sx--comment-valid-p text 'silent)) (setq text (read-string "Comment text (between 16 and 600 characters): " text)))) ;; If non-interactive, `text' could be anything. @@ -291,10 +291,8 @@ TEXT is a string. Interactively, it is read from the minibufer." ;; The api returns the new DATA. (when (> (length result) 0) (sx--add-comment-to-object - (elt result 0) - (if .post_id - (sx--get-post .post_type .site_par .post_id) - data)) + (sx--ensure-owner-in-object (list (cons 'display_name "(You)")) (elt result 0)) + (if .post_id (sx--get-post .post_type .site_par .post_id) data)) ;; Display the changes in `data'. (sx--maybe-update-display))))) @@ -344,7 +342,15 @@ OBJECT can be a question or an answer." (list comment))))) ;; No previous comments, add it manually. (setcdr object (cons (car object) (cdr object))) - (setcar object `(comments . [,comment]))))) + (setcar object `(comments . [,comment])))) + object) + +(defun sx--ensure-owner-in-object (owner object) + "Add `owner' property with value OWNER to OBJECT." + (unless (cdr-safe (assq 'owner object)) + (setcdr object (cons (car object) (cdr object))) + (setcar object `(owner . ,owner))) + object) ;;; Editing @@ -439,7 +445,8 @@ context at point. " (append (cdr cell) (list answer)))) ;; No previous comments, add it manually. (setcdr question (cons (car question) (cdr question))) - (setcar question `(answers . [,answer]))))) + (setcar question `(answers . [,answer]))) + question)) (provide 'sx-interaction) ;;; sx-interaction.el ends here diff --git a/sx-question-list.el b/sx-question-list.el index 1b7fe5a..884f994 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -111,16 +111,6 @@ "" :group 'sx-question-list-faces) -(defface sx-question-list-reputation - '((t :inherit sx-question-list-date)) - "" - :group 'sx-question-list-faces) - -(defface sx-question-list-user - '((t :inherit font-lock-builtin-face)) - "" - :group 'sx-question-list-faces) - ;;; Backend variables (defvar sx-question-list--print-function #'sx-question-list--print-info @@ -138,8 +128,9 @@ change `tabulated-list-format' accordingly.") This is the default printer used by `sx-question-list'. It assumes QUESTION-DATA is an alist containing (at least) the elements: - `site', `score', `upvoted', `answer_count', `title', - `last_activity_date', `tags', `uestion_id'. + `question_id', `site_par', `score', `upvoted', `answer_count', + `title', `bounty_amount', `bounty_amount', `bounty_amount', + `last_activity_date', `tags', `owner'. Also see `sx-question-list-refresh'." (sx-assoc-let question-data @@ -182,11 +173,7 @@ Also see `sx-question-list-refresh'." (propertize (format "%-40s" (mapconcat #'sx-question--tag-format .tags " ")) 'face 'sx-question-list-tags) " " - (let-alist .owner - (format "%15s %5s" - (propertize (or .display_name "") 'face 'sx-question-list-user) - (propertize (number-to-string (or .reputation 0)) - 'face 'sx-question-list-reputation))) + (sx-user--format "%15d %4r" .owner) (propertize " " 'display "\n"))))))) (defvar sx-question-list--pages-so-far 0 diff --git a/sx-question-print.el b/sx-question-print.el index f6cd1dc..7881b52 100644 --- a/sx-question-print.el +++ b/sx-question-print.el @@ -26,6 +26,7 @@ (require 'sx) (require 'sx-question) (require 'sx-babel) +(require 'sx-user) (defgroup sx-question-mode nil "Customization group for sx-question-mode." @@ -33,20 +34,15 @@ :tag "SX Question Mode" :group 'sx) -(defgroup sx-question-mode-faces nil - "Customization group for the faces of `sx-question-mode'." +(defgroup sx-question-mode-faces '((sx-user custom-group)) + "Customization group for the faces of `sx-question-mode'. +Some faces of this mode might be defined in the `sx-user' group." :prefix "sx-question-mode-" :tag "SX Question Mode Faces" :group 'sx-question-mode) ;;; Faces and Variables -(defcustom sx-question-mode-deleted-user - '((display_name . "(deleted user)")) - "The structure used to represent a deleted account." - :type '(alist :options ((display_name string))) - :group 'sx-question-mode) - (defface sx-question-mode-header '((t :inherit font-lock-variable-name-face)) "Face used on the question headers in the question buffer." @@ -67,13 +63,9 @@ :type 'string :group 'sx-question-mode) -(defface sx-question-mode-author - '((t :inherit font-lock-string-face)) - "Face used on the question author in the question buffer." - :group 'sx-question-mode-faces) - -(defcustom sx-question-mode-header-author "\nAuthor: " - "String used before the question author at the header." +(defcustom sx-question-mode-header-author-format "\nAuthor: %d %r" + "String used to display the question author at the header. +% constructs have special meaning here. See `sx-user--format'." :type 'string :group 'sx-question-mode) @@ -92,11 +84,6 @@ "Face used on the question tags in the question buffer." :group 'sx-question-mode-faces) -(defface sx-question-mode-author - '((t :inherit font-lock-variable-name-face)) - "Face used for author names in the question buffer." - :group 'sx-question-mode-faces) - (defface sx-question-mode-score '((t)) "Face used for the score in the question buffer." @@ -204,11 +191,13 @@ DATA can represent a question or an answer." ;; Sections can be hidden with overlays (sx--wrap-in-overlay '(sx-question-mode--section-content t) + ;; Author + (insert + (sx-user--format + (propertize sx-question-mode-header-author-format + 'face 'sx-question-mode-header) + .owner)) (sx-question-mode--insert-header - ;; Author - sx-question-mode-header-author - (sx-question-mode--propertize-display-name .owner) - 'sx-question-mode-author ;; Date sx-question-mode-header-date (concat @@ -216,8 +205,7 @@ DATA can represent a question or an answer." (when .last_edit_date (format sx-question-mode-last-edit-format (sx-time-since .last_edit_date) - (sx-question-mode--propertize-display-name - (or .last_editor sx-question-mode-deleted-user))))) + (sx-user--format "%d" .last_editor)))) 'sx-question-mode-date) (sx-question-mode--insert-header sx-question-mode-header-score @@ -273,12 +261,6 @@ DATA can represent a question or an answer." :type 'sx-button-comment) (insert "\n"))))) -(defun sx-question-mode--propertize-display-name (author) - "Return display_name of AUTHOR with `sx-question-mode-author' face." - (sx-assoc-let author - (propertize (or .display_name "??") - 'face 'sx-question-mode-author))) - (defun sx-question-mode--print-comment (comment-data) "Print the comment described by alist COMMENT-DATA. The comment is indented, filled, and then printed according to @@ -291,9 +273,8 @@ The comment is indented, filled, and then printed according to (if (eq .upvoted t) "^" "") " ")) (insert - (format - sx-question-mode-comments-format - (sx-question-mode--propertize-display-name .owner) + (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. diff --git a/sx-question.el b/sx-question.el index b9fc78a..1adbc24 100644 --- a/sx-question.el +++ b/sx-question.el @@ -19,7 +19,7 @@ ;;; Commentary: -;; Thie file provides an API for retrieving questions and defines +;; This file provides an API for retrieving questions and defines ;; additional logic for marking questions as read or hidden. diff --git a/sx-search.el b/sx-search.el index fa08e56..aefd12e 100644 --- a/sx-search.el +++ b/sx-search.el @@ -19,7 +19,7 @@ ;;; Commentary: -;; Implements sarch functionality. The basic function is +;; Implements search functionality. The basic function is ;; `sx-search-get-questions', which returns an array of questions ;; according to a search term. ;; diff --git a/sx-switchto.el b/sx-switchto.el index ed83360..6a195e0 100644 --- a/sx-switchto.el +++ b/sx-switchto.el @@ -33,7 +33,7 @@ (mapc (lambda (x) (define-key sx-switchto-map (car x) (cadr x))) '( - ;; These immitate the site's G hotkey. + ;; These imitate the site's G hotkey. ("a" sx-ask) ("h" sx-tab-frontpage) ("m" sx-tab-meta-or-main) diff --git a/sx-user.el b/sx-user.el new file mode 100644 index 0000000..c0f3a78 --- /dev/null +++ b/sx-user.el @@ -0,0 +1,203 @@ +;;; sx-user.el --- handling and printing user information -*- lexical-binding: t; -*- + +;; Copyright (C) 2014 Artur Malabarba + +;; Author: Artur Malabarba <bruce.connor.am@gmail.com> + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + + +;;; Code: +(require 'sx) +(require 'sx-button) + +(defgroup sx-user nil + "How users are displayed by SX." + :prefix "sx-user-" + :tag "SX User" + :group 'sx) + +(defcustom sx-question-mode-fallback-user + '( + (about_me . "") + (accept_rate . -1) + (account_id . -1) + (age . -1) + (answer_count . -1) + (badge_counts . ((bronze . -1) (silver . -1) (gold . -1))) + (creation_date . -1) + (display_name . "(unknown user)") + (down_vote_count . -1) + (is_employee . :json-false) + (last_access_date . -1) + (last_modified_date . -1) + (link . "") + (location . "") + (profile_image . ":(") + (question_count . -1) + (reputation . -1) + (reputation_change_day . -1) + (reputation_change_month . -1) + (reputation_change_quarter . -1) + (reputation_change_week . -1) + (reputation_change_year . -1) + (timed_penalty_date . -1) + (up_vote_count . -1) + (user_id . -1) + (user_type . does_not_exist) + (view_count . -1) + (website_url . "") + ) + "The structure used to represent missing user information. +NOOTE: SX relies on this variable containing all necessary user +information. You may edit any of its fields, but you'll run into +errors if you remove them." + :type '(alist :options ((about_me string) + (accept_rate integer) + (account_id integer) + (age integer) + (answer_count integer) + (badge_counts alist) + (creation_date integer) + (display_name string) + (down_vote_count integer) + (is_employee boolean) + (last_access_date integer) + (last_modified_date integer) + (link string) + (location string) + (profile_image string) + (question_count integer) + (reputation integer) + (reputation_change_day integer) + (reputation_change_month integer) + (reputation_change_quarter integer) + (reputation_change_week integer) + (reputation_change_year integer) + (timed_penalty_date integer) + (up_vote_count integer) + (user_id integer) + (user_type symbol) + (view_count integer) + (website_url string))) + :group 'sx-user) + + +;;; Text properties +(defface sx-user-name + '((t :inherit font-lock-builtin-face)) + "Face used for user names." + :group 'sx-user) + +(defface sx-user-reputation + '((t :inherit font-lock-comment-face)) + "Face used for user reputations." + :group 'sx-user) + +(defface sx-user-accept-rate + '((t)) + "Face used for user accept-rates." + :group 'sx-user) + +(defvar sx-user--format-property-alist + `((?d button ,(list t) category ,(button-category-symbol 'sx-button-user)) + (?n button ,(list t) category ,(button-category-symbol 'sx-button-user)) + (?@ button ,(list t) category ,(button-category-symbol 'sx-button-user)) + (?r face sx-user-reputation) + (?a face sx-user-accept-rate)) + "Alist relating % constructs with text properties. +See `sx-user--format'.") + + +;;; Formatting function +(defun sx-user--format (format-string user) + "Use FORMAT-STRING to format the user object USER. +The value is a copy of FORMAT-STRING, but with certain constructs +replaced by text that describes the specified USER: + +%d is the display name. +%@ is the display name in a format suitable for @mentions. +%l is the link to the profile. +%r is the reputation. +%a is the accept rate. + +The string replaced in each of these construct is also given the +text-properties specified in `sx-user--format-property-alist'. +Specially, %d and %@ are turned into buttons with the +`sx-button-user' category." + (sx-assoc-let (append user sx-question-mode-fallback-user) + (let* ((text (sx-format-replacements + format-string + `((?d . ,\.display_name) + (?n . ,\.display_name) + (?l . ,\.link) + (?r . ,\.reputation) + (?a . ,\.accept_rate) + (?@ . ,(when (string-match "%@" format-string) + (sx-user--@name .display_name))) + ) + sx-user--format-property-alist))) + (if (< 0 (string-width .link)) + (propertize text + ;; For visiting and stuff. + 'sx-button-url .link + 'sx-button-copy .link) + text)))) + + +;;; @name conversion +(defconst sx-user--ascii-replacement-list + '(("[:space:]" . "") + ("àåáâäãåą" . "a") + ("èéêëę" . "e") + ("ìíîïı" . "i") + ("òóôõöøőð" . "o") + ("ùúûüŭů" . "u") + ("çćčĉ" . "c") + ("żźž" . "z") + ("śşšŝ" . "s") + ("ñń" . "n") + ("ýÿ" . "y") + ("ğĝ" . "g") + ("ř" . "r") + ("ł" . "l") + ("đ" . "d") + ("ß" . "ss") + ("Þ" . "th") + ("ĥ" . "h") + ("ĵ" . "j") + ("^[:ascii:]" . "")) + "List of replacements to use for non-ascii characters. +Used to convert user names into @mentions.") + +(defun sx-user--@name (display-name) + "Convert DISPLAY-NAME into an @mention. +In order to correctly @mention the user, all whitespace is +removed from DISPLAY-NAME and a series of unicode conversions are +performed before it is returned. +See `sx-user--ascii-replacement-list'. + +If all you need is the @name, this is very slightly faster than +using `sx-user--format', but it doesn't do any sanity checking." + (concat "@" (sx--recursive-replace + sx-user--ascii-replacement-list display-name))) + +(provide 'sx-user) +;;; sx-user.el ends here + +;; Local Variables: +;; indent-tabs-mode: nil +;; End: @@ -294,39 +294,6 @@ Return the result of BODY." (push ov sx--overlays)) result)) -(defconst sx--ascii-replacement-list - '(("[:space:]" . "") - ("àåáâäãåą" . "a") - ("èéêëę" . "e") - ("ìíîïı" . "i") - ("òóôõöøőð" . "o") - ("ùúûüŭů" . "u") - ("çćčĉ" . "c") - ("żźž" . "z") - ("śşšŝ" . "s") - ("ñń" . "n") - ("ýÿ" . "y") - ("ğĝ" . "g") - ("ř" . "r") - ("ł" . "l") - ("đ" . "d") - ("ß" . "ss") - ("Þ" . "th") - ("ĥ" . "h") - ("ĵ" . "j") - ("^[:ascii:]" . "")) - "List of replacements to use for non-ascii characters. -Used to convert user names into @mentions.") - -(defun sx--user-@name (user) - "Get the `display_name' of USER prepended with @. -In order to correctly @mention the user, all whitespace is -removed from the display name before it is returned." - (sx-assoc-let user - (when (stringp .display_name) - (concat "@" (sx--recursive-replace - sx--ascii-replacement-list .display_name))))) - (defun sx--recursive-replace (alist string) "Replace each car of ALIST with its cdr in STRING." (if alist @@ -337,6 +304,44 @@ removed from the display name before it is returned." (format "[%s]" (car kar)) (cdr kar) string))) string)) +(defun sx-format-replacements (format alist &optional property-alist) + "Use FORMAT-STRING to format the values in ALIST. +ALIST is a list with elements of the form (CHAR . STRING). +The value is a copy of FORMAT-STRING, but with certain constructs +replaced by text as given by ALIST. + +The construct is a `%' character followed by any other character. +The replacement is the STRING corresponding to CHAR in ALIST. In +addition, if CHAR is also the car of an element in +PROPERTY-ALIST, the cdr of that element should be a list of text +properties which will be applied on the replacement. + +The %% construct is special, it is replaced with a single %, even +if ALIST contains a different string at the ?% entry." + (let ((alist (cons '(?% . "%") alist))) + (with-temp-buffer + (insert format) + (goto-char (point-min)) + (while (search-forward-regexp + (rx "%" (group-n 1 (* (any "-+ #0-9.")))) nil 'noerror) + (let* ((char (char-after)) + ;; Understand flags + (flag (match-string 1)) + (val (cdr-safe (assq char alist)))) + (unless val + (error "Invalid format character: `%%%c'" char)) + ;; Insert first, to preserve text properties. + (insert-and-inherit (format (concat "%" flag "s") val)) + (when property-alist + (add-text-properties (match-end 0) (point) + (cdr-safe (assq char property-alist)))) + ;; Delete the specifier body. + (delete-region (match-beginning 0) + (match-end 0)) + ;; Delete `char-after'. + (delete-char 1))) + (buffer-string)))) + (defcustom sx-init-hook nil "Hook run when SX initializes. @@ -97,7 +97,7 @@ Scrolling past the bottom of the list fetches more questions. - ~sx-init-hook~ :: Run when ~sx-initialize~ is called. - ~sx-compose-before-send-hook~ :: Run before POSTing to the API from a buffer in ~sx-compose-mode~. If any of the functions in this - hook, return nil, the transaction is cancelled. + hook, return nil, the transaction is canceled. - ~sx-compose-after-send-functions~ :: Run after POSTing to the API from a buffer in ~sx-compose-mode~, if the transaction was successful. @@ -156,44 +156,45 @@ has a descriptive header explaining its purpose. Still, to help you find your way around, we describe below the current project structure. This list is very loosely ordered form low to high-level. -- ~sx.el~ - Utility functions used throughout the package. Essentially - every file indirectly requires this one. If you're adding a function - that's used by different parts of the package, add it to this file. -- ~sx-time.el~ - Similar to ~sx.el~, but only contains a few - time-related functions. -- ~sx-filter.el~ - Handles retrieval of filters. -- ~sx-cache.el~ - Saves and restores persistent data between sessions. -- ~sx-button.el~ - Defines all button types used throughout the - package. Currently used only by ~sx-question-print.el~. - -- ~sx-request.el~ - Requests and url manipulation. Backend used by - ~sx-method.el~. It shouldn't be necessary to use the functions in - this file outside ~sx-method.el~. -- ~sx-method.el~ - Main interface for API method calls. - -- ~sx-favorites.el~ - Starred questions. -- ~sx-networks.el~ - User network information. -- ~sx-site.el~ - Browsing sites. -- ~sx-auth.el~ - Handles user authentication. - -- ~sx-question.el~ - Base question logic. Holds several functions for - retrieving questions and for processing retrieved questions. Doesn't - do any sort of user interface, that is left for - ~sx-question-list.el~ and ~sx-question-mode.el~. -- ~sx-question-list.el~ - Major-mode for navigating questions list. -- ~sx-question-mode.el~ - User interface for displaying a - question. Creates the buffer and defines the major-mode. -- ~sx-question-print.el~ - Populating the question buffer with - content. Used by ~sx-question-mode.el~ to actually print the content - of a question. -- ~sx-babel.el~ - Font-locking code blocks printed by - ~sx-question-print.el~ according to the language. - -- ~sx-compose.el~ - Major-mode for composing questions and answers. -- ~sx-interaction.el~ - Voting, commenting, and otherwise interacting with questions. -- ~sx-tab.el~ - Functions for viewing different tabs. - -- ~sx-load.el~ - Load all files of the sx package. Designed as an easy way in for users who install the package manually (since they don't have autoloads). +- ~sx.el~ :: Utility functions used throughout the + package. Essentially every file indirectly requires this + one. If you're adding a function that's used by different + parts of the package, add it to this file. +- ~sx-time.el~ :: Similar to ~sx.el~, but only contains a few + time-related functions. +- ~sx-filter.el~ :: Handles retrieval of filters. +- ~sx-cache.el~ :: Saves and restores persistent data between + sessions. +- ~sx-button.el~ :: Defines all button types used throughout the + package. Currently used only by + ~sx-question-print.el~. +- ~sx-request.el~ :: Requests and url manipulation. Back-end used by + ~sx-method.el~. It shouldn't be necessary to use the functions in + this file outside ~sx-method.el~. +- ~sx-method.el~ :: Main interface for API method calls. +- ~sx-favorites.el~ :: Starred questions. +- ~sx-networks.el~ :: User network information. +- ~sx-site.el~ :: Browsing sites. +- ~sx-auth.el~ :: Handles user authentication. +- ~sx-question.el~ :: Base question logic. Holds several functions for + retrieving questions and for processing retrieved + questions. Doesn't do any sort of user interface, that is left + for ~sx-question-list.el~ and ~sx-question-mode.el~. +- ~sx-question-list.el~ :: Major-mode for navigating questions list. +- ~sx-question-mode.el~ :: User interface for displaying a + question. Creates the buffer and defines the major-mode. +- ~sx-question-print.el~ :: Populating the question buffer with + content. Used by ~sx-question-mode.el~ to actually print the + content of a question. +- ~sx-babel.el~ :: Font-locking code blocks printed by + ~sx-question-print.el~ according to the language. +- ~sx-compose.el~ :: Major-mode for composing questions and answers. +- ~sx-interaction.el~ :: Voting, commenting, and otherwise interacting + with questions. +- ~sx-tab.el~ :: Functions for viewing different tabs. +- ~sx-load.el~ :: Load all files of the SX package. Designed as an + easy way in for users who install the package + manually (since they don't have autoloads). * COMMENT Local Variables # LocalWords: StackExchange SX inbox sx API url json inline Org diff --git a/test/test-printing.el b/test/test-printing.el index c477b28..7384829 100644 --- a/test/test-printing.el +++ b/test/test-printing.el @@ -64,13 +64,76 @@ after being run through `sx-question--tag-format'." "Test `sx--user-@name' character substitution" (should (string= - (sx--user-@name '((display_name . "ĥÞßđłřğĝýÿñńśşšŝżźžçćčĉùúûüŭůòóôõöøőðìíîïıèéêëęàåáâäãåąĵ★"))) + (sx-user--@name "ĥÞßđłřğĝýÿñńśşšŝżźžçćčĉùúûüŭůòóôõöøőðìíîïıèéêëęàåáâäãåąĵ★") "@hTHssdlrggyynnsssszzzccccuuuuuuooooooooiiiiieeeeeaaaaaaaaj")) (should (string= - (sx--user-@name '((display_name . "ĤÞßĐŁŘĞĜÝŸÑŃŚŞŠŜŻŹŽÇĆČĈÙÚÛÜŬŮÒÓÔÕÖØŐÐÌÍÎÏıÈÉÊËĘÀÅÁÂÄÃÅĄĴ"))) + (sx-user--@name "ĤÞßĐŁŘĞĜÝŸÑŃŚŞŠŜŻŹŽÇĆČĈÙÚÛÜŬŮÒÓÔÕÖØŐÐÌÍÎÏıÈÉÊËĘÀÅÁÂÄÃÅĄĴ") + "@HTHssDLRGGYYNNSSSSZZZCCCCUUUUUUOOOOOOOOIIIIiEEEEEAAAAAAAAJ")) + (should-error + (sx-user--@name 2))) + +(ert-deftest sx-user--format () + "Test various `sx-user--format' features." + (let ((user + '((display_name . "ĥÞßđłřğĝýÿñńśşšŝżźžçćčĉùúûüŭůòóôõöøőðìíîïıèéêëęàåáâäãåąĵ★") + (accept_rate . 90) + (reputation . 10) + (link . "link")))) + (should + (equal (sx-user--format "%l" user) "link")) + (should + (equal + (sx-user--format "%@" user) + "@hTHssdlrggyynnsssszzzccccuuuuuuooooooooiiiiieeeeeaaaaaaaaj")) + (should + (equal + (sx-user--format "%@%%d%%%-30d %9r%l" user) + "@hTHssdlrggyynnsssszzzccccuuuuuuooooooooiiiiieeeeeaaaaaaaaj%d%ĥÞßđłřğĝýÿñńśşšŝżźžçćčĉùúûüŭůòóôõöøőðìíîïıèéêëęàåáâäãåąĵ★ 10link"))) + (should + (string= + (sx-user--format "%@" '((display_name . "ĤÞßĐŁŘĞĜÝŸÑŃŚŞŠŜŻŹŽÇĆČĈÙÚÛÜŬŮÒÓÔÕÖØŐÐÌÍÎÏıÈÉÊËĘÀÅÁÂÄÃÅĄĴ"))) "@HTHssDLRGGYYNNSSSSZZZCCCCUUUUUUOOOOOOOOIIIIiEEEEEAAAAAAAAJ"))) +(ert-deftest sx-object-modification () + "Test adding things to objects" + (let ((object (list (cons 'owner "me")))) + (should + (equal (sx--ensure-owner-in-object 1 object) + '((owner . "me")))) + (should + (equal object '((owner . "me"))))) + (let ((object (list (cons 'not-owner "me")))) + (should + (equal (sx--ensure-owner-in-object 1 object) + '((owner . 1) (not-owner . "me")))) + (should + (equal object '((owner . 1) (not-owner . "me"))))) + (let ((object (list (cons 'comments [something])))) + (should + (equal (sx--add-comment-to-object "comment" object) + '((comments . [something "comment"])))) + (should + (equal object '((comments . [something "comment"]))))) + (let ((object (list (cons 'not-comments [something])))) + (should + (equal (sx--add-comment-to-object "comment" object) + '((comments . ["comment"]) (not-comments . [something])))) + (should + (equal object '((comments . ["comment"]) (not-comments . [something]))))) + (let ((object (list (cons 'not-answers [something])))) + (should + (equal (sx--add-answer-to-question-object "answer" object) + '((answers . ["answer"]) (not-answers . [something])))) + (should + (equal object '((answers . ["answer"]) (not-answers . [something]))))) + (let ((object (list (cons 'answers [something])))) + (should + (equal (sx--add-answer-to-question-object "answer" object) + '((answers . [something "answer"])))) + (should + (equal object '((answers . [something "answer"])))))) + (ert-deftest sx-question-mode--fill-and-fontify () "Check complicated questions are filled correctly." (should |