Skip to content

Commit df6aaca

Browse files
committed
fix: Ensure cleanup runs when user quits prompt
* mevedel-tools.el (mevedel--prompt-user-with-overlay): Wrap `recursive-edit` in `undwind-protect` and `condition-case` so the cleanup code runs also on error and quit events.
1 parent 0325d81 commit df6aaca

File tree

1 file changed

+89
-82
lines changed

1 file changed

+89
-82
lines changed

mevedel-tools.el

Lines changed: 89 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -601,16 +601,23 @@ using `recursive-edit' to block until the user responds."
601601
(setq mevedel--request-result 'pending)
602602

603603
;; Enter recursive edit - allows user input while blocking
604-
(recursive-edit)
605-
606-
;; Clean up overlay if still present (e.g., if user quit with C-g)
607-
(when (and ov (overlay-buffer ov))
608-
(let ((start (overlay-start ov))
609-
(end (overlay-end ov)))
610-
(delete-overlay ov)
611-
(delete-region start end))
612-
(when (eq mevedel--request-result 'pending)
613-
(setq mevedel--request-result nil)))
604+
(unwind-protect
605+
(condition-case err
606+
(recursive-edit)
607+
;; Treat quit (C-g) as a denial
608+
(quit (setq mevedel--request-result nil))
609+
(error
610+
(user-error "%s" (error-message-string err))
611+
(setq mevedel--request-result nil)))
612+
613+
;; Clean up overlay if still present
614+
(when (and ov (overlay-buffer ov))
615+
(let ((start (overlay-start ov))
616+
(end (overlay-end ov)))
617+
(delete-overlay ov)
618+
(delete-region start end))
619+
(when (eq mevedel--request-result 'pending)
620+
(setq mevedel--request-result nil))))
614621

615622
;; Return result (t for approved, nil for denied, (feedback . TEXT) for feedback)
616623
mevedel--request-result))
@@ -1694,9 +1701,9 @@ Expects buffer-local variables to be set in
16941701
"Return lines START-LINE to END-LINE fom FILENAME via CALLBACK."
16951702
;; Validate input
16961703
(mevedel-tools--validate-params callback mevedel-tools--read-file-lines
1697-
(filename stringp)
1698-
(start-line integerp nil)
1699-
(end-line integerp nil))
1704+
(filename stringp)
1705+
(start-line integerp nil)
1706+
(end-line integerp nil))
17001707

17011708
(unless (file-readable-p filename)
17021709
(cl-return-from mevedel-tools--read-file-lines
@@ -1711,8 +1718,8 @@ Expects buffer-local variables to be set in
17111718

17121719
;; Check directory permissions
17131720
(mevedel-tools--check-directory-permissions filename
1714-
(format "Need to read file: %s" filename)
1715-
mevedel-tools--read-file-lines callback)
1721+
(format "Need to read file: %s" filename)
1722+
mevedel-tools--read-file-lines callback)
17161723

17171724
(if (and (not start-line) (not end-line)) ;read full file
17181725
(if (> (file-attribute-size (file-attributes filename))
@@ -1798,10 +1805,10 @@ Returns a string containing matches grouped by file, with line numbers
17981805
and optional context. Results are sorted by modification time."
17991806
;; Validate input
18001807
(mevedel-tools--validate-params callback mevedel-tools--grep
1801-
(regex stringp)
1802-
(path stringp)
1803-
(glob stringp nil)
1804-
(context-lines integerp nil))
1808+
(regex stringp)
1809+
(path stringp)
1810+
(glob stringp nil)
1811+
(context-lines integerp nil))
18051812

18061813
(unless (file-readable-p path)
18071814
(cl-return-from mevedel-tools--grep
@@ -1813,8 +1820,8 @@ and optional context. Results are sorted by modification time."
18131820

18141821
;; Check directory permissions
18151822
(mevedel-tools--check-directory-permissions path
1816-
(format "Need to grep in: %s" path)
1817-
mevedel-tools--grep callback)
1823+
(format "Need to grep in: %s" path)
1824+
mevedel-tools--grep callback)
18181825

18191826
(with-temp-buffer
18201827
(let* ((args
@@ -1879,8 +1886,8 @@ Workflow:
18791886
6. If rejected: optionally get feedback for LLM"
18801887
;; Validate input
18811888
(mevedel-tools--validate-params callback mevedel-tools--edit-files
1882-
(path stringp)
1883-
(new-str-or-diff stringp))
1889+
(path stringp)
1890+
(new-str-or-diff stringp))
18841891

18851892
(unless (file-readable-p path)
18861893
(cl-return-from mevedel-tools--edit-files
@@ -1889,8 +1896,8 @@ Workflow:
18891896
(let* ((expanded-path (expand-file-name path)))
18901897
;; Check directory permissions
18911898
(mevedel-tools--check-directory-permissions expanded-path
1892-
(format "Need to edit file: %s" path)
1893-
mevedel-tools--edit-files callback)
1899+
(format "Need to edit file: %s" path)
1900+
mevedel-tools--edit-files callback)
18941901

18951902
(mevedel-tools--edit-files-1 callback expanded-path old-str new-str-or-diff use-diff)))
18961903

@@ -2100,9 +2107,9 @@ LINE-NUMBER conventions:
21002107
- N > 1 inserts before line N"
21012108
;; Validate input
21022109
(mevedel-tools--validate-params callback mevedel-tools--insert-in-file
2103-
(path stringp)
2104-
(line-number integerp)
2105-
(new-str stringp))
2110+
(path stringp)
2111+
(line-number integerp)
2112+
(new-str stringp))
21062113

21072114
(unless (file-readable-p path)
21082115
(cl-return-from mevedel-tools--insert-in-file
@@ -2124,8 +2131,8 @@ LINE-NUMBER conventions:
21242131

21252132
;; Check directory permissions
21262133
(mevedel-tools--check-directory-permissions expanded-path
2127-
(format "Need to insert into file: %s" path)
2128-
mevedel-tools--insert-in-file callback)
2134+
(format "Need to insert into file: %s" path)
2135+
mevedel-tools--insert-in-file callback)
21292136

21302137
(with-temp-file temp-file
21312138
(insert original-content)
@@ -2256,7 +2263,7 @@ TODOS is a list of plists with keys :content, :activeForm, and :status.
22562263
Completed items are displayed with strikethrough and shadow face.
22572264
Exactly one item should have status \"in_progress\"."
22582265
(mevedel-tools--validate-params nil nil
2259-
(todos (vectorp . "array")))
2266+
(todos (vectorp . "array")))
22602267
(setq mevedel-tools--todos todos)
22612268
(mevedel-tools--display-todo-overlay todos)
22622269
t)
@@ -2279,8 +2286,8 @@ FILE-PATH specifies which file's buffer context to use for the search."
22792286
(require 'xref)
22802287
;; Validate input
22812288
(mevedel-tools--validate-params callback mevedel-tools--xref-find-references
2282-
(identifier stringp)
2283-
(file-path stringp))
2289+
(identifier stringp)
2290+
(file-path stringp))
22842291

22852292
(let* ((full-path (expand-file-name file-path))
22862293
(target-buffer (or (find-buffer-visiting full-path)
@@ -2289,8 +2296,8 @@ FILE-PATH specifies which file's buffer context to use for the search."
22892296

22902297
;; Check directory permissions
22912298
(mevedel-tools--check-directory-permissions full-path
2292-
(format "Need to read file: %s" file-path)
2293-
mevedel-tools--xref-find-references callback)
2299+
(format "Need to read file: %s" file-path)
2300+
mevedel-tools--xref-find-references callback)
22942301

22952302
(unless (file-exists-p full-path)
22962303
(cl-return-from mevedel-tools--xref-find-references
@@ -2332,8 +2339,8 @@ project."
23322339
(require 'xref)
23332340
;; Validate input
23342341
(mevedel-tools--validate-params callback mevedel-tools--xref-find-apropos
2335-
(pattern stringp)
2336-
(file-path stringp))
2342+
(pattern stringp)
2343+
(file-path stringp))
23372344

23382345
(let* ((full-path (expand-file-name file-path))
23392346
(target-buffer (or (find-buffer-visiting full-path)
@@ -2342,8 +2349,8 @@ project."
23422349

23432350
;; Check directory permissions
23442351
(mevedel-tools--check-directory-permissions full-path
2345-
(format "Need to read file: %s" file-path)
2346-
mevedel-tools--xref-find-apropos callback)
2352+
(format "Need to read file: %s" file-path)
2353+
mevedel-tools--xref-find-apropos callback)
23472354

23482355
(unless (file-exists-p full-path)
23492356
(cl-return-from mevedel-tools--xref-find-apropos
@@ -2395,16 +2402,16 @@ Returns a list of symbols with their types and positions."
23952402
(require 'imenu)
23962403
;; Validate input
23972404
(mevedel-tools--validate-params callback mevedel-tools--imenu-list-symbols
2398-
(file-path stringp))
2405+
(file-path stringp))
23992406

24002407
(let* ((full-path (expand-file-name file-path))
24012408
(target-buffer (or (find-buffer-visiting full-path)
24022409
(find-file-noselect full-path))))
24032410

24042411
;; Check directory permissions
24052412
(mevedel-tools--check-directory-permissions full-path
2406-
(format "Need to read file: %s" file-path)
2407-
mevedel-tools--imenu-list-symbols callback)
2413+
(format "Need to read file: %s" file-path)
2414+
mevedel-tools--imenu-list-symbols callback)
24082415

24092416
(unless (file-exists-p full-path)
24102417
(cl-return-from mevedel-tools--imenu-list-symbols
@@ -2476,21 +2483,21 @@ If INCLUDE_ANCESTORS is non-nil, include parent node hierarchy.
24762483
If INCLUDE_CHILDREN is non-nil, include child nodes."
24772484
;; Validate input
24782485
(mevedel-tools--validate-params callback mevedel-tools--treesit-info
2479-
(file-path stringp)
2480-
(line integerp nil)
2481-
(column integerp nil)
2482-
(whole_file booleanp nil)
2483-
(include_ancestors booleanp nil)
2484-
(include_children booleanp nil))
2486+
(file-path stringp)
2487+
(line integerp nil)
2488+
(column integerp nil)
2489+
(whole_file booleanp nil)
2490+
(include_ancestors booleanp nil)
2491+
(include_children booleanp nil))
24852492

24862493
(let* ((full-path (expand-file-name file-path))
24872494
(target-buffer (or (find-buffer-visiting full-path)
24882495
(find-file-noselect full-path))))
24892496

24902497
;; Check directory permissions
24912498
(mevedel-tools--check-directory-permissions full-path
2492-
(format "Need to read file: %s" file-path)
2493-
mevedel-tools--treesit-info callback)
2499+
(format "Need to read file: %s" file-path)
2500+
mevedel-tools--treesit-info callback)
24942501

24952502
(unless (file-exists-p full-path)
24962503
(cl-return-from mevedel-tools--treesit-info
@@ -2634,25 +2641,25 @@ LINE is 1-based, COLUMN is 0-based (Emacs convention)."
26342641
CALLBACK is the async callback function to call with user response.
26352642
PLAN is a plist with :title, :summary, and :sections keys."
26362643
(mevedel-tools--validate-params callback mevedel-tools--present-plan
2637-
(plan (listp . "object")))
2644+
(plan (listp . "object")))
26382645

26392646
(let* ((chat-buffer (current-buffer))
26402647
(overlay nil)
26412648
(title (or (plist-get plan :title) "Untitled Plan"))
26422649
(summary (or (plist-get plan :summary) "No summary provided"))
26432650
(sections (append (plist-get plan :sections) nil))
26442651
(plan-markdown (concat
2645-
"# Plan: " title "\n\n"
2646-
"## Summary\n"
2647-
summary "\n\n"
2648-
(mapconcat
2649-
(lambda (section)
2650-
(let ((heading (or (plist-get section :heading) "Unnamed Section"))
2651-
(content (or (plist-get section :content) "No content"))
2652-
(type (or (plist-get section :type) "step")))
2653-
(format "## %s `[%s]`\n%s\n" heading type content)))
2654-
sections
2655-
"\n"))))
2652+
"# Plan: " title "\n\n"
2653+
"## Summary\n"
2654+
summary "\n\n"
2655+
(mapconcat
2656+
(lambda (section)
2657+
(let ((heading (or (plist-get section :heading) "Unnamed Section"))
2658+
(content (or (plist-get section :content) "No content"))
2659+
(type (or (plist-get section :type) "step")))
2660+
(format "## %s `[%s]`\n%s\n" heading type content)))
2661+
sections
2662+
"\n"))))
26562663

26572664
(cl-labels
26582665
((accept-plan
@@ -2746,7 +2753,7 @@ PLAN is a plist with :title, :summary, and :sections keys."
27462753
CALLBACK is the async callback function to call with results.
27472754
QUESTIONS is an array of question plists, each with :question and :options keys."
27482755
(mevedel-tools--validate-params callback mevedel-tools--ask-user
2749-
(questions (vectorp . "array")))
2756+
(questions (vectorp . "array")))
27502757

27512758
(let* ((questions-list (append questions nil)) ; Convert vector to list
27522759
(answers (make-vector (length questions-list) nil))
@@ -3068,13 +3075,13 @@ DIRECTIVE-DATA is the data for the current directive."
30683075
(t 'error))))
30693076
(concat icon " "
30703077
(propertize (format "[depth %d] " depth)
3071-
'face `(:inherit ,depth-color))
3078+
'face `(:inherit ,depth-color))
30723079
summary
30733080
(propertize (format " (%s)" concept)
3074-
'face 'font-lock-comment-face))))
3081+
'face 'font-lock-comment-face))))
30753082
hints "\n")
30763083
(propertize "No hints given yet"
3077-
'face 'font-lock-comment-face)))
3084+
'face 'font-lock-comment-face)))
30783085
(hint-display
30793086
(concat
30803087
(unless (= (char-before (overlay-end hint-ov)) 10) "\n")
@@ -3087,12 +3094,12 @@ DIRECTIVE-DATA is the data for the current directive."
30873094
'face 'help-key-binding))
30883095
(propertize " to toggle display ]\n" 'face 'font-lock-comment-face)
30893096
(propertize (format "Hints given: %d | Suggested depth: %d/5\n"
3090-
hint-count suggested-depth)
3097+
hint-count suggested-depth)
30913098
'face 'font-lock-doc-face)
30923099
(when concepts-explained
30933100
(propertize (format "Concepts: %s\n"
3094-
(mapconcat #'identity concepts-explained ", "))
3095-
'face 'font-lock-string-face))
3101+
(mapconcat #'identity concepts-explained ", "))
3102+
'face 'font-lock-string-face))
30963103
formatted-hints "\n"
30973104
mevedel-tools--hrule-hints)))
30983105
(overlay-put hint-ov 'after-string hint-display))))))))
@@ -3131,10 +3138,10 @@ DEPTH is the hint detail level (1-5)."
31313138
(let* ((directive-uuid mevedel--current-directive-uuid)
31323139
(timestamp (current-time))
31333140
(hint-record (list :type hint_type
3134-
:concept concept
3135-
:summary hint_summary
3136-
:depth depth
3137-
:timestamp timestamp))
3141+
:concept concept
3142+
:summary hint_summary
3143+
:depth depth
3144+
:timestamp timestamp))
31383145
(directive-data (alist-get directive-uuid mevedel-tools--hint-history))
31393146
(hints (alist-get 'hints directive-data)))
31403147
;; Add hint
@@ -3321,9 +3328,9 @@ Useful for understanding code structure and AST analysis"
33213328
(cl-block nil
33223329
;; Validate input
33233330
(mevedel-tools--validate-params callback nil
3324-
(pattern stringp)
3325-
(path stringp nil)
3326-
(depth integerp nil))
3331+
(pattern stringp)
3332+
(path stringp nil)
3333+
(depth integerp nil))
33273334

33283335
(when (string-empty-p pattern)
33293336
(cl-return
@@ -3664,7 +3671,7 @@ Call: RecordHint(hint_type='socratic-question', concept='closure-capture',
36643671
(mevedel-tools--validate-params nil nil (parent stringp) (name stringp))
36653672
;; Check directory permissions
36663673
(mevedel-tools--check-directory-permissions parent
3667-
(format "Need to create directory in: %s" parent) nil nil)
3674+
(format "Need to create directory in: %s" parent) nil nil)
36683675

36693676
(condition-case errdata
36703677
(progn
@@ -3689,15 +3696,15 @@ Consider using the more granular tools \"Insert\" or \"Edit\" first."
36893696
(cl-block nil
36903697
;; Validate input
36913698
(mevedel-tools--validate-params callback nil
3692-
(path stringp)
3693-
(filename stringp)
3694-
(content stringp))
3699+
(path stringp)
3700+
(filename stringp)
3701+
(content stringp))
36953702

36963703
(let* ((full-path (expand-file-name filename path)))
36973704
;; Check directory permissions
36983705
(mevedel-tools--check-directory-permissions full-path
3699-
(format "Need to create %s in directory: %s" filename path)
3700-
nil callback)
3706+
(format "Need to create %s in directory: %s" filename path)
3707+
nil callback)
37013708

37023709
;; Snapshot the file before any modifications
37033710
(mevedel--snapshot-file-if-needed full-path)

0 commit comments

Comments
 (0)