Contents

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)