Make khoj.el pass checkdoc, package-lint, flycheck checks

- Add docstrings, mention args in them. Make docstring crisper
- prefix funcs, variables with khoj--
- Require emacs >27.1 for json-parse-buffer
- Use lexical binding
- Add quickstart docs to elisp file itself
- Bump version of khoj.el
This commit is contained in:
Debanjum Singh Solanky
2022-08-13 20:29:06 +03:00
parent 36dc2f619a
commit 541e03da3d

View File

@@ -1,10 +1,12 @@
;;; khoj.el --- Natural, Incremental Search via Emacs ;;; khoj.el --- Natural, Incremental Search for your Second Brain -*- lexical-binding: t -*-
;; Copyright (C) 2021-2022 Debanjum Singh Solanky ;; Copyright (C) 2021-2022 Debanjum Singh Solanky
;; Author: Debanjum Singh Solanky <debanjum@gmail.com> ;; Author: Debanjum Singh Solanky <debanjum@gmail.com>
;; Version: 2.0 ;; Description: Natural, Incremental Search for your Second Brain
;; Keywords: search, org-mode, outlines, markdown, image ;; Keywords: search, org-mode, outlines, markdown, beancount, ledger, image
;; Version: 2.1
;; Package-Requires: ((emacs "27.1"))
;; URL: http://github.com/debanjum/khoj/interface/emacs ;; URL: http://github.com/debanjum/khoj/interface/emacs
;; This file is NOT part of GNU Emacs. ;; This file is NOT part of GNU Emacs.
@@ -27,9 +29,20 @@
;;; Commentary: ;;; Commentary:
;; This package provides a natural, incremental search interface to your ;; This package provides a natural, incremental search interface to your
;; org-mode notes, markdown files, beancount transactions and images. ;; `org-mode' notes, `markdown' files, `beancount' transactions and images.
;; It is a wrapper that interfaces with transformer based ML models. ;; It is a wrapper that interfaces with the Khoj server.
;; The models search capabilities are exposed via the Khoj HTTP API. ;; The server exposes an API for advanced search using transformer ML models.
;; The Khoj server needs to be running to use this package.
;; See the repository docs for detailed setup of the Khoj server.
;;
;; Quickstart
;; -------------
;; 1. Install Khoj Server
;; pip install khoj-assistant
;; 2. Start, Configure Khoj Server
;; khoj
;; 3. Install khoj.el
;; (use-package khoj :bind ("C-c s" . 'khoj))
;;; Code: ;;; Code:
@@ -52,7 +65,7 @@
:type 'integer) :type 'integer)
(defcustom khoj-rerank-after-idle-time 2.0 (defcustom khoj-rerank-after-idle-time 2.0
"Idle time (in seconds) to trigger cross-encoder to rerank incremental search results." "Idle time (in seconds) to rerank incremental search results."
:group 'khoj :group 'khoj
:type 'float) :type 'float)
@@ -70,7 +83,7 @@
(const "music"))) (const "music")))
(defvar khoj--rerank-timer nil (defvar khoj--rerank-timer nil
"Idle timer to make cross-encoder re-rank incremental search results if user idle.") "Idle timer to re-rank incremental search results if user idle.")
(defvar khoj--minibuffer-window nil (defvar khoj--minibuffer-window nil
"Minibuffer window being used by user to enter query.") "Minibuffer window being used by user to enter query.")
@@ -85,6 +98,7 @@
"The type of content to perform search on.") "The type of content to perform search on.")
(defun khoj--keybindings-info-message () (defun khoj--keybindings-info-message ()
"Show available khoj keybindings in-context, when user invokes Khoj."
(let ((enabled-content-types (khoj--get-enabled-content-types))) (let ((enabled-content-types (khoj--get-enabled-content-types)))
(concat (concat
" "
@@ -101,13 +115,13 @@
(when (member 'music enabled-content-types) (when (member 'music enabled-content-types)
"C-x M | music\n")))) "C-x M | music\n"))))
(defun khoj--search-markdown () (interactive) (setq khoj--search-type "markdown")) (defun khoj--search-markdown () "Set search-type to 'markdown'." (interactive) (setq khoj--search-type "markdown"))
(defun khoj--search-org () (interactive) (setq khoj--search-type "org")) (defun khoj--search-org () "Set search-type to 'org-mode'." (interactive) (setq khoj--search-type "org"))
(defun khoj--search-ledger () (interactive) (setq khoj--search-type "ledger")) (defun khoj--search-ledger () "Set search-type to 'ledger'." (interactive) (setq khoj--search-type "ledger"))
(defun khoj--search-images () (interactive) (setq khoj--search-type "image")) (defun khoj--search-images () "Set search-type to image." (interactive) (setq khoj--search-type "image"))
(defun khoj--search-music () (interactive) (setq khoj--search-type "music")) (defun khoj--search-music () "Set search-type to music." (interactive) (setq khoj--search-type "music"))
(defun khoj--make-search-keymap (&optional existing-keymap) (defun khoj--make-search-keymap (&optional existing-keymap)
"Setup keymap to configure Khoj search" "Setup keymap to configure Khoj search. Build of EXISTING-KEYMAP when passed."
(let ((enabled-content-types (khoj--get-enabled-content-types)) (let ((enabled-content-types (khoj--get-enabled-content-types))
(kmap (or existing-keymap (make-sparse-keymap)))) (kmap (or existing-keymap (make-sparse-keymap))))
(when (member 'markdown enabled-content-types) (when (member 'markdown enabled-content-types)
@@ -121,6 +135,8 @@
(when (member 'music enabled-content-types) (when (member 'music enabled-content-types)
(define-key kmap (kbd "C-x M") #'khoj--search-music)) (define-key kmap (kbd "C-x M") #'khoj--search-music))
kmap)) kmap))
(defvar khoj--keymap nil "Track Khoj keymap in this variable.")
(defun khoj--display-keybinding-info () (defun khoj--display-keybinding-info ()
"Display information on keybindings to customize khoj search. "Display information on keybindings to customize khoj search.
Use `which-key` if available, else display simple message in echo area" Use `which-key` if available, else display simple message in echo area"
@@ -132,7 +148,7 @@ Use `which-key` if available, else display simple message in echo area"
(message "%s" (khoj--keybindings-info-message)))) (message "%s" (khoj--keybindings-info-message))))
(defun khoj--extract-entries-as-markdown (json-response query) (defun khoj--extract-entries-as-markdown (json-response query)
"Convert json response from API to markdown entries" "Convert JSON-RESPONSE, QUERY from API to markdown entries."
;; remove leading (, ) or SPC from extracted entries string ;; remove leading (, ) or SPC from extracted entries string
(replace-regexp-in-string (replace-regexp-in-string
"^[\(\) ]" "" "^[\(\) ]" ""
@@ -147,7 +163,7 @@ Use `which-key` if available, else display simple message in echo area"
json-response)))) json-response))))
(defun khoj--extract-entries-as-org (json-response query) (defun khoj--extract-entries-as-org (json-response query)
"Convert json response from API to org-mode entries" "Convert JSON-RESPONSE, QUERY from API to 'org-mode' entries."
;; remove leading (, ) or SPC from extracted entries string ;; remove leading (, ) or SPC from extracted entries string
(replace-regexp-in-string (replace-regexp-in-string
"^[\(\) ]" "" "^[\(\) ]" ""
@@ -162,7 +178,7 @@ Use `which-key` if available, else display simple message in echo area"
json-response)))) json-response))))
(defun khoj--extract-entries-as-images (json-response query) (defun khoj--extract-entries-as-images (json-response query)
"Convert json response from API to html with images" "Convert JSON-RESPONSE, QUERY from API to html with images."
;; remove leading (, ) or SPC from extracted entries string ;; remove leading (, ) or SPC from extracted entries string
(replace-regexp-in-string (replace-regexp-in-string
"[\(\) ]$" "" "[\(\) ]$" ""
@@ -188,7 +204,7 @@ Use `which-key` if available, else display simple message in echo area"
json-response))))) json-response)))))
(defun khoj--extract-entries-as-ledger (json-response query) (defun khoj--extract-entries-as-ledger (json-response query)
"Convert json response from API to ledger entries" "Convert JSON-RESPONSE, QUERY from API to ledger entries."
;; remove leading (, ) or SPC from extracted entries string ;; remove leading (, ) or SPC from extracted entries string
(replace-regexp-in-string (replace-regexp-in-string
"[\(\) ]$" "" "[\(\) ]$" ""
@@ -203,6 +219,7 @@ Use `which-key` if available, else display simple message in echo area"
json-response))))) json-response)))))
(defun khoj--buffer-name-to-search-type (buffer-name) (defun khoj--buffer-name-to-search-type (buffer-name)
"Infer search type based on BUFFER-NAME."
(let ((enabled-content-types (khoj--get-enabled-content-types)) (let ((enabled-content-types (khoj--get-enabled-content-types))
(file-extension (file-name-extension buffer-name))) (file-extension (file-name-extension buffer-name)))
(cond (cond
@@ -213,7 +230,7 @@ Use `which-key` if available, else display simple message in echo area"
(t khoj-default-search-type)))) (t khoj-default-search-type))))
(defun khoj--get-enabled-content-types () (defun khoj--get-enabled-content-types ()
"Get content types enabled for search from API" "Get content types enabled for search from API."
(let ((config-url (format "%s/config/data" khoj-server-url))) (let ((config-url (format "%s/config/data" khoj-server-url)))
(with-temp-buffer (with-temp-buffer
(erase-buffer) (erase-buffer)
@@ -228,11 +245,14 @@ Use `which-key` if available, else display simple message in echo area"
content-type)))))) content-type))))))
(defun khoj--construct-api-query (query search-type &optional rerank) (defun khoj--construct-api-query (query search-type &optional rerank)
"Construct API Query from QUERY, SEARCH-TYPE and (optional) RERANK params."
(let ((rerank (or rerank "false")) (let ((rerank (or rerank "false"))
(encoded-query (url-hexify-string query))) (encoded-query (url-hexify-string query)))
(format "%s/search?q=%s&t=%s&r=%s&n=%s" khoj-server-url encoded-query search-type rerank khoj-results-count))) (format "%s/search?q=%s&t=%s&r=%s&n=%s" khoj-server-url encoded-query search-type rerank khoj-results-count)))
(defun khoj--query-api-and-render-results (query search-type query-url buffer-name) (defun khoj--query-api-and-render-results (query search-type query-url buffer-name)
"Query Khoj API using QUERY, SEARCH-TYPE, QUERY-URL.
Render results in BUFFER-NAME."
;; get json response from api ;; get json response from api
(with-current-buffer buffer-name (with-current-buffer buffer-name
(let ((inhibit-read-only t)) (let ((inhibit-read-only t))
@@ -260,8 +280,8 @@ Use `which-key` if available, else display simple message in echo area"
(read-only-mode t))) (read-only-mode t)))
;; Incremental Search on Khoj
(defun khoj--incremental-search (&optional rerank) (defun khoj--incremental-search (&optional rerank)
"Perform Incremental Search on Khoj. Allow optional RERANK of results."
(let* ((rerank-str (cond (rerank "true") (t "false"))) (let* ((rerank-str (cond (rerank "true") (t "false")))
(khoj-buffer-name (get-buffer-create khoj--buffer-name)) (khoj-buffer-name (get-buffer-create khoj--buffer-name))
(query (minibuffer-contents-no-properties)) (query (minibuffer-contents-no-properties))
@@ -281,8 +301,8 @@ Use `which-key` if available, else display simple message in echo area"
query-url query-url
khoj-buffer-name))))) khoj-buffer-name)))))
(defun delete-open-network-connections-to-khoj () (defun khoj--delete-open-network-connections-to-server ()
"Delete all network connections to khoj server" "Delete all network connections to khoj server."
(dolist (proc (process-list)) (dolist (proc (process-list))
(let ((proc-buf (buffer-name (process-buffer proc))) (let ((proc-buf (buffer-name (process-buffer proc)))
(khoj-network-proc-buf (string-join (split-string khoj-server-url "://") " "))) (khoj-network-proc-buf (string-join (split-string khoj-server-url "://") " ")))
@@ -290,6 +310,7 @@ Use `which-key` if available, else display simple message in echo area"
(delete-process proc))))) (delete-process proc)))))
(defun khoj--teardown-incremental-search () (defun khoj--teardown-incremental-search ()
"Teardown timers and hooks used for incremental search."
(message "Khoj: Teardown Incremental Search") (message "Khoj: Teardown Incremental Search")
;; remove advice to rerank results on normal exit from minibuffer ;; remove advice to rerank results on normal exit from minibuffer
(advice-remove 'exit-minibuffer #'khoj--minibuffer-exit-advice) (advice-remove 'exit-minibuffer #'khoj--minibuffer-exit-advice)
@@ -298,19 +319,20 @@ Use `which-key` if available, else display simple message in echo area"
;; cancel rerank timer ;; cancel rerank timer
(when (timerp khoj--rerank-timer) (when (timerp khoj--rerank-timer)
(cancel-timer khoj--rerank-timer)) (cancel-timer khoj--rerank-timer))
;; delete open connections to khoj ;; delete open connections to khoj server
(delete-open-network-connections-to-khoj) (khoj--delete-open-network-connections-to-server)
;; remove hooks for khoj incremental query and self ;; remove hooks for khoj incremental query and self
(remove-hook 'post-command-hook #'khoj--incremental-search) (remove-hook 'post-command-hook #'khoj--incremental-search)
(remove-hook 'minibuffer-exit-hook #'khoj--teardown-incremental-search)) (remove-hook 'minibuffer-exit-hook #'khoj--teardown-incremental-search))
(defun khoj--minibuffer-exit-advice (&rest _args) (defun khoj--minibuffer-exit-advice (&rest _args)
"Rerank results of incremental search on exiting minibuffer."
(khoj--incremental-search t)) (khoj--incremental-search t))
;;;###autoload ;;;###autoload
(defun khoj () (defun khoj ()
"Natural, Incremental Search for your personal notes, transactions and music using Khoj" "Natural, Incremental Search for your personal notes, transactions and music."
(interactive) (interactive)
(let* ((khoj-buffer-name (get-buffer-create khoj--buffer-name))) (let* ((khoj-buffer-name (get-buffer-create khoj--buffer-name)))
;; set khoj search type to last used or based on current buffer ;; set khoj search type to last used or based on current buffer
@@ -337,7 +359,7 @@ Use `which-key` if available, else display simple message in echo area"
;;;###autoload ;;;###autoload
(defun khoj-simple (query) (defun khoj-simple (query)
"Natural Search for QUERY in your personal notes, transactions, music and images using Khoj" "Natural Search for QUERY on your personal notes, transactions, music and images."
(interactive "s🦅Khoj: ") (interactive "s🦅Khoj: ")
(let* ((rerank "true") (let* ((rerank "true")
(default-type (khoj--buffer-name-to-search-type (buffer-name))) (default-type (khoj--buffer-name-to-search-type (buffer-name)))