From 44bbc0a417b5f37275034dc7b029ce6658674218 Mon Sep 17 00:00:00 2001 From: Debanjum Singh Solanky Date: Thu, 19 Jan 2023 23:36:54 -0300 Subject: [PATCH 1/4] Add section separators to khoj.el for easier code traversal --- src/interface/emacs/khoj.el | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/interface/emacs/khoj.el b/src/interface/emacs/khoj.el index a36221b3..da366dbd 100644 --- a/src/interface/emacs/khoj.el +++ b/src/interface/emacs/khoj.el @@ -50,7 +50,7 @@ (require 'json) (require 'transient) - + ;; ------------------------- ;; Khoj Static Configuration ;; ------------------------- @@ -84,7 +84,7 @@ (const "image") (const "music"))) - + ;; -------------------------- ;; Khoj Dynamic Configuration ;; -------------------------- @@ -160,7 +160,7 @@ Use `which-key` if available, else display simple message in echo area" nil t t)) (message "%s" (khoj--keybindings-info-message)))) - + ;; ----------------------------------------------- ;; Extract and Render Entries of each Content Type ;; ----------------------------------------------- @@ -247,7 +247,7 @@ Use `which-key` if available, else display simple message in echo area" ((and (member 'markdown enabled-content-types) (or (equal file-extension "markdown") (equal file-extension "md"))) "markdown") (t khoj-default-content-type)))) - + ;; -------------- ;; Query Khoj API ;; -------------- @@ -304,7 +304,7 @@ Render results in BUFFER-NAME." (t (fundamental-mode)))) (read-only-mode t))) - + ;; ------------------ ;; Incremental Search ;; ------------------ @@ -379,6 +379,7 @@ Render results in BUFFER-NAME." (read-string khoj--query-prompt)))) + ;; --------- ;; Khoj Menu ;; --------- @@ -424,7 +425,7 @@ Render results in BUFFER-NAME." ("u" "Update" khoj--update-command) ("q" "Quit" transient-quit-one)]]) - + ;; ---------- ;; Entrypoint ;; ---------- From 17aaadea1fb013d20e0f9453e0ec288fac60faa7 Mon Sep 17 00:00:00 2001 From: Debanjum Singh Solanky Date: Fri, 20 Jan 2023 05:14:16 -0300 Subject: [PATCH 2/4] Find notes similar to current org entry at point --- src/interface/emacs/khoj.el | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/interface/emacs/khoj.el b/src/interface/emacs/khoj.el index da366dbd..b64b4e72 100644 --- a/src/interface/emacs/khoj.el +++ b/src/interface/emacs/khoj.el @@ -378,6 +378,43 @@ Render results in BUFFER-NAME." (add-hook 'minibuffer-exit-hook #'khoj--teardown-incremental-search)) ; teardown khoj incremental search on minibuffer exit (read-string khoj--query-prompt)))) + +;; -------------- +;; Similar Search +;; -------------- + +(defun khoj--get-current-org-entry-text () + "Get text in org entry at point." + (with-current-buffer (current-buffer) + (org-with-wide-buffer + ;; jump to cursor in current buffer + (goto-char (point)) + ;; trim trailing whitespaces from text + (replace-regexp-in-string + "[ \t\n]*$" "" + ;; get text of current entry + (save-excursion + ;; jump to heading of current entry + (org-back-to-heading t) + ;; get text of current entry using org-element-at-point + (buffer-substring-no-properties + (org-element-property :begin (org-element-at-point)) + (org-element-property :end (org-element-at-point)))))))) + +(defun khoj--find-similar-notes () + "Search for org entries similar to entry at point." + (let* ((rerank "true") + (content-type (khoj--buffer-name-to-content-type (buffer-name))) + (query (khoj--get-current-org-entry-text)) + (query-url (khoj--construct-api-query query content-type rerank)) + (buffer-name (get-buffer-create khoj--buffer-name))) + (khoj--query-api-and-render-results + ;; extract headline from query string containing org-entry + (replace-regexp-in-string "^\\** " "" (car (split-string query "\n"))) + content-type + query-url + buffer-name) + (switch-to-buffer buffer-name))) ;; --------- @@ -403,6 +440,11 @@ Render results in BUFFER-NAME." ;; trigger incremental search (call-interactively #'khoj-incremental))) +(transient-define-suffix khoj--find-similar-command (&optional _) + "Find other notes similar to current note at point." + (interactive) + (khoj--find-similar-notes)) + (transient-define-suffix khoj--update-command (&optional args) "Call khoj API to update index of specified content type." (interactive (list (transient-args transient-current-command))) @@ -422,6 +464,7 @@ Render results in BUFFER-NAME." ("-f" "Force Update" "--force-update")]] [["Act" ("s" "Search" khoj--search-command) + ("f" "Find Similar Notes" khoj--find-similar-command) ("u" "Update" khoj--update-command) ("q" "Quit" transient-quit-one)]]) From 936a88fa7e5f6e2293d7ad121f9c783b12f13fe4 Mon Sep 17 00:00:00 2001 From: Debanjum Singh Solanky Date: Fri, 20 Jan 2023 20:40:15 -0300 Subject: [PATCH 3/4] Find items of specified type similar to current text item at point - Support querying with text surrounding point in any text buffer Previously could only find items similar to org entry at point - Find similar items of specified content type indexed on khoj Previously only looked for similar org entries indexed on khoj Now uses the content-type configured in khoj transient menu to find items of the specified content type - Details - Generalize the get-current-org-entry-text func to get text for any outline section - Replace leading whitespaces from query text as well - Create method to get current paragraph text from non-outline mode buffers - Update transient, find-similar funcs to pass, use content-type configured in khoj transient menu - Generalize query title creation logic to remove markdown headings prefix (#) apart from org heading prefix (*) as well - Update last used khoj content-type and results from the find-similar and update funcs for later reuse - Jump to top of results buffer after results rendered --- src/interface/emacs/khoj.el | 103 ++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/src/interface/emacs/khoj.el b/src/interface/emacs/khoj.el index b64b4e72..2c2f4172 100644 --- a/src/interface/emacs/khoj.el +++ b/src/interface/emacs/khoj.el @@ -49,6 +49,7 @@ (require 'url) (require 'json) (require 'transient) +(require 'outline) ;; ------------------------- @@ -383,38 +384,66 @@ Render results in BUFFER-NAME." ;; Similar Search ;; -------------- -(defun khoj--get-current-org-entry-text () - "Get text in org entry at point." +(defun khoj--get-current-outline-entry-text () + "Get text under current outline section." (with-current-buffer (current-buffer) - (org-with-wide-buffer - ;; jump to cursor in current buffer - (goto-char (point)) + ;; jump to cursor in current buffer + (goto-char (point)) + ;; trim leading whitespaces from text + (replace-regexp-in-string + "^[ \t\n]*" "" ;; trim trailing whitespaces from text (replace-regexp-in-string "[ \t\n]*$" "" - ;; get text of current entry - (save-excursion - ;; jump to heading of current entry - (org-back-to-heading t) - ;; get text of current entry using org-element-at-point - (buffer-substring-no-properties - (org-element-property :begin (org-element-at-point)) - (org-element-property :end (org-element-at-point)))))))) + ;; get text of current outline entry + (buffer-substring-no-properties + (save-excursion (outline-previous-heading) (point)) + (save-excursion (outline-next-heading) (point))))))) -(defun khoj--find-similar-notes () - "Search for org entries similar to entry at point." +(defun khoj--get-current-paragraph-text () + "Get text in current paragraph at point." + (with-current-buffer (current-buffer) + ;; jump to cursor in current buffer + (goto-char (point)) + ;; trim leading whitespaces from text + (replace-regexp-in-string + "^[ \t\n]*" "" + ;; trim trailing whitespaces from text + (replace-regexp-in-string + "[ \t\n]*$" "" + ;; get text of current entry + (buffer-substring-no-properties + (save-excursion (backward-paragraph) (point)) + (save-excursion (forward-paragraph) (point))))))) + +(defun khoj--find-similar (&optional content-type) + "Find items of CONTENT-TYPE in khoj index similar to text surrounding point." + (interactive) (let* ((rerank "true") - (content-type (khoj--buffer-name-to-content-type (buffer-name))) - (query (khoj--get-current-org-entry-text)) + ;; set content type to: specified > based on current buffer > default type + (content-type (or content-type (khoj--buffer-name-to-content-type (buffer-name)))) + ;; get text surrounding current point based on the major mode context + (query (cond + ;; get section outline derived mode like org or markdown + ((or (derived-mode-p 'outline-mode) (equal major-mode 'markdown-mode)) + (khoj--get-current-outline-entry-text)) + ;; get paragraph, if in text mode + (t + (khoj--get-current-paragraph-text)))) (query-url (khoj--construct-api-query query content-type rerank)) + ;; extract heading to show in result buffer from query + (query-title + (format "Similar to: %s" + (replace-regexp-in-string "^[#\\*]* " "" (car (split-string query "\n"))))) (buffer-name (get-buffer-create khoj--buffer-name))) - (khoj--query-api-and-render-results - ;; extract headline from query string containing org-entry - (replace-regexp-in-string "^\\** " "" (car (split-string query "\n"))) - content-type - query-url - buffer-name) - (switch-to-buffer buffer-name))) + (progn + (khoj--query-api-and-render-results + query-title + content-type + query-url + buffer-name) + (switch-to-buffer buffer-name) + (goto-char (point-min))))) ;; --------- @@ -425,7 +454,7 @@ Render results in BUFFER-NAME." :class 'transient-switches :argument-format "--content-type=%s" :argument-regexp ".+" - ;; set content type to last used or based on current buffer or to default + ;; set content type to: last used > based on current buffer > default type :init-value (lambda (obj) (oset obj value (format "--content-type=%s" (or khoj--content-type (khoj--buffer-name-to-content-type (buffer-name)))))) ;; dynamically set choices to content types enabled on khoj backend :choices (or (ignore-errors (mapcar #'symbol-name (khoj--get-enabled-content-types))) '("org" "markdown" "ledger" "music" "image"))) @@ -433,26 +462,34 @@ Render results in BUFFER-NAME." (transient-define-suffix khoj--search-command (&optional args) (interactive (list (transient-args transient-current-command))) (progn - ;; set content type to last used or based on current buffer or to default + ;; set content type to: specified > last used > based on current buffer > default type (setq khoj--content-type (or (transient-arg-value "--content-type=" args) (khoj--buffer-name-to-content-type (buffer-name)))) - ;; set results count to last used or to default + ;; set results count to: specified > last used > to default (setq khoj-results-count (or (transient-arg-value "--results-count=" args) khoj-results-count)) ;; trigger incremental search (call-interactively #'khoj-incremental))) -(transient-define-suffix khoj--find-similar-command (&optional _) - "Find other notes similar to current note at point." - (interactive) - (khoj--find-similar-notes)) +(transient-define-suffix khoj--find-similar-command (&optional args) + "Find items similar to current item at point." + (interactive (list (transient-args transient-current-command))) + (progn + ;; set content type to: specified > last used > based on current buffer > default type + (setq khoj--content-type (or (transient-arg-value "--content-type=" args) (khoj--buffer-name-to-content-type (buffer-name)))) + ;; set results count to: specified > last used > to default + (setq khoj-results-count (or (transient-arg-value "--results-count=" args) khoj-results-count)) + (khoj--find-similar khoj--content-type))) (transient-define-suffix khoj--update-command (&optional args) "Call khoj API to update index of specified content type." (interactive (list (transient-args transient-current-command))) (let* ((force-update (if (member "--force-update" args) "true" "false")) + ;; set content type to: specified > last used > based on current buffer > default type (content-type (or (transient-arg-value "--content-type=" args) (khoj--buffer-name-to-content-type (buffer-name)))) (update-url (format "%s/api/update?t=%s&force=%s" khoj-server-url content-type force-update)) (url-request-method "GET")) - (url-retrieve update-url (lambda (_) (message "Khoj %s index %supdated!" content-type (if (member "--force-update" args) "force " "")))))) + (progn + (setq khoj--content-type content-type) + (url-retrieve update-url (lambda (_) (message "Khoj %s index %supdated!" content-type (if (member "--force-update" args) "force " ""))))))) (transient-define-prefix khoj-menu () "Create Khoj Menu to Configure and Execute Commands." @@ -464,7 +501,7 @@ Render results in BUFFER-NAME." ("-f" "Force Update" "--force-update")]] [["Act" ("s" "Search" khoj--search-command) - ("f" "Find Similar Notes" khoj--find-similar-command) + ("f" "Find Similar" khoj--find-similar-command) ("u" "Update" khoj--update-command) ("q" "Quit" transient-quit-one)]]) From b7aa22a059de8c6c492bde44c46d007db749fdcb Mon Sep 17 00:00:00 2001 From: Debanjum Singh Solanky Date: Fri, 20 Jan 2023 22:11:00 -0300 Subject: [PATCH 4/4] Change order of arg passed to query-api-and-render-results by importance --- src/interface/emacs/khoj.el | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/interface/emacs/khoj.el b/src/interface/emacs/khoj.el index 2c2f4172..c4a60e57 100644 --- a/src/interface/emacs/khoj.el +++ b/src/interface/emacs/khoj.el @@ -275,9 +275,8 @@ Use `which-key` if available, else display simple message in echo area" (encoded-query (url-hexify-string query))) (format "%s/api/search?q=%s&t=%s&r=%s&n=%s" khoj-server-url encoded-query content-type rerank khoj-results-count))) -(defun khoj--query-api-and-render-results (query content-type query-url buffer-name) - "Query Khoj API using QUERY, CONTENT-TYPE, QUERY-URL. -Render results in BUFFER-NAME." +(defun khoj--query-api-and-render-results (query-url content-type query buffer-name) + "Query Khoj QUERY-URL. Render results in BUFFER-NAME using QUERY, CONTENT-TYPE." ;; get json response from api (with-current-buffer buffer-name (let ((inhibit-read-only t) @@ -335,9 +334,9 @@ Render results in BUFFER-NAME." (setq khoj--rerank t) (message "Khoj: Rerank Results")) (khoj--query-api-and-render-results - query - khoj--content-type query-url + khoj--content-type + query khoj-buffer-name)))))) (defun khoj--delete-open-network-connections-to-server () @@ -438,9 +437,9 @@ Render results in BUFFER-NAME." (buffer-name (get-buffer-create khoj--buffer-name))) (progn (khoj--query-api-and-render-results - query-title - content-type query-url + content-type + query-title buffer-name) (switch-to-buffer buffer-name) (goto-char (point-min)))))