diff options
-rw-r--r-- | Cask | 9 | ||||
-rw-r--r-- | sx-auth.el | 5 | ||||
-rw-r--r-- | sx-babel.el | 118 | ||||
-rw-r--r-- | sx-load.el | 1 | ||||
-rw-r--r-- | sx-method.el | 2 | ||||
-rw-r--r-- | sx-question-mode.el | 4 | ||||
-rw-r--r-- | sx-question-print.el | 27 | ||||
-rw-r--r-- | sx.el | 30 | ||||
-rw-r--r-- | sx.org | 2 |
9 files changed, 136 insertions, 62 deletions
@@ -1,15 +1,8 @@ -(package "stack-mode" "0" "Stack Exchange for Emacs") - (source gnu) (source melpa-stable) +(package-file "sx.el") (files "sx*.el") -(depends-on "json" "1.4") -(depends-on "url") -(depends-on "cl-lib") -(depends-on "markdown-mode") -(depends-on "let-alist") - (development (depends-on "ert")) @@ -80,7 +80,8 @@ will be (METHOD . t)") Keywords are of form (OBJECT TYPES) where TYPES is (FILTER FILTER FILTER).") -(defun sx-auth-authenticate () +;;;###autoload +(defun sx-authenticate () "Authenticate this application. Authentication is required to read your personal data (such as notifications) and to write with the API (asking and answering @@ -126,8 +127,6 @@ parsed and displayed prominently on the page)." (error "You must enter this code to use this client fully")) (sx-cache-set 'auth `((access_token . ,sx-auth-access-token))))) -(defalias 'sx-authenticate #'sx-auth-authenticate) - (defun sx-auth--method-p (method &optional submethod) "Check if METHOD is one that may require authentication. If it has `auth-required' SUBMETHODs, or no submethod, return t." diff --git a/sx-babel.el b/sx-babel.el new file mode 100644 index 0000000..5544642 --- /dev/null +++ b/sx-babel.el @@ -0,0 +1,118 @@ +;;; sx-babel.el --- Font-locking pre blocks according to language. -*- 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: + +;; 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. + + +;;; Code: +(require 'sx-button) + +(defvar sx-babel-major-mode-alist + `((,(rx (or "*" "#+")) org-mode) + (,(rx (or "[" "(" ";" "#(")) emacs-lisp-mode) + ;; @TODO: Make shell-mode work here. Currently errors because it + ;; needs a process. `sh-mode' isn't as nice. + (,(rx (or "$ " "# ")) sh-mode) + ) + "List of cons cells determining which major-mode to use when. +Each car is a rule and each cdr is a major-mode. The first rule +which is satisfied activates the major-mode. + +Point is moved to the first non-blank character before testing +the rule, which can either be a string or a function. If it is a +string, is tested as a regexp starting from point. If it is a +function, is called with no arguments and should return non-nil +on a match.") +(put 'sx-babel-major-mode-alist 'risky-local-variable-p t) + + +;;; Font-locking the text +(defun sx-babel--make-pre-button (beg end) + "Turn the region between BEG and END into a button." + (let ((text (buffer-substring-no-properties beg end)) + indent) + (with-temp-buffer + (insert text) + (setq indent (sx-babel--unindent-buffer)) + (goto-char (point-min)) + (make-text-button + (point-min) (point-max) + 'sx-button-copy (buffer-string) + :type 'sx-question-mode-code-block) + (sx-babel--determine-and-activate-major-mode) + (font-lock-fontify-region (point-min) (point-max)) + (goto-char (point-min)) + (let ((space (make-string indent ?\s))) + (while (not (eobp)) + (insert space) + (forward-line 1))) + (setq text (buffer-string))) + (goto-char beg) + (delete-region beg end) + (insert text))) + +(defun sx-babel--determine-and-activate-major-mode () + "Activate the major-mode most suitable for the current buffer." + (let ((alist sx-babel-major-mode-alist) + cell) + (while (setq cell (pop alist)) + (goto-char (point-min)) + (skip-chars-forward "\r\n[:blank:]") + (let ((kar (car cell))) + (when (if (stringp kar) (looking-at kar) (funcall kar)) + (setq alist nil) + (funcall (cadr cell))))))) + +(defun sx-babel--unindent-buffer () + "Remove absolute indentation in current buffer. +Finds the least indented line, and removes that amount of +indentation from all lines. Primarily designed to extract the +content of markdown code blocks. + +Returns the amount of indentation removed." + (save-excursion + (goto-char (point-min)) + (let (result) + ;; Get indentation of each non-blank line + (while (null (eobp)) + (skip-chars-forward "[:blank:]") + (unless (looking-at "$") + (push (current-column) result)) + (forward-line 1)) + (when result + (setq result (apply #'min result)) + ;; Build a regexp with the smallest indentation + (let ((rx (format "^ \\{0,%s\\}" result))) + (goto-char (point-min)) + ;; Use this regexp to remove that much indentation + ;; throughout the buffer. + (while (and (null (eobp)) + (search-forward-regexp rx nil 'noerror)) + (replace-match "") + (forward-line 1)))) + (or result 0)))) + +(provide 'sx-babel) +;;; sx-babel.el ends here + @@ -25,6 +25,7 @@ sx-time sx-auth sx-button + sx-babel sx-cache sx-compose sx-encoding diff --git a/sx-method.el b/sx-method.el index 5646772..4575b0f 100644 --- a/sx-method.el +++ b/sx-method.el @@ -91,7 +91,7 @@ Return the entire response as a complex alist." ;; 1. Need auth and warn user (interactive use) ((and method-auth (equal 'warn auth)) (user-error - "This request requires authentication. Please run `M-x sx-auth-authenticate' and try again.")) + "This request requires authentication. Please run `M-x sx-authenticate' and try again.")) ;; 2. Need auth to populate UI, cannot provide subset ((and method-auth auth) (setq call 'sx-request-fallback)) diff --git a/sx-question-mode.el b/sx-question-mode.el index 19d7d16..5735f47 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -62,7 +62,9 @@ Returns the question buffer." (sx-question-mode--erase-and-print-question data))) (defun sx-question-mode--erase-and-print-question (data) - "Erase contents of buffer and print question given by DATA." + "Erase contents of buffer and print question given by DATA. +Also marks the question as read with `sx-question--mark-read'." + (sx-question--mark-read data) (let ((inhibit-read-only t)) (erase-buffer) (sx-question-mode) diff --git a/sx-question-print.el b/sx-question-print.el index c32c3eb..dc853ba 100644 --- a/sx-question-print.el +++ b/sx-question-print.el @@ -23,11 +23,9 @@ ;;; Code: (require 'markdown-mode) (require 'sx-button) -(eval-when-compile - (require 'rx)) - (require 'sx) (require 'sx-question) +(require 'sx-babel) (defgroup sx-question-mode nil "Customization group for sx-question-mode." @@ -431,29 +429,18 @@ If ID is nil, use FALLBACK-ID instead." "If there's a pre block ahead, handle it, skip it and return t. Handling means to turn it into a button and remove erroneous font-locking." - (let (beg end text) + (let (beg end) (when (markdown-match-pre-blocks (save-excursion (skip-chars-forward "\r\n[:blank:]") (setq beg (point)))) (setq end (point)) - (setq text - (sx--unindent-text - (buffer-substring - (save-excursion - (goto-char beg) - (line-beginning-position)) - end))) - (put-text-property beg end 'display nil) - (make-text-button - beg end - 'face 'markdown-pre-face - 'sx-button-copy text - :type 'sx-question-mode-code-block)))) + (sx-babel--make-pre-button + (save-excursion + (goto-char beg) + (line-beginning-position)) + end)))) (provide 'sx-question-print) ;;; sx-question-print.el ends here -;; Local Variables: -;; lexical-binding: t -;; End: @@ -1,4 +1,4 @@ -;;; sx.el --- core functions of the sx package. +;;; sx.el --- StackExchange client ;; Copyright (C) 2014 Sean Allred @@ -201,34 +201,6 @@ Anything before the (sub)domain is removed." (rx string-start (or (and (0+ word) (optional ":") "//"))) "" url))) -(defun sx--unindent-text (text) - "Remove indentation from TEXT. -Primarily designed to extract the content of markdown code -blocks." - (with-temp-buffer - (insert text) - (goto-char (point-min)) - (let (result) - ;; Get indentation of each non-blank line - (while (null (eobp)) - (skip-chars-forward "[:blank:]") - (unless (looking-at "$") - (push (current-column) result)) - (forward-line 1)) - (when result - ;; Build a regexp with the smallest indentation - (let ((rx (format "^ \\{0,%s\\}" - (apply #'min result)))) - (goto-char (point-min)) - ;; Use this regexp to remove that much indentation - ;; throughout the buffer. - (while (and (null (eobp)) - (search-forward-regexp rx nil 'noerror)) - (replace-match "") - (forward-line 1))))) - ;; Return the buffer - (buffer-string))) - ;;; Printing request data (defvar sx--overlays nil @@ -186,6 +186,8 @@ structure. This list is very loosely ordered form low to high-level. - ~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. |