改良在Emacs中瀏覽筆記的方式

「實戰Elisp」系列旨在講述我使用Elisp定製Emacs的經驗,拋磚引玉,還請廣大Emacs同好不吝賜教——若是真的有廣大Emacs用戶的話,哈哈哈。

半年前我在這篇文章中展現了在Emacs中查閱筆記的效果——用emacs-request請求ElasticSearch查詢關鍵字、基於helm如下拉菜單的方式展現查詢結果的標題(即問題),最後打開瀏覽器查看筆記內容。稍加使用就發現一些不足之處:git

  1. 須要離開Emacs打開瀏覽器。我更但願能在Emacs中查看;
  2. ES的響應內容爲JSON,要快速地辨認出questionanswer字段比較困難;
  3. 一個問題的答案每每是多行的,但在瀏覽器中answer字段是以一行的形式展現的,不利於閱讀。

爲了解決這些問題,我實現了一種新的查看筆記內容的方式。github

改良後的效果

image

實現方法

個人目標是:json

  1. 在不脫離Emacs的狀況下瀏覽筆記內容;
  2. 提供org-mode的語法高亮。

爲此,先用被選中筆記的_id請求ES,取回完整的JSON。接着,將_source中的questionanswer字段的內容拼接在一塊兒(以\n做爲分隔符)。最後,在Emacs中新建一個buffer、啓用org-mode、插入拼接後的內容,並設置該buffer爲只讀。大功告成!瀏覽器

完整的代碼以下app

;;; 調用ElasticSearch查詢筆記
(require 'request)

(defun faq (query)
  "向ElasticSearch查詢QUERY匹配的筆記"
  (let ((response))
    (request
     "http://localhost:9200/faq/_search"
     :data (encode-coding-string
            (json-encode
             (list
              (cons "query" (list
                             (cons "multi_match" (list
                                                  (cons "fields" (list "answer" "question"))
                                                  (cons "query" query)))))))
            'utf-8)
     :headers '(("Content-Type" . "application/json"))
     :parser 'buffer-string
     :success (cl-function
               (lambda (&key data &allow-other-keys)
                 (setq data (decode-coding-string data 'utf-8))
                 (setq response (json-read-from-string data))))
     :sync t)
    response))

(defun make-faq-candidates (response)
  "將查詢ElasticSearch的結果構造爲helm能夠識別的candidates格式"
  (let ((hits (cdr (assoc 'hits (cdr (assoc 'hits response))))))
    (mapcar (lambda (doc)
              (let ((_source (cdr (assoc '_source doc))))
                (cons (cdr (assoc 'question _source))
                      ;; (cdr (assoc 'answer (assoc '_source doc)))
                      (cdr (assoc '_id doc)))))
            hits)))

(defvar faq-query nil)

(defun faq-candidates ()
  (make-faq-candidates (faq faq-query)))

;;; 建立新的buffer並將ElasticSearch的內容展現在其中
(defun show-faq (text)
  ;; 建立一個buffer,顯示它並選中這個窗口
  (let ((buffer (get-buffer-create "*FAQ*")))
    (let ((window (display-buffer buffer)))
      (select-window window)
      ;; 用新的內容覆蓋原來的內容
      (setq inhibit-read-only t)
      (org-mode)
      (erase-buffer)
      (insert text)
      (read-only-mode))))

(setq faq-helm-sources
      `((name . "FAQ at Emacs")
        (candidates . faq-candidates)
        (action . (lambda (candidate)
                    (let (response
                          (url (format "http://localhost:9200/faq/_doc/%s" candidate)))
                      (message "url is %s" url)
                      (request
                       url
                       :parser 'buffer-string
                       :success (cl-function
                                 (lambda (&key data &allow-other-keys)
                                   (setq data (decode-coding-string data 'utf-8))
                                   (setq response (json-read-from-string data))))
                       :sync t)
                      ;; 從文檔中提取出問題和答案,拼裝成本來在.org文件中的模樣
                      (let ((answer (cdr (assoc 'answer (assoc '_source response))))
                            (question (cdr (assoc 'question (assoc '_source response)))))
                        (show-faq
                         (concat question "\n" answer))))))))

(defun lt-ask ()
  "交互式地從minibuffer中讀取筆記的關鍵詞並展現選項"
  (interactive)
  (let ((content (read-from-minibuffer "筆記關鍵詞:")))
    (setq faq-query content)
    (helm :sources '(faq-helm-sources))))

與以前版本的差別主要在於:函數

  1. 變量faq-helm-sources中的action部分多了不少內容,主要是請求ES和拼接字段;
  2. 新增了show-faq函數用於顯示問題及其答案。

後記

挺好奇各位讀者朋友是怎麼記筆記和看筆記的XDui

閱讀原文url

相關文章
相關標籤/搜索