emacs的outline wiki 插件
Contents
不多说了,直接贴代码吧,也是从别人的配置上拿到的,在他的基础上加了一些功能(支持了搜索、刷新)。这就是emacs之道吧,看了别人的菜谱,自己也可以方便地抄过来改吧改吧,希望可以帮助到有需要的人。
依赖了helm 和markdown-mode
;;; outline-wiki.el --- Outline Wiki tools for Emacs -*- lexical-binding: t; -*-
;; Copyright (c) 2019 Abhinav Tushar
;; Author: Abhinav Tushar <[email protected]>
;; Version: 1.0.1
;; Package-Requires: ((emacs "26") (helm "3.7.0") (markdown-mode "2.4") (request "0.3.2"))
;; URL: https://github.com/lepisma/outline-wiki.el
;;; Commentary:
;; Outline Wiki tools for Emacs
;; This file is not a part of GNU Emacs.
;;; License:
;; 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/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'markdown-mode)
(require 'request)
(defcustom outline-wiki-url "<wiki url>"
"Root url for outline wiki.")
(defcustom outline-wiki-api-token "<your token>"
"API token for outline wiki.")
(defvar-local outline-wiki-doc nil
"Buffer local variable for keeping currently shown document.")
(defun outline-wiki-get-token ()
"Open webpage for token generation."
(interactive)
(browse-url (concat outline-wiki-url "/settings/tokens")))
(defun outline-wiki-post-request (request-url data callback)
"Send post request to outline API."
(request
(concat outline-wiki-url request-url)
:type "POST"
:headers `(("authorization" . ,(concat "Bearer " outline-wiki-api-token))
("Content-Type" . "application/json"))
:data (json-encode data)
:parser 'json-read
:success (cl-function
(lambda (&key data &allow-other-keys)
(funcall callback data)))
:error (cl-function
(lambda (&key error-thrown &allow-other-keys)
(message "Error: %S" error-thrown)))
))
(defun outline-wiki-share-url-p (url)
(string-match-p (concat outline-wiki-url "/share") url))
(defun outline-wiki-get-id-from-url (url)
"Get identifier from given URL.
This id is share-id or url-id depending on the type of URL."
(car (last (split-string url "/"))))
(defun outline-wiki-get-doc-from-url (url callback)
"Get document for the given URL and call CALLBACK on the
document."
(let ((data (if (outline-wiki-share-url-p url)
`(("shareId" . ,(outline-wiki-get-id-from-url url)))
`(("id" . ,(outline-wiki-get-id-from-url url))))))
(outline-wiki-post-request "/api/documents.info" data (lambda (data) (funcall callback (alist-get 'data data))))))
(defun outline-wiki-doc-open (doc)
"Open an outline DOC in a new buffer."
(let ((buffer (get-buffer-create (concat "*outline-wiki:" (alist-get 'title doc) "*"))))
(with-current-buffer buffer
(erase-buffer)
(insert (alist-get 'text doc))
(goto-char (point-min))
(markdown-mode)
(setq outline-wiki-doc doc)
(outline-wiki-mode))
(set-buffer buffer)
(switch-to-buffer buffer)))
(defun outline-wiki-doc-save (doc)
"Push given DOC on the API. This unconditionally overwrites the
upstream so be careful with multiple editors."
(message "Saving document")
(outline-wiki-post-request
"/api/documents.update"
`(("id" . ,(alist-get 'id doc))
("text" . ,(buffer-substring-no-properties (point-min) (point-max))))
(lambda (&rest _) (message "Document saved"))))
(defun outline-wiki-doc-open-in-browser (doc)
"Open an outline DOC in default web browser."
(browse-url (concat outline-wiki-url (alist-get 'url doc))))
(defun outline-wiki-doc-parent (doc &optional all-docs)
"Pick and return parent of given DOC from ALL-DOCS."
(when-let ((pid (alist-get 'parentDocumentId doc)))
(cl-find-if (lambda (other) (string= (alist-get 'id other) pid)) all-docs)))
(defun outline-wiki-qualified-title (doc &optional all-docs)
"Return fully specified title for given doc.
TODO: Show collection name also in front. That might need caching
of some sort so not doing right now."
(if-let ((parent (outline-wiki-doc-parent doc all-docs)))
(concat (outline-wiki-relative-path parent all-docs) " › " (alist-get 'title doc))
(alist-get 'title doc)))
;;;###autoload
(defun outline-wiki-doc-open-from-url (url)
"Open doc from given URL for editing."
(interactive "sOutline URL: ")
(outline-wiki-get-doc-from-url url #'outline-wiki-doc-open))
(defun outline-wiki-save ()
"Save doc showed in current buffer."
(interactive)
(if outline-wiki-doc
(outline-wiki-doc-save outline-wiki-doc)
(message "No outline document open right now")))
;;;###autoload
(define-minor-mode outline-wiki-mode
"Minor mode for working with outline wiki documents."
:init-value nil
:keymap `((,(kbd "C-x C-s") . outline-wiki-save)))
;;;###autoload
(defun helm-outline-wiki-search (query-term)
"Actions for outline wiki documents."
(interactive "sQuery: ")
(outline-wiki-post-request
"/api/documents.search"
`(("query" . ,query-term))
(lambda (data)
(let ((documents (mapcar (lambda (item) (alist-get 'document item)) (alist-get 'data data))))
(helm :sources (helm-build-sync-source "documents"
:candidates (mapcar (lambda (doc) (cons (outline-wiki-qualified-title doc documents) doc)) documents)
:action `(("Open in buffer" . ,#'outline-wiki-doc-open)
("Open in browser" . ,#'outline-wiki-doc-open-in-browser)))
:buffer "*helm outline*"
:prompt "Open Doc: ")))))
(defun outline-wiki-doc-create (options)
;; new doc, options contains collections and new doc title
(let ((title (car options))
(id (cdr (assoc 'id (cdr options)))))
(outline-wiki-post-request
"/api/documents.create"
`(("title" . ,title)
("collectionId" . ,id)
("publish" . t))
(lambda (data)
(outline-wiki-doc-open (alist-get 'data data))))))
;;;###autoload
(defun helm-outline-wiki-new (title)
"New outline wiki document with TITLE."
(interactive "sTitle: ")
(outline-wiki-post-request
"/api/collections.list"
`(("offset" . 0)
("limit" . 25))
(lambda (data)
(letrec ((collections (alist-get 'data data))
(cadi (mapcar (lambda (collection) (cons (cdr (assoc 'name collection)) (cons title collection) )) collections)))
(helm :sources (helm-build-sync-source "collections"
:candidates cadi
:action `(("new document in collection" . ,#'outline-wiki-doc-create )))
:buffer "*helm outline*"
:prompt "New Doc in: ")))))
;;;###autoload
(defun outline-wiki-doc-refresh ()
"Refresh current outline wiki doc."
(interactive)
(if (null outline-wiki-doc)
(message "no opened outline wiki")
(outline-wiki-doc-open-from-url (cdr (assoc 'id outline-wiki-doc)))))
;; (outline-wiki-doc-refresh)
(provide 'outline-wiki)
;;; outline-wiki.el ends here
加上一些案件映射设置,让一切更加丝滑,在buffer保存的时候自动到outline wiki。
;; 映射保存功能
(map! :map outline-wiki-mode-map
"s-s" #'outline-wiki-save)
(defun my-outline-wiki-save-command ()
"Save the file in outline-wiki-mode."
(interactive)
(call-interactively #'outline-wiki-save)
)
(defun my-evil-write (old-fun &rest args)
(if (bound-and-true-p outline-wiki-mode)
(my-outline-wiki-save-command)
(apply old-fun args)))
(advice-add #'evil-write :around #'my-evil-write)
;; 设置outline wiki的搜索快捷键
(map! :leader
:desc "outline wiki search"
"ows" #'helm-outline-wiki-search)
;; 设置outline wiki的文档新建
(map! :leader
:desc "outline wiki new doc"
"own" #'helm-outline-wiki-new)
;; 刷新当前的buffer中的文档
(map! :leader
:desc "outline wiki refresh"
"owr" #'outline-wiki-doc-refresh)