diff --git a/.emacs.d/custom.el b/.emacs.d/custom.el index 21c1ce2..7b5a80b 100644 --- a/.emacs.d/custom.el +++ b/.emacs.d/custom.el @@ -28,6 +28,7 @@ '(js2-strict-trailing-comma-warning nil) '(make-backup-files nil) '(mouse-buffer-menu-mode-mult 0) + '(org-export-backends (quote (ascii html icalendar latex md))) '(org-hide-leading-stars t) '(org-odd-levels-only t) '(rmail-mail-new-frame t) diff --git a/.emacs.d/ox-quip.el b/.emacs.d/ox-quip.el new file mode 100644 index 0000000..09c88ed --- /dev/null +++ b/.emacs.d/ox-quip.el @@ -0,0 +1,32 @@ +;; Publisher from org-mode to Quip. (Export as markdown, push as a new +;; thread or amend to existing quip thread.) + +(require 'cl-extra) +(require 'ox-md) +(require 'quip-api) + + +(defun org-quip-get-thread-identifier () + (org-entry-get nil "quip-id" t)) + +(defun org-quip-put-thread-identifier (identifier) + (save-excursion + (while (org-up-heading-safe)) + (org-entry-put nil "quip-id" identifier))) + +(defun org-quip-publish-quip (content) + "Publish content as a new Quip document. Returns the ID of the new document." + (let ((response (quip-new-document content))) + (cdr (assoc 'id (cdr (assoc 'thread response)))))) + +(defun org-quip-publish-to-quip () + (interactive) + (let + ((quip-id (org-quip-get-thread-identifier)) + (content (org-export-as 'md))) + (if quip-id + (org-quip-update-quip quip-id content) + (let ((new-quip-id (org-quip-publish-quip content))) + (org-quip-put-thread-identifier new-quip-id))))) + +(provide 'ox-quip) diff --git a/.emacs.d/quip.el b/.emacs.d/quip.el new file mode 100644 index 0000000..5850985 --- /dev/null +++ b/.emacs.d/quip.el @@ -0,0 +1,103 @@ +;; Quip API + +(require 'cl-extra) +(require 'json) +(require 'url) + +;; TODO: Make this actually a variable. +(defconst doty-quip-api-key + "UU9RQU1BcTNCdU0=|1506626374|H13gPE9bkDAkHQp9PtTlX8i78wYvtSBwEJgLAuChnXs=") + +(defun quip-invoke-json (path method params) + "Submit a request to the Quip API. Returns the parsed JSON from the response." + (let + ((url (concat "https://platform.quip.com/1/" path)) + (url-request-method method) + (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " doty-quip-api-key)) + ("Content-Type" . "application/x-www-form-urlencoded"))) + (url-request-data + (mapconcat (lambda (pair) (format "%s=%s" (car pair) (url-hexify-string (cdr pair)))) + params + "&"))) + (with-current-buffer (url-retrieve-synchronously url) + (goto-char (point-min)) + (re-search-forward "^$") + (json-read)))) + +(defun quip-new-document (content) + "Create a new Quip document with the provided content. Returns the parsed JSON response." + (quip-invoke-json "threads/new-document" + "POST" + `((format . "markdown") + (content . ,content)))) + +(defun quip-get-thread (id) + "Get the Quip thread with the specified ID. Returns the parsed JSON response." + (quip-invoke-json (concat "threads/" id) "GET" nil)) + +(defconst quip-location-append 0) +(defconst quip-location-prepend 1) +(defconst quip-location-after-section 2) +(defconst quip-location-before-section 3) +(defconst quip-location-replace-section 4) +(defconst quip-location-delete-section 5) + +(defun quip-thread-append (thread content) + "Append the content to the specified thread." + (quip-invoke-json "threads/edit-document" + "POST" + `((format . "markdown") + (content . ,content) + (location . ,quip-location-append) + (thread_id . ,thread)))) + +(defun quip-thread-prepend (thread content) + "Prepend the content to the specified thread." + (quip-invoke-json "threads/edit-document" + "POST" + `((format . "markdown") + (content . ,content) + (location . ,quip-location-prepend) + (thread_id . ,thread)))) + +(defun quip-thread-append-after (thread section content) + "Append the content to the specified thread after the specified section." + (quip-invoke-json "threads/edit-document" + "POST" + `((format . "markdown") + (content . ,content) + (location . ,quip-location-append-section) + (section_id . ,section) + (thread_id . ,thread)))) + +(defun quip-thread-prepend-before (thread section content) + "Prepend the content to the specified thread before the specified section." + (quip-invoke-json "threads/edit-document" + "POST" + `((format . "markdown") + (content . ,content) + (location . ,quip-location-prepend-section) + (section_id . ,section) + (thread_id . ,thread)))) + +(defun quip-thread-replace-section (thread section content) + "Replace the content of the specified section." + (quip-invoke-json "threads/edit-document" + "POST" + `((format . "markdown") + (content . ,content) + (location . ,quip-location-replace-section) + (section_id . ,section) + (thread_id . ,thread)))) + +(defun quip-thread-delete-section (thread section) + "Delete the specified section." + (quip-invoke-json "threads/edit-document" + "POST" + `((format . "markdown") + (content . ,content) + (location . ,quip-location-delete-section) + (section_id . ,section) + (thread_id . ,thread)))) + +(provide 'quip-api)