From 1b759597dfc1fcfec27e9fef1e2e4a992ddf4abb Mon Sep 17 00:00:00 2001 From: Debanjum Singh Solanky Date: Wed, 27 Jul 2022 20:08:37 +0400 Subject: [PATCH] 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 --- src/interface/emacs/khoj.el | 54 +++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/interface/emacs/khoj.el b/src/interface/emacs/khoj.el index 90562bf7..a31cb3bc 100644 --- a/src/interface/emacs/khoj.el +++ b/src/interface/emacs/khoj.el @@ -36,6 +36,7 @@ (require 'url) (require 'json) + (defcustom khoj--server-url "http://localhost:8000" "Location of Khoj API server." :group 'khoj @@ -59,12 +60,16 @@ (defvar khoj--rerank-timer nil "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: " "Query prompt shown to user in the minibuffer.") (defvar khoj--search-type "org" "The type of content to perform search on.") + (defun khoj--extract-entries-as-markdown (json-response query) "Convert json response from API to markdown entries" ;; remove leading (, ) or SPC from extracted entries string @@ -170,24 +175,33 @@ (t (fundamental-mode)))) (read-only-mode t))) + ;; Incremental Search on Khoj -(defun khoj--incremental-query (&optional rerank) - (let* ((rerank (cond (rerank "true") (t "false"))) +(defun khoj--incremental-search (&optional rerank) + (let* ((rerank-str (cond (rerank "true") (t "false"))) (search-type khoj--search-type) (buffer-name (get-buffer-create (format "*Khoj (t:%s)*" search-type))) (query (minibuffer-contents-no-properties)) - (query-url (khoj--construct-api-query query search-type rerank))) - (khoj--query-api-and-render-results - query - search-type - query-url - buffer-name))) + (query-url (khoj--construct-api-query query search-type rerank-str))) + ;; Query khoj API only when user in khoj minibuffer. + ;; Prevents querying during recursive edits or with contents of other buffers user may jump to + (when (and (active-minibuffer-window) (equal (current-buffer) khoj--minibuffer-window)) + (khoj--query-api-and-render-results + 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 (defun khoj () @@ -197,17 +211,23 @@ (search-type (completing-read "Type: " '("org" "markdown" "ledger" "music") nil t default-type)) (buffer-name (get-buffer-create (format "*Khoj (t:%s)*" 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) + ;; open and setup minibuffer for incremental search (minibuffer-with-setup-hook (lambda () - (add-hook 'post-command-hook #'khoj--incremental-query nil 'local) - (add-hook 'minibuffer-exit-hook #'khoj--remove-incremental-query nil 'local)) + ;; set current (mini-)buffer entered as khoj minibuffer + ;; 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)))) ;;;###autoload (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: ") (let* ((rerank "true") (default-type (khoj--buffer-name-to-search-type (buffer-name)))