Make incremental search more robust. Follow standard user expectations

- Rename functions to more standard, descriptive names
- Keep known, required code for incremental search
  - E.g Do not set buffer local flag in hooks on minibuffer setup

- Only query when user in khoj minibuffer
  - Use active-minibuffer-window and track khoj minibuffer
  - (minibuffer-prompt) is not useful for our use-case here

- (For now) Run re-rank only if user idle while querying
  - Do not run rerank on teardown/completion
    - The reranking lag (~2s) is annoying; hit enter,
      wait to see results
    - Also triggered when user exits abnormally,
      so C-g also results in rerank which is even more annoying
  - Emacs will still hang if re-ranking gets triggered on idle but
    that's better than always getting triggered. And better than not
    having mechanism to get results re-ranked via cross-encoder at all
This commit is contained in:
Debanjum Singh Solanky 2022-07-27 20:08:37 +04:00
parent 9a6eee31be
commit 1b759597df

View file

@ -36,6 +36,7 @@
(require 'url) (require 'url)
(require 'json) (require 'json)
(defcustom khoj--server-url "http://localhost:8000" (defcustom khoj--server-url "http://localhost:8000"
"Location of Khoj API server." "Location of Khoj API server."
:group 'khoj :group 'khoj
@ -59,12 +60,16 @@
(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 make cross-encoder re-rank incremental search results if user idle.")
(defvar khoj--minibuffer-window nil
"Minibuffer window being used by user to enter query.")
(defconst khoj--query-prompt "Khoj: " (defconst khoj--query-prompt "Khoj: "
"Query prompt shown to user in the minibuffer.") "Query prompt shown to user in the minibuffer.")
(defvar khoj--search-type "org" (defvar khoj--search-type "org"
"The type of content to perform search on.") "The type of content to perform search on.")
(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 from API to markdown entries"
;; remove leading (, ) or SPC from extracted entries string ;; remove leading (, ) or SPC from extracted entries string
@ -170,24 +175,33 @@
(t (fundamental-mode)))) (t (fundamental-mode))))
(read-only-mode t))) (read-only-mode t)))
;; Incremental Search on Khoj ;; Incremental Search on Khoj
(defun khoj--incremental-query (&optional rerank) (defun khoj--incremental-search (&optional rerank)
(let* ((rerank (cond (rerank "true") (t "false"))) (let* ((rerank-str (cond (rerank "true") (t "false")))
(search-type khoj--search-type) (search-type khoj--search-type)
(buffer-name (get-buffer-create (format "*Khoj (t:%s)*" search-type))) (buffer-name (get-buffer-create (format "*Khoj (t:%s)*" search-type)))
(query (minibuffer-contents-no-properties)) (query (minibuffer-contents-no-properties))
(query-url (khoj--construct-api-query query search-type rerank))) (query-url (khoj--construct-api-query query search-type rerank-str)))
(khoj--query-api-and-render-results ;; Query khoj API only when user in khoj minibuffer.
query ;; Prevents querying during recursive edits or with contents of other buffers user may jump to
search-type (when (and (active-minibuffer-window) (equal (current-buffer) khoj--minibuffer-window))
query-url (khoj--query-api-and-render-results
buffer-name))) query
search-type
query-url
buffer-name))))
(defun khoj--teardown-incremental-search ()
;; unset khoj minibuffer window
(setq khoj--minibuffer-window nil)
;; cancel rerank timer
(when (timerp khoj--rerank-timer)
(cancel-timer khoj--rerank-timer))
;; remove hooks for khoj incremental query and self
(remove-hook 'post-command-hook #'khoj--incremental-search)
(remove-hook 'minibuffer-exit-hook #'khoj--teardown-incremental-search))
(defun khoj--remove-incremental-query ()
(khoj--incremental-query t)
(cancel-timer khoj--rerank-timer)
(remove-hook 'post-command-hook #'khoj--incremental-query)
(remove-hook 'minibuffer-exit-hook #'khoj--remove-incremental-query))
;;;###autoload ;;;###autoload
(defun khoj () (defun khoj ()
@ -197,17 +211,23 @@
(search-type (completing-read "Type: " '("org" "markdown" "ledger" "music") nil t default-type)) (search-type (completing-read "Type: " '("org" "markdown" "ledger" "music") nil t default-type))
(buffer-name (get-buffer-create (format "*Khoj (t:%s)*" search-type)))) (buffer-name (get-buffer-create (format "*Khoj (t:%s)*" search-type))))
(setq khoj--search-type search-type) (setq khoj--search-type search-type)
(setq khoj--rerank-timer (run-with-idle-timer khoj--rerank-after-idle-time t 'khoj--incremental-query t)) ;; setup rerank to improve results once user idle for KHOJ--RERANK-AFTER-IDLE-TIME seconds
(setq khoj--rerank-timer (run-with-idle-timer khoj--rerank-after-idle-time t 'khoj--incremental-search t))
;; switch to khoj results buffer
(switch-to-buffer buffer-name) (switch-to-buffer buffer-name)
;; open and setup minibuffer for incremental search
(minibuffer-with-setup-hook (minibuffer-with-setup-hook
(lambda () (lambda ()
(add-hook 'post-command-hook #'khoj--incremental-query nil 'local) ;; set current (mini-)buffer entered as khoj minibuffer
(add-hook 'minibuffer-exit-hook #'khoj--remove-incremental-query nil 'local)) ;; used to query khoj API only when user in khoj minibuffer
(setq khoj--minibuffer-window (current-buffer))
(add-hook 'post-command-hook #'khoj--incremental-search) ; do khoj incremental search after every user action
(add-hook 'minibuffer-exit-hook #'khoj--teardown-incremental-search)) ; teardown khoj incremental search on minibuffer exit
(read-string khoj--query-prompt)))) (read-string khoj--query-prompt))))
;;;###autoload ;;;###autoload
(defun khoj-simple (query) (defun khoj-simple (query)
"Natural Search for your personal notes, transactions, music and images using Khoj" "Natural Search for QUERY in your personal notes, transactions, music and images using Khoj"
(interactive "sQuery: ") (interactive "sQuery: ")
(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)))