diff options
-rw-r--r-- | bot/sx-bot.el | 54 | ||||
-rwxr-xr-x | bot/sx-bot.sh | 8 | ||||
-rw-r--r-- | sx-compose.el | 29 | ||||
-rw-r--r-- | sx-filter.el | 35 | ||||
-rw-r--r-- | sx-tag.el | 78 |
5 files changed, 203 insertions, 1 deletions
diff --git a/bot/sx-bot.el b/bot/sx-bot.el new file mode 100644 index 0000000..f7e0557 --- /dev/null +++ b/bot/sx-bot.el @@ -0,0 +1,54 @@ +;;; sx-bot.el --- Functions for viewing different tabs. -*- 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-site) +(require 'sx-tag) + +(defcustom sx-bot-out-dir "./data/tags/" + "Directory where output tag files are saved." + :type 'directory + :group 'sx) + + +;;; Printing +(defun sx-bot-write-to-file (data) + "Write (cdr DATA) to file named (car DATA). +File is savedd in `sx-bot-out-dir'." + (with-temp-file (expand-file-name (car data) sx-bot-out-dir) + (let (print-length) + (prin1 (cdr data) (current-buffer))))) + + +(defun sx-bot-fetch-and-write-tags () + "Get a list of all tags of all sites and save to disk." + (make-directory sx-bot-out-dir t) + (mapc #'sx-bot-write-to-file + ;; @TODO: Not yet implemented! + (mapcar #'sx-tag--get-all (sx-site-get-api-tokens)))) + +;;; Newest +(provide 'sx-bot) +;;; sx-bot.el ends here diff --git a/bot/sx-bot.sh b/bot/sx-bot.sh new file mode 100755 index 0000000..176e454 --- /dev/null +++ b/bot/sx-bot.sh @@ -0,0 +1,8 @@ +#!/usr/bin/bash + +git branch gh-pages && + git pull && + emacs -Q --batch -L "./" -l sx-bot -f sx-bot-fetch-and-write-tags && + git commit . && + git push && + echo SUCCESS diff --git a/sx-compose.el b/sx-compose.el index ab4a58d..d27d2f3 100644 --- a/sx-compose.el +++ b/sx-compose.el @@ -82,6 +82,10 @@ Is invoked between `sx-compose-before-send-hook' and "Headers inserted when composing a new question. Used by `sx-compose-create'.") +(defvar sx-compose--site nil + "Site which the curent compose buffer belongs to.") +(make-variable-buffer-local 'sx-compose--site) + ;;; Major-mode (define-derived-mode sx-compose-mode markdown-mode "Compose" @@ -116,6 +120,8 @@ contents to the API, then calls `sx-compose-after-send-functions'." (run-hook-with-args 'sx-compose-after-send-functions (current-buffer) result))))) + +;;; Functions for use in hooks (defun sx-compose-quit (buffer _) "Close BUFFER's window and kill it." (interactive (list (current-buffer) nil)) @@ -131,6 +137,26 @@ contents to the API, then calls `sx-compose-after-send-functions'." (with-current-buffer buffer (kill-new (buffer-string))))) +(defun sx-compose--check-tags () + "Check if tags in current compose buffer are valid." + (save-excursion + (goto-char (point-min)) + (unless (search-forward-regexp + "^Tags : *\\([^[:space:]].*\\) *$" + (next-single-property-change (point-min) 'sx-compose-separator) + 'noerror) + (error "No Tags header found")) + (let ((invalid-tags + (sx-tag--invalid-name-p + (split-string (match-string 1) "[[:space:],;]" + 'omit-nulls "[[:space:]]") + sx-compose--site))) + (if invalid-tags + ;; If the user doesn't want to create the tags, we return + ;; nil and sending is aborted. + (y-or-n-p "Following tags don't exist. Create them? %s " invalid-tags) + t)))) + ;;; Functions to help preparing buffers (defun sx-compose-create (site parent &optional before-functions after-functions) @@ -153,6 +179,7 @@ respectively added locally to `sx-compose-before-send-hook' and (cdr (assoc 'title parent)))))) (with-current-buffer (sx-compose--get-buffer-create site parent) (sx-compose-mode) + (setq sx-compose--site site) (setq sx-compose--send-function (if (consp parent) (sx-assoc-let parent @@ -180,6 +207,8 @@ respectively added locally to `sx-compose-before-send-hook' and (add-hook 'sx-compose-before-send-hook it nil t)) (dolist (it (reverse after-functions)) (add-hook 'sx-compose-after-send-functions it nil t)) + (when is-question + (add-hook 'sx-compose-before-send-hook #'sx-compose--check-tags nil t)) ;; If the buffer is empty, the draft didn't exist. So prepare the ;; question. (when (or (string= (buffer-string) "") diff --git a/sx-filter.el b/sx-filter.el index 8c00c12..ad37e67 100644 --- a/sx-filter.el +++ b/sx-filter.el @@ -41,7 +41,40 @@ Structure: ...)") -;;; Compilation +;;; Creation + +(defmacro sx-filter-from-nil (included) + "Creates a filter data structure with INCLUDED fields. +All wrapper fields are included by default." + ;; @OTODO: it would be neat to have syntax like + ;; + ;; (field-a + ;; field-b + ;; (object-a subfield) + ;; field-c + ;; (object-b subfield-a subfield-b)) + ;; + ;; expand into + ;; + ;; (field-a + ;; field-b + ;; object-a.subfield + ;; field-c + ;; object-b.subfield-a object-b.subfield-b) + `(quote ((,@included + .backoff + .error_id + .error_message + .error_name + .has_more + .items + .page + .page_size + .quota_max + .quota_remaining + .total + .type) + nil none))) ;;; @TODO allow BASE to be a precompiled filter name (defun sx-filter-compile (&optional include exclude base) diff --git a/sx-tag.el b/sx-tag.el new file mode 100644 index 0000000..0aec814 --- /dev/null +++ b/sx-tag.el @@ -0,0 +1,78 @@ +;;; sx-tag.el --- Retrieving list of tags and handling tags. -*- lexical-binding: t; -*- + +;; 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: +(eval-when-compile + '(require 'cl-lib)) + +(require 'sx) +(require 'sx-method) + + +;;; Getting the list from a site +(defvar sx-tag-filter + (sx-filter-from-nil + (tag.name)) + "Filter used when querying tags.") + +(defun sx-tag--get-all (site) + "Retrieve all tags for SITE." + (sx-method-call 'tags + :get-all t + :filter sx-tag-filter + :site "emacs")) + +(defun sx-tag--get-some-tags-containing (site string) + "Return at most 100 tags for SITE containing STRING. +Returns an array." + (sx-method-call 'tags + :auth nil + :filter sx-tag-filter + :site site + :keywords `((page . 1) (pagesize . 100) (inname . ,string)))) + +(defun sx-tag--get-some-tag-names-containing (site string) + "Return at most 100 tag names for SITE containing STRING. +Returns a list." + (mapcar (lambda (x) (cdr (assoc 'name x))) + (sx-tag--get-some-tags-containing site string))) + + +;;; Check tag validity +(defun sx-tag--invalid-name-p (site tags) + "Nil if TAGS exist in SITE. +TAGS can be a string (the tag name) or a list of strings. +Fails if TAGS is a list with more than 100 items. +Return the list of invalid tags in TAGS." + (and (listp tags) (> (length tags) 100) + (error "Invalid argument. TAG has more than 100 items")) + (let ((result + (mapcar + (lambda (x) (cdr (assoc 'name x))) + (sx-method-call 'tags + :id (sx--thing-as-string tags) + :submethod 'info + :auth nil + :filter sx-tag-filter + :site site + :keywords '((page . 1) (pagesize . 100)))))) + (cl-remove-if (lambda (x) (member x result)) tags))) + +(provide 'sx-tag) +;;; sx-tag.el ends here |