Emacsでノート閲覧システムを構築する試み


Emacsにプラグインを書くのは痛くて楽しい感じがします.このアイデアを生かす過程は面白いですが、Elispは書くといつも違和感があります.一方、私はそれをCommon Lispと見なし、「この使い方に問題があるかもしれない」とは思わなかった.一方,通常のlispコードではなく,書きながらEmacsのいくつかの概念を模索する.しかし、全体的には、まともなREPLがない以外は面白いです.

いきさつ


私はEmacsで多くの「ノート」を記録した.私自身はそれをノートと呼んでいますが、それらは私が出会ったいくつかの問題と解決方法を記録したように、あまり自分の悟りがありません.それらの外観は高さの一致で、下図を参照してください.
(初めて自分の画像に透かしを打ってみましたが、ちょっと面白いです)各レベルのエントリは問題で、このファイルには1レベルのエントリしかありません.項目の下の内容はタイトルの質問に対する答えです.中にはBEGIN_と書かれたコードブロックもありますSRCとEND_SRCの部分.ノートをorg-modeで記録するにはいくつかのメリットがあります.その1つは、ノートにEmacsがサポートするプログラミング言語コードのクリップを挿入し、構文のハイライトを備えていることです.もちろん、org-modeは花の中で口笛のように見えますが、骨の中は正統な純粋なテキストファイルで、他のツールで簡単に処理できます.
私が処理するためのツールの一つはElasticSearchです.例えば、上図の最初のメモは、ElasticSearchに次のような構造で保存されています.
もともとAlfredのWorkflowを書いてElasticSearchを検索していましたが、どうやってWorkflowのような1行でorg-mode形式のノートを表示するのはあまり友好的ではないので、Emacsで直接ノートの内容を検索して表示するつもりです.

牛刀小試


Emacsでノートの内容を確認できるように、Helmの力を借りるつもりです.HelmはEmacsの補完フレームワークで、一連の候補を表示し、選択した後に何かをトリガーすることができます.私が望んでいる形式は、Emacsでショートカットキーを押すか、コマンドラインを入力してminibufferに自分がクエリーする内容を入力し、EmacsがElasticSearchをクエリーし、最終的にHelmを通じてこれらのクエリーの内容が一致するメモエントリを表示することです.現在の成果は次のようなものです.
具体的なやり方も実は簡単です.まず、Helmがどのように使われているかを知る必要があります.この文書では、変数を1つ特定し、:sourcesのキーワードパラメータを介してhelmという関数に渡すだけでよいことが初歩的に理解されています.私が定義したhelm関数に渡す「source」は以下の通りです.
(setq faq-helm-sources
      `((name . "FAQ at Emacs")
        (candidates . faq-candidates)
        (action . (lambda (candidate)
                    (let ((url (format "http://localhost:9200/faq/_doc/%s" candidate)))
                      (browse-url url))))))
faq-candidatesの役割は、minibufferのキーワードに基づいてElasticSearchを問合せ、構造を組織してhelmに返すことです.faq-candidatesは、パラメータのない関数でなければなりませんが、入力されたデータはminibufferから取得する必要があります.したがって、私のやり方は、faq-queryを呼び出す前にhelm関数を呼び出して入力を読み出し、入力した文字列をread-from-minibufferに割り当て、faq-queryがこのsourceを使用し始めると、helm関数はパラメータを必要とせず、faq-candidatesから自分の必要な検索内容を直接取得してElasticSearchに要求することができます.もちろん、Common Lispのようなダイナミックなドメインがあれば、このようなグローバル変数を定義する必要はありません.Emacsグローバルへの侵入はさらに少なくなります.
現在できることは、ElasticSearchを検索し、エントリを選択して車に戻るときにブラウザを開いて表示することだけで、その後も改善されるはずです.現在の完全なコードは次のとおりです.
;;;  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 '_id doc)))))
            hits)))

(defvar faq-query nil)

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

(setq faq-helm-sources
      `((name . "FAQ at Emacs")
        (candidates . faq-candidates)
        (action . (lambda (candidate)
                    (let ((url (format "http://localhost:9200/faq/_doc/%s" candidate)))
                      (browse-url url))))))

(defun lt-ask ()
  " minibuffer "
  (interactive)
  (let ((content (read-from-minibuffer " :")))
    (setq faq-query content)
    (helm :sources '(faq-helm-sources))))

ツッコミどころはいろいろありますが、まずは押して表に出さないようにしましょう.読者の皆さんが興味があれば、伝言を残してXDを交流してもいいです.
原文を読む