Skip to content

Commit 32eaea0

Browse files
committed
Ensure evaluated code is balanced
* Fixes #25
1 parent 02ec2ac commit 32eaea0

File tree

5 files changed

+56
-36
lines changed

5 files changed

+56
-36
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Changes to Calva Backseat Driver
44

55
## [Unreleased]
66

7+
- [Balance brackets before evaluating code](https://github.com/BetterThanTomorrow/calva-backseat-driver/issues/25)
8+
79
## [v0.0.16] - 2025-08-12
810

911
- [Human Intelligence input box closes when focus is lost (should persist)](https://github.com/BetterThanTomorrow/calva-backseat-driver/issues/22)

src/calva_backseat_driver/bracket_balance.cljs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22
(:require ["parinfer" :as parinfer]))
33

44
(defn infer-parens
5+
[code]
6+
(some-> (parinfer/indentMode code #js {:partialResult true})
7+
(js->clj :keywordize-keys true)))
8+
9+
(defn infer-parens-response
510
"Infer parens from the indentation"
611
[{:ex/keys [dispatch!]
712
:calva/keys [text]}]
813
(dispatch! [[:app/ax.log :debug "[Server] Infering brackets for:" text]])
914
(try
10-
(let [result (some-> (parinfer/indentMode text #js {:partialResult true})
11-
(js->clj :keywordize-keys true))]
15+
(let [result (infer-parens text)]
1216
(clj->js
1317
(if (:success result)
1418
(let [new-text (:text result)]
@@ -21,5 +25,5 @@
2125
#js {:error (.-message e)})))
2226

2327
(comment
24-
(infer-parens {:ex/dispatch! println
25-
:calva/text "(def foo [a b"}))
28+
(infer-parens-response {:ex/dispatch! println
29+
:calva/text "(def foo [a b"}))

src/calva_backseat_driver/integrations/calva/features.cljs

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
(ns calva-backseat-driver.integrations.calva.features
22
(:require
33
["vscode" :as vscode]
4+
[calva-backseat-driver.bracket-balance :as balance]
45
[calva-backseat-driver.integrations.calva.api :as calva]
56
[calva-backseat-driver.integrations.calva.editor :as editor]
67
[promesa.core :as p]))
@@ -11,43 +12,56 @@
1112
(def ^:private empty-result-note
1213
"Not expecting a empty string as a result? If it is the first time you are using a namespace, evaluate its ns-form in the `user` namespace first.")
1314

14-
1515
(def ^:private error-result-note
1616
"* clj: Evaluating `*e` will give your information about the error.
1717
* cljs: Evaluating `(.-stack *e), gives you a stack trace")
1818

19+
1920
(defn evaluate-code+
2021
"Returns a promise that resolves to the result of evaluating Clojure/ClojureScript code.
2122
Takes a string of code to evaluate and a session key (clj/cljs/cljc), js/undefined means current session."
2223
[{:ex/keys [dispatch!]
2324
:calva/keys [code repl-session-key ns]}]
24-
(p/let [evaluate (get-in calva/calva-api [:repl :evaluateCode])
25-
result (-> (p/let [^js evaluation+ (if ns
26-
(evaluate repl-session-key code ns)
27-
(evaluate repl-session-key code))]
28-
(dispatch! [[:app/ax.log :debug "[Server] Evaluating code:" code]])
29-
(cond-> {:result (.-result evaluation+)
30-
:ns (.-ns evaluation+)
31-
:stdout (.-output evaluation+)
32-
:stderr (.-errorOutput evaluation+)
33-
:session-key (.-replSessionKey evaluation+)
34-
:note "Remember to check the output tool now and then to see what's happening in the application."}
35-
(.-error evaluation+)
36-
(merge {:error (.-error evaluation+)
37-
:stacktrace (.-stacktrace evaluation+)})
38-
39-
(not ns)
40-
(merge {:note no-ns-eval-note})
41-
42-
(= "" (.-result evaluation+))
43-
(merge {:note empty-result-note})))
44-
(p/catch (fn [err]
45-
(dispatch! [[:app/ax.log :debug "[Server] Evaluation failed:"
46-
err]])
47-
{:result "nil"
48-
:stderr (pr-str err)
49-
:note error-result-note})))]
50-
(clj->js result)))
25+
(let [inferred (balance/infer-parens code)
26+
balancded-code (if (:success inferred)
27+
(:text inferred)
28+
code)
29+
balancing-ocurred? (not= code balancded-code)]
30+
(when balancing-ocurred?
31+
(dispatch! [[:app/ax.log :debug "[Server] Code was unbalanced:" code "balancded-code:" balancded-code]]))
32+
(p/let [evaluate (get-in calva/calva-api [:repl :evaluateCode])
33+
result (-> (p/let [^js evaluation+ (if ns
34+
(evaluate repl-session-key balancded-code ns)
35+
(evaluate repl-session-key balancded-code))]
36+
(dispatch! [[:app/ax.log :debug "[Server] Evaluating code:" balancded-code]])
37+
(cond-> {:result (.-result evaluation+)
38+
:ns (.-ns evaluation+)
39+
:stdout (.-output evaluation+)
40+
:stderr (.-errorOutput evaluation+)
41+
:session-key (.-replSessionKey evaluation+)
42+
:note "Remember to check the output tool now and then to see what's happening in the application."}
43+
44+
balancing-ocurred?
45+
(merge
46+
{:balancing-note "The code provided for evaluation had unbalanced brackets. The code was automatically balanced before evaluation. Use the code in the `balanced-code` to correct your code on record."
47+
:balanced-code balancded-code})
48+
49+
(.-error evaluation+)
50+
(merge {:error (.-error evaluation+)
51+
:stacktrace (.-stacktrace evaluation+)})
52+
53+
(not ns)
54+
(merge {:note no-ns-eval-note})
55+
56+
(= "" (.-result evaluation+))
57+
(merge {:note empty-result-note})))
58+
(p/catch (fn [err]
59+
(dispatch! [[:app/ax.log :debug "[Server] Evaluation failed:"
60+
err]])
61+
{:result "nil"
62+
:stderr (pr-str err)
63+
:note error-result-note})))]
64+
(clj->js result))))
5165

5266
(defn get-clojuredocs+ [{:ex/keys [dispatch!]
5367
:calva/keys [clojure-symbol]}]

src/calva_backseat_driver/mcp/requests.cljs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,8 @@
269269

270270
(= tool "balance_brackets")
271271
(let [{:keys [text]} arguments
272-
result (bracket-balance/infer-parens (merge options
273-
{:calva/text text}))]
272+
result (bracket-balance/infer-parens-response (merge options
273+
{:calva/text text}))]
274274
{:jsonrpc "2.0"
275275
:id id
276276
:result {:content [{:type "text"

src/calva_backseat_driver/tools.cljs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@
9090

9191
:invoke (fn invoke [^js options _token]
9292
(let [text (-> options .-input .-text)
93-
result (balance/infer-parens {:ex/dispatch! dispatch!
94-
:calva/text text})]
93+
result (balance/infer-parens-response {:ex/dispatch! dispatch!
94+
:calva/text text})]
9595
(vscode/LanguageModelToolResult.
9696
#js [(vscode/LanguageModelTextPart.
9797
(js/JSON.stringify result))])))})

0 commit comments

Comments
 (0)