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
This commit is contained in:
Debanjum Singh Solanky
2023-01-20 20:40:15 -03:00
parent 17aaadea1f
commit 936a88fa7e

View File

@@ -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)]])