Skip to content

Commit 7c46971

Browse files
author
Kang Tu
committed
Support any Org headline, not just TODO keywords, but not DONE
1 parent 7a23d39 commit 7c46971

3 files changed

Lines changed: 110 additions & 20 deletions

File tree

ai-code-change.el

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,8 @@ Returns (TEXT START-POS END-POS) if TODO found, nil otherwise."
147147
(let ((heading-line (buffer-substring-no-properties
148148
(line-beginning-position)
149149
(line-end-position))))
150-
(when (and (or (org-get-todo-state)
151-
(ai-code--implement-todo--org-todo-headline-p heading-line))
152-
(not (org-entry-is-done-p)))
150+
(when (and (not (org-entry-is-done-p))
151+
(not (string-match-p "^\\*+ DONE " heading-line)))
153152
(list heading-line
154153
(line-beginning-position)
155154
(line-end-position))))))))))
@@ -363,12 +362,9 @@ The plist contains `:heading-line', `:content', and `:line-number'."
363362
(let* ((line-number (line-number-at-pos (point)))
364363
(heading-line (buffer-substring-no-properties
365364
(line-beginning-position)
366-
(line-end-position)))
367-
(todo-state (org-get-todo-state))
368-
(todo-prefix-p
369-
(ai-code--implement-todo--org-todo-headline-p heading-line)))
370-
(when (and (or todo-state todo-prefix-p)
371-
(not (org-entry-is-done-p)))
365+
(line-end-position))))
366+
(when (and (not (org-entry-is-done-p))
367+
(not (string-match-p "^\\*+ DONE " heading-line)))
372368
(let* ((content-start (save-excursion
373369
(forward-line 1)
374370
(point)))
@@ -402,6 +398,7 @@ The plist contains `:heading-line', `:content', and `:line-number'."
402398
ARG is the prefix argument for clipboard context.
403399
Optional DEFAULT-ACTION skips the completing-read prompt when non-nil."
404400
;; DONE: ask user with completing-read before build up prompt, candidate should be 1. Code change; 2. Ask question. Given selection, add suffix to them respectively to indicate AI to make code change, or do not make any code change
401+
;; DONE: currently ai-code-implement-todo work on the org-mode TODO headline. But I want it be able to work on any org-mode headline, no matter it has TODO keyword or not. Please also update the ai-code-code-change and @ai-code-discussion.el#ai-code-ask-question, for the org headline detection code (currently only detect org TODO headline) to be consistent with this function.
405402
(let* ((clipboard-context (when arg (ai-code--get-clipboard-text)))
406403
(current-line (string-trim (thing-at-point 'line t)))
407404
(current-line-number (line-number-at-pos (point)))
@@ -440,7 +437,7 @@ Optional DEFAULT-ACTION skips the completing-read prompt when non-nil."
440437
(ai-code--is-comment-block region-text)))
441438
;; Validate scenario before prompting user
442439
(_ (unless (or org-todo-section-info region-text is-comment)
443-
(user-error "Current line is not a TODO comment or Org TODO headline and cannot proceed with `ai-code-implement-todo'. Please select a TODO comment (not DONE), an Org TODO headline, a region of comments, or activate on a blank line")))
440+
(user-error "Current line is not a TODO comment or Org headline and cannot proceed with `ai-code-implement-todo'. Please select a TODO comment (not DONE), an Org headline (not DONE), a region of comments, or activate on a blank line")))
444441
(_ (unless region-comment-block-p
445442
(user-error "Selected region must be a comment block")))
446443
(action-intent (or default-action
@@ -452,32 +449,32 @@ Optional DEFAULT-ACTION skips the completing-read prompt when non-nil."
452449
(cond
453450
((and ask-question-p org-todo-section-info)
454451
(if (and clipboard-context (string-match-p "\\S-" clipboard-context))
455-
"Question about Org TODO headline (clipboard context): "
456-
"Question about Org TODO headline: "))
452+
"Question about Org headline (clipboard context): "
453+
"Question about Org headline: "))
457454
(ask-question-p
458455
(if (and clipboard-context (string-match-p "\\S-" clipboard-context))
459456
"Question about TODO comment (clipboard context): "
460457
"Question about TODO comment: "))
461458
((and org-todo-section-info
462459
clipboard-context
463460
(string-match-p "\\S-" clipboard-context))
464-
"TODO implementation instruction for Org TODO headline (clipboard context): ")
461+
"Implementation instruction for Org headline (clipboard context): ")
465462
((and clipboard-context
466463
(string-match-p "\\S-" clipboard-context))
467464
(cond
468465
(region-text "TODO implementation instruction (clipboard context): ")
469466
(is-comment "TODO implementation instruction (clipboard context): ")
470467
(function-name (format "TODO implementation instruction for function %s (clipboard context): " function-name))
471468
(t "TODO implementation instruction (clipboard context): ")))
472-
(org-todo-section-info "TODO implementation instruction for Org TODO headline: ")
469+
(org-todo-section-info "Implementation instruction for Org headline: ")
473470
(region-text "TODO implementation instruction: ")
474471
(is-comment "TODO implementation instruction: ")
475472
(function-name (format "TODO implementation instruction for function %s: " function-name))
476473
(t "TODO implementation instruction: ")))
477474
(initial-input
478475
(cond
479476
((and ask-question-p org-todo-section-info)
480-
(format "Regarding this Org TODO headline on line %d:\n%s%s%s"
477+
(format "Regarding this Org headline on line %d:\n%s%s%s"
481478
org-line-number org-section-block function-context files-context-string))
482479
((and ask-question-p region-text)
483480
(format "Regarding this TODO comment block in the selected region:\n%s\n%s%s%s"
@@ -486,7 +483,7 @@ Optional DEFAULT-ACTION skips the completing-read prompt when non-nil."
486483
(format "Regarding this TODO comment on line %d: '%s'%s%s"
487484
current-line-number current-line function-context files-context-string))
488485
(org-todo-section-info
489-
(format "Please implement code for this Org TODO headline first. After implementing, keep the Org TODO headline in place and use the headline and content as prompt context.\nLine %d:\n%s%s%s"
486+
(format "Please implement code for this Org headline first. After implementing, keep the Org headline in place and use the headline and content as prompt context.\nLine %d:\n%s%s%s"
490487
org-line-number org-section-block function-context
491488
files-context-string))
492489
(region-text

test/test_ai-code-change.el

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ is between the function definition and its body."
577577
(ai-code-implement-todo nil)
578578

579579
(should (stringp captured-prompt))
580-
(should (string-match-p "Regarding this Org TODO headline" captured-prompt))
580+
(should (string-match-p "Regarding this Org headline" captured-prompt))
581581
(should (string-match-p "TODO: what is the most important verse in Bible"
582582
captured-prompt))))))
583583

@@ -611,17 +611,23 @@ is between the function definition and its body."
611611
(cl-letf (((symbol-function 'region-active-p) (lambda () nil)))
612612
(should-not (ai-code--detect-todo-info nil)))))
613613

614-
(ert-deftest ai-code-test-detect-todo-info-org-non-todo-headline-returns-nil ()
615-
"Test `ai-code--detect-todo-info' returns nil for non-TODO Org headlines."
614+
(ert-deftest ai-code-test-detect-todo-info-org-plain-headline-detected ()
615+
"Test `ai-code--detect-todo-info' detects plain Org headlines without TODO keyword."
616616
(with-temp-buffer
617617
(require 'org)
618618
(setq buffer-file-name "notes.org")
619619
(insert "* Regular heading\n")
620+
(insert "Some content.\n")
620621
(org-mode)
621622
(goto-char (point-min))
622623

623624
(cl-letf (((symbol-function 'region-active-p) (lambda () nil)))
624-
(should-not (ai-code--detect-todo-info nil)))))
625+
(let ((result (ai-code--detect-todo-info nil)))
626+
(should result)
627+
(should (stringp (nth 0 result)))
628+
(should (string-match-p "Regular heading" (nth 0 result)))
629+
(should (integerp (nth 1 result)))
630+
(should (integerp (nth 2 result)))))))
625631

626632
(ert-deftest ai-code-test-detect-todo-info-org-todo-colon-prefix ()
627633
"Test `ai-code--detect-todo-info' detects `TODO:' prefixed Org headlines."
@@ -721,6 +727,71 @@ is between the function definition and its body."
721727

722728
(should (equal captured-default-action "Code change"))))))
723729

730+
(ert-deftest ai-code-test-get-org-section-info-plain-headline ()
731+
"Test `ai-code--implement-todo--get-org-todo-section-info' returns info for plain Org headline."
732+
(with-temp-buffer
733+
(require 'org)
734+
(setq buffer-file-name "notes.org")
735+
(insert "* Regular heading\n")
736+
(insert "Some content.\n")
737+
(org-mode)
738+
(goto-char (point-min))
739+
740+
(let ((result (ai-code--implement-todo--get-org-todo-section-info)))
741+
(should result)
742+
(should (string-match-p "Regular heading"
743+
(plist-get result :heading-line)))
744+
(should (string= "Some content." (plist-get result :content))))))
745+
746+
(ert-deftest ai-code-test-implement-todo-org-plain-headline-works ()
747+
"Test `ai-code-implement-todo' works on a plain Org headline."
748+
(with-temp-buffer
749+
(require 'org)
750+
(setq buffer-file-name "notes.org")
751+
(insert "* Implement search feature\n")
752+
(insert "Use fuzzy matching.\n")
753+
(org-mode)
754+
(goto-char (point-min))
755+
756+
(let (captured-prompt)
757+
(cl-letf (((symbol-function 'completing-read)
758+
(lambda (&rest _) "Code change"))
759+
((symbol-function 'ai-code-read-string)
760+
(lambda (_label input) input))
761+
((symbol-function 'ai-code--get-clipboard-text) (lambda () nil))
762+
((symbol-function 'ai-code--get-context-files-string) (lambda () ""))
763+
((symbol-function 'ai-code--format-repo-context-info) (lambda () ""))
764+
((symbol-function 'which-function) (lambda () nil))
765+
((symbol-function 'region-active-p) (lambda () nil))
766+
((symbol-function 'ai-code--insert-prompt)
767+
(lambda (prompt) (setq captured-prompt prompt))))
768+
769+
(ai-code-implement-todo nil)
770+
771+
(should (stringp captured-prompt))
772+
(should (string-match-p "Implement search feature" captured-prompt))
773+
(should (string-match-p "Use fuzzy matching" captured-prompt))))))
774+
775+
(ert-deftest ai-code-test-code-change-routes-to-implement-todo-on-plain-org-headline ()
776+
"Test `ai-code-code-change' routes to `ai-code-implement-todo' on plain Org headline."
777+
(with-temp-buffer
778+
(require 'org)
779+
(setq buffer-file-name "notes.org")
780+
(insert "* Regular heading\n")
781+
(org-mode)
782+
(goto-char (point-min))
783+
784+
(let (captured-default-action)
785+
(cl-letf (((symbol-function 'ai-code--get-clipboard-text) (lambda () nil))
786+
((symbol-function 'ai-code-implement-todo)
787+
(lambda (_arg &optional default-action)
788+
(setq captured-default-action default-action)))
789+
((symbol-function 'region-active-p) (lambda () nil)))
790+
791+
(ai-code-code-change nil)
792+
793+
(should (equal captured-default-action "Code change"))))))
794+
724795
(provide 'test_ai-code-change)
725796

726797
;;; test_ai-code-change.el ends here

test/test_ai-code-discussion.el

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,28 @@
118118

119119
(should (equal captured-default-action "Ask question"))))))
120120

121+
(ert-deftest ai-code-test-ask-question-routes-to-implement-todo-on-plain-org-headline ()
122+
"Test `ai-code-ask-question' routes to `ai-code-implement-todo' on plain Org headline."
123+
(with-temp-buffer
124+
(require 'org)
125+
(setq buffer-file-name "notes.org")
126+
(insert "* Regular heading\n")
127+
(org-mode)
128+
(goto-char (point-min))
129+
130+
(let (implement-todo-called)
131+
(cl-letf (((symbol-function 'ai-code--get-clipboard-text) (lambda () nil))
132+
((symbol-function 'ai-code-implement-todo)
133+
(lambda (_arg &optional _default-action)
134+
(setq implement-todo-called t)))
135+
((symbol-function 'ai-code--ask-question-file)
136+
(lambda (_ctx) (error "Should not reach ask-question-file")))
137+
((symbol-function 'region-active-p) (lambda () nil)))
138+
139+
(ai-code-ask-question nil)
140+
141+
(should implement-todo-called)))))
142+
121143
(provide 'test_ai-code-discussion)
122144

123145
;;; test_ai-code-discussion.el ends here

0 commit comments

Comments
 (0)