branch: elpa/gptel
commit 2bf3a4452c953c39832442eaf27cbd8a2beb0659
Author: Karthik Chikmagalur <karthikchikmaga...@gmail.com>
Commit: Karthik Chikmagalur <karthikchikmaga...@gmail.com>

    gptel-org: Fix oneshot markdown to org converter (#81)
    
    * gptel-org.el (gptel--convert-markdown->org): Fix backtick
    handling and add support for converting markdown headings.
    
    * test/gptel-org-test.el (gptel-org--test-stream-conversion,
    gptel-org--test-compare-org): Add tests for oneshot converter.
---
 gptel-org.el           | 34 +++++++++++--------
 test/gptel-org-test.el | 92 +++++++++++++++++++++++++++++---------------------
 2 files changed, 73 insertions(+), 53 deletions(-)

diff --git a/gptel-org.el b/gptel-org.el
index 9f8ca25487..623a8d02d7 100644
--- a/gptel-org.el
+++ b/gptel-org.el
@@ -331,22 +331,28 @@ elements."
   (with-temp-buffer
     (insert str)
     (goto-char (point-min))
-    (while (re-search-forward "`\\|\\*\\{1,2\\}\\|_" nil t)
+    (while (re-search-forward "`+\\|\\*\\{1,2\\}\\|_\\|^#+" nil t)
       (pcase (match-string 0)
-        ("`" (if (save-excursion
-                   (beginning-of-line)
-                   (skip-chars-forward " \t")
-                   (looking-at "```"))
-                 (progn (backward-char)
-                        (delete-char 3)
-                        (insert "#+begin_src ")
-                        (when (re-search-forward "^```" nil t)
-                          (replace-match "#+end_src")))
-               (replace-match "=")))
+        ;; Handle backticks
+        ((and (guard (eq (char-before) ?`)) ticks)
+         (gptel--replace-source-marker (length ticks))
+         (save-match-data
+           (catch 'block-end
+             (while (search-forward ticks nil t)
+               (unless (or (eq (char-before (match-beginning 0)) ?`)
+                           (eq (char-after) ?`))
+                   (gptel--replace-source-marker (length ticks) 'end)
+                   (throw 'block-end nil))))))
+        ;; Handle headings
+        ((and (guard (eq (char-before) ?#)) heading)
+         (when (looking-at "[[:space:]]")
+           (delete-region (line-beginning-position) (point))
+           (insert (make-string (length heading) ?*))))
+        ;; Handle emphasis
         ("**" (cond
-               ((looking-at "\\*\\(?:[[:word:]]\\|\s\\)")
-                (delete-char 1))
-               ((looking-back "\\(?:[[:word:]]\\|\s\\)\\*\\{2\\}"
+               ;; ((looking-at "\\*\\(?:[[:word:]]\\|\s\\)")
+               ;;  (delete-char 1))
+               ((looking-back "\\(?:[[:word:][:punct:]\n]\\|\s\\)\\*\\{2\\}"
                               (max (- (point) 3) (point-min)))
                 (delete-char -1))))
         ("*"
diff --git a/test/gptel-org-test.el b/test/gptel-org-test.el
index 7aa69adcea..e04ffc3d39 100644
--- a/test/gptel-org-test.el
+++ b/test/gptel-org-test.el
@@ -39,10 +39,24 @@ Org markup incrementally and display both in buffers."
       (apply #'insert (mapcar func md-list))
       (display-buffer (current-buffer)))))
 
+;; Oneshot converter test generation
+
+(defmacro gptel-org--test-conversion (md-list org-str)
+  `(ert-deftest
+       ,(intern (concat "gptel-org--test-conversion-"
+                 (substring (sha1 (prin1-to-string (current-time))) 0 10)))
+       ()
+     (should
+      (string= (gptel--convert-markdown->org
+                (apply #'concat ,md-list))
+       ,org-str))))
+
+;; Stream converter test generation
+
 (defmacro gptel-org--test-stream-conversion (md-list org-str)
   `(ert-deftest
        ,(intern (concat "gptel-org--test-stream-conversion-"
-                 (substring (sha1 (prin1-to-string md-list)) 0 10)))
+                 (substring (sha1 (prin1-to-string (current-time))) 0 10)))
        ()
        (let ((func (gptel--stream-convert-markdown->org)))
         (prog1
@@ -51,27 +65,28 @@ Org markup incrementally and display both in buffers."
               ,org-str))
           (setq gptel-post-response-functions nil)))))
 
-(gptel-org--test-stream-conversion
- '("" "```" "cpp" "
+;; Tests
+
+(let ((md '("" "```" "cpp" "
 " "#include" " <" "cstdio" ">
 
 " "int" " main" "()" " {
 " "   " " printf" "(\"" "``" "``" "`" "\n" "\");
 " "   " " return" " " "0" ";
 " "}
-" "```")
- "#+begin_src cpp
+" "```"))
+      (org "#+begin_src cpp
 #include <cstdio>
 
 int main() {
     printf(\"`````\n\");
     return 0;
 }
-#+end_src")
+#+end_src"))
+  (gptel-org--test-conversion md org)
+  (gptel-org--test-stream-conversion md org))
 
-(gptel-org--test-stream-conversion
- ;; markdown
- '("" "Here" " is" " a" " simple" " C" "++" " program" " that" " uses" " the" 
" `" "printf" "`" " function" " to" " print" " the" " string" " containing" " " 
"5" " back" "ticks" ":
+(let ((md '("" "Here" " is" " a" " simple" " C" "++" " program" " that" " 
uses" " the" " `" "printf" "`" " function" " to" " print" " the" " string" " 
containing" " " "5" " back" "ticks" ":
 
 " "```" "cpp" "
 " "#include" " <" "iostream" ">
@@ -84,9 +99,8 @@ int main() {
 " "}
 " "``" "`
 
-" "In" " this" " code" " snippet" "," " `" "printf" "(\"" "``" "``" "`" "\n" 
"\");" "`" " is" " used" " to" " print" " the" " string" " \"" "``" "```" "\"" 
" followed" " by" " a" " newline" " character" ".")
- ;; Org
-  "Here is a simple C++ program that uses the =printf= function to print the 
string containing 5 backticks:
+" "In" " this" " code" " snippet" "," " `" "printf" "(\"" "``" "``" "`" "\n" 
"\");" "`" " is" " used" " to" " print" " the" " string" " \"" "``" "```" "\"" 
" followed" " by" " a" " newline" " character" "."))
+      (org "Here is a simple C++ program that uses the =printf= function to 
print the string containing 5 backticks:
 
 #+begin_src cpp
 #include <iostream>
@@ -99,35 +113,35 @@ int main() {
 }
 #+end_src
 
-In this code snippet, =printf(\"`````\n\");= is used to print the string \"=\" 
followed by a newline character.")
+In this code snippet, =printf(\"`````\n\");= is used to print the string \"=\" 
followed by a newline character."))
+  (gptel-org--test-conversion md org)
+  (gptel-org--test-stream-conversion md org))
 
 
-(gptel-org--test-stream-conversion
- ;; markdown
- '("" "In" " the" " definition" " of" " the" " `" "struct" " json" "_parser" 
"`," " the" " line" " `" "L" "isp" "_Object" " *" "object" "_workspace" ";" "`" 
" declares" " a" " pointer" " named" " `" "object" "_workspace" "`" " of" " 
type" " `" "L" "isp" "_Object" "`.\n\n" "The" " aster" "isk" " (*)" " in" " `" 
"L" "isp" "_Object" " *" "object" "_workspace" ";" "`" " is" " the" " pointer" 
" ind" "irection" " operator" " in" " C" "." " It" " indicates" " that" " `" 
"object" "_workspace" "` [...]
- ;; org
- "In the definition of the =struct json_parser=, the line =Lisp_Object 
*object_workspace;= declares a pointer named =object_workspace= of type 
=Lisp_Object=.
+(let ((md '("" "In" " the" " definition" " of" " the" " `" "struct" " json" 
"_parser" "`," " the" " line" " `" "L" "isp" "_Object" " *" "object" 
"_workspace" ";" "`" " declares" " a" " pointer" " named" " `" "object" 
"_workspace" "`" " of" " type" " `" "L" "isp" "_Object" "`.\n\n" "The" " aster" 
"isk" " (*)" " in" " `" "L" "isp" "_Object" " *" "object" "_workspace" ";" "`" 
" is" " the" " pointer" " ind" "irection" " operator" " in" " C" "." " It" " 
indicates" " that" " `" "object" "_work [...]
+      (org "In the definition of the =struct json_parser=, the line 
=Lisp_Object *object_workspace;= declares a pointer named =object_workspace= of 
type =Lisp_Object=.
 
 The asterisk (*) in =Lisp_Object *object_workspace;= is the pointer 
indirection operator in C. It indicates that =object_workspace= is a pointer to 
an object of type =Lisp_Object=. This means that =object_workspace= will store 
the memory address (location) of a =Lisp_Object= variable rather than storing 
the actual =Lisp_Object= value.
 
-Therefore, =object_workspace= will be used to point to or reference locations 
in memory where =Lisp_Object= instances are stored. This allows the =struct 
json_parser= to store and work with =Lisp_Object= instances indirectly through 
pointers.")
-
-(gptel-org--test-stream-conversion
- ;; markdown
- '("#" "# Advantages of"
-   " Org-Mode: A Detailed Overview\n\nOrg-mode is a powerful and versatile 
Emacs extension that offers a wide range of features"
-   " for organizing information, planning projects, and writing documents. 
Here's a detailed overview of its advantages:\n\n**Note Taking and Idea 
Management:**\n\n"
-   "* **Unified platform:** Org-mode provides a single platform for capturing 
notes, ideas, and tasks, eliminating the need for multiple tools and ensuring 
everything is in one place.\n* **Flexibility:** Notes can be structured 
hierarchically"
-   " using headlines and subheadings, allowing for easy organization and 
navigation.\n* **Linking and tags:** Link notes together for easy reference and 
connect them with tags for categorized browsing.\n* **Metadata:** Capture 
additional information like author, deadline, and"
-   " priority for better organization and search.\n\n**Project Management and 
Planning:**\n\n* **Task management:** Create to-do lists with deadlines, 
priority levels, and tags for efficient task management.\n* **Gantt charts and 
time estimates:** Visualize project timelines and estimate time commitments for 
better planning and organization.\n* **Calendar integration:** Link tasks to 
your calendar for better integration and time management.\n* **"
-   "Progress tracking:** Track the progress of tasks and projects with 
checkboxes and progress bars.\n\n**Writing and Document Creation:**\n\n* **Rich 
text formatting:** Org-mode supports a variety of text formatting options, 
including bold, italics, headings, and lists, for creating professional-looking 
documents.\n* **Exporting to various formats:** Easily export your notes and 
documents to various formats like PDF, HTML, LaTeX, and"
-   " plain text.\n* **Beamer presentations:** Create Beamer presentations 
directly within Org-mode for academic or professional presentations.\n* 
**Source code blocks:** Include and highlight code blocks for easy reference 
and documentation.\n\n**Additional Features:**\n\n* **Org-Capture:** Quickly 
capture ideas, notes, and tasks from anywhere using keyboard shortcuts.\n* 
**Org-Agenda:** View and manage your tasks and appointments in a calendar-like 
format.\n* **Emacs Lisp scripting:** A [...]
-   " functionality and automate tasks with Emacs Lisp scripting.\n* *"
-   "*Active development and community support:** Benefit from the active 
development and supportive community of Org-mode users.\n\n**Overall 
Advantages:**\n\n* **Increased productivity:** Organize your thoughts, tasks, 
and projects efficiently, leading to increased productivity.\n*"
-   " **Improved focus:** Eliminate distractions and stay focused on the task 
at hand.\n* **Enhanced creativity:** Capture ideas quickly and easily, 
fostering creativity and innovation.\n* **Knowledge management:** Build a 
comprehensive knowledge base"
-   " of notes, ideas, and projects for future reference.\n*"
-   " **Personalized workflow:** Tailor Org-mode to your specific needs and 
preferences for a truly personalized workflow.\n\n**Limitations:**\n\n* 
**Learning curve:** While powerful, Org-mode has a steeper learning curve 
compared to simpler note-taking apps.\n* **Emacs dependency:** Org-mode 
requires Emacs, which may not be suitable for all users.\n* **Limited mobile 
support:** Mobile support for Org-mode is available but not as feature-rich as"
-   " the desktop version.\n\n**Who should use Org-mode?**\n\n"
-   "* Students\n* Researchers\n* Writers\n* Project managers\n* Anyone who 
wants to improve their personal organization and 
productivity\n\n**Conclusion:**\n\nOrg-mode is a powerful and versatile tool 
that can significantly increase your productivity and organization. Its 
flexibility, rich features, and active community make it an excellent choice 
for managing notes, projects, and documents. If you're looking for a way to 
streamline your workflow and unleash your creativity, Org-mode is  [...]
- ;; org
- "** Advantages of Org-Mode: A Detailed Overview\n\nOrg-mode is a powerful and 
versatile Emacs extension that offers a wide range of features for organizing 
information, planning projects, and writing documents. Here's a detailed 
overview of its advantages:\n\n*Note Taking and Idea Management:*\n\n- *Unified 
platform:* Org-mode provides a single platform for capturing notes, ideas, and 
tasks, eliminating the need for multiple tools and ensuring everything is in 
one place.\n- *Flexibility [...]
+Therefore, =object_workspace= will be used to point to or reference locations 
in memory where =Lisp_Object= instances are stored. This allows the =struct 
json_parser= to store and work with =Lisp_Object= instances indirectly through 
pointers."))
+  (gptel-org--test-conversion md org)
+  (gptel-org--test-stream-conversion md org))
+
+(let ((md '("#" "# Advantages of"
+            " Org-Mode: A Detailed Overview\n\nOrg-mode is a powerful and 
versatile Emacs extension that offers a wide range of features"
+            " for organizing information, planning projects, and writing 
documents. Here's a detailed overview of its advantages:\n\n**Note Taking and 
Idea Management:**\n\n"
+            "* **Unified platform:** Org-mode provides a single platform for 
capturing notes, ideas, and tasks, eliminating the need for multiple tools and 
ensuring everything is in one place.\n* **Flexibility:** Notes can be 
structured hierarchically"
+            " using headlines and subheadings, allowing for easy organization 
and navigation.\n* **Linking and tags:** Link notes together for easy reference 
and connect them with tags for categorized browsing.\n* **Metadata:** Capture 
additional information like author, deadline, and"
+            " priority for better organization and search.\n\n**Project 
Management and Planning:**\n\n* **Task management:** Create to-do lists with 
deadlines, priority levels, and tags for efficient task management.\n* **Gantt 
charts and time estimates:** Visualize project timelines and estimate time 
commitments for better planning and organization.\n* **Calendar integration:** 
Link tasks to your calendar for better integration and time management.\n* **"
+            "Progress tracking:** Track the progress of tasks and projects 
with checkboxes and progress bars.\n\n**Writing and Document Creation:**\n\n* 
**Rich text formatting:** Org-mode supports a variety of text formatting 
options, including bold, italics, headings, and lists, for creating 
professional-looking documents.\n* **Exporting to various formats:** Easily 
export your notes and documents to various formats like PDF, HTML, LaTeX, and"
+            " plain text.\n* **Beamer presentations:** Create Beamer 
presentations directly within Org-mode for academic or professional 
presentations.\n* **Source code blocks:** Include and highlight code blocks for 
easy reference and documentation.\n\n**Additional Features:**\n\n* 
**Org-Capture:** Quickly capture ideas, notes, and tasks from anywhere using 
keyboard shortcuts.\n* **Org-Agenda:** View and manage your tasks and 
appointments in a calendar-like format.\n* **Emacs Lisp scrip [...]
+            " functionality and automate tasks with Emacs Lisp scripting.\n* *"
+            "*Active development and community support:** Benefit from the 
active development and supportive community of Org-mode users.\n\n**Overall 
Advantages:**\n\n* **Increased productivity:** Organize your thoughts, tasks, 
and projects efficiently, leading to increased productivity.\n*"
+            " **Improved focus:** Eliminate distractions and stay focused on 
the task at hand.\n* **Enhanced creativity:** Capture ideas quickly and easily, 
fostering creativity and innovation.\n* **Knowledge management:** Build a 
comprehensive knowledge base"
+            " of notes, ideas, and projects for future reference.\n*"
+            " **Personalized workflow:** Tailor Org-mode to your specific 
needs and preferences for a truly personalized 
workflow.\n\n**Limitations:**\n\n* **Learning curve:** While powerful, Org-mode 
has a steeper learning curve compared to simpler note-taking apps.\n* **Emacs 
dependency:** Org-mode requires Emacs, which may not be suitable for all 
users.\n* **Limited mobile support:** Mobile support for Org-mode is available 
but not as feature-rich as"
+            " the desktop version.\n\n**Who should use Org-mode?**\n\n"
+            "* Students\n* Researchers\n* Writers\n* Project managers\n* 
Anyone who wants to improve their personal organization and 
productivity\n\n**Conclusion:**\n\nOrg-mode is a powerful and versatile tool 
that can significantly increase your productivity and organization. Its 
flexibility, rich features, and active community make it an excellent choice 
for managing notes, projects, and documents. If you're looking for a way to 
streamline your workflow and unleash your creativity, Org [...]
+      (org "** Advantages of Org-Mode: A Detailed Overview\n\nOrg-mode is a 
powerful and versatile Emacs extension that offers a wide range of features for 
organizing information, planning projects, and writing documents. Here's a 
detailed overview of its advantages:\n\n*Note Taking and Idea Management:*\n\n- 
*Unified platform:* Org-mode provides a single platform for capturing notes, 
ideas, and tasks, eliminating the need for multiple tools and ensuring 
everything is in one place.\n- *F [...]
+  (gptel-org--test-conversion md org)
+  (gptel-org--test-stream-conversion md org))

Reply via email to