pi-revit 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/package.json +1 -1
- package/src/Revit/Tools/ExecuteCsharp.cs +49 -9
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,24 @@ Format follows [Keep a Changelog](https://keepachangelog.com/); version headers
|
|
|
7
7
|
Every published version gets an entry with **Added** / **Changed** / **Fixed** sections
|
|
8
8
|
describing what the user will notice — not internal refactors.
|
|
9
9
|
|
|
10
|
+
## [0.2.5] - 2026-07-20
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- `execute_csharp` dialog guard no longer answers every Revit popup with OK. On some
|
|
14
|
+
dialogs OK is the destructive choice (e.g. "Delete Element(s)"), so a script could
|
|
15
|
+
silently delete dimensions or constraints and still report success. Unrecognized
|
|
16
|
+
dialogs are now answered dismissively (Cancel, then Close, then No; OK only as the
|
|
17
|
+
last resort so Revit can never hang behind a popup), a small allowlist keeps OK for
|
|
18
|
+
dialogs that are safe to confirm, and `suppressedDialogs` now reports which answer
|
|
19
|
+
was given (e.g. `TaskDialog_… (answered Cancel)`).
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- The `execute_csharp` tool description tells the model that confirmation prompts may be
|
|
23
|
+
cancelled and to check `suppressedDialogs` when a result looks incomplete.
|
|
24
|
+
|
|
25
|
+
Requires redeploying the Revit add-in (`scripts\deploy.ps1` + Revit restart) — `ping`
|
|
26
|
+
warns on a version mismatch until then.
|
|
27
|
+
|
|
10
28
|
## [0.2.4] - 2026-07-20
|
|
11
29
|
|
|
12
30
|
### Added
|
package/package.json
CHANGED
|
@@ -59,7 +59,7 @@ namespace RevitBridge.Tools
|
|
|
59
59
|
|
|
60
60
|
public string Name => "execute_csharp";
|
|
61
61
|
public string Label => "Execute C#";
|
|
62
|
-
public string Description => "Compile and run a C# script on the Revit API thread against the open model — the escape hatch for anything without a dedicated tool: element creation, deletion, geometry edits (move/copy/rotate), views, sheets, schedules, tagging, families, links, worksets. Globals: doc (Document), uidoc (UIDocument), uiapp (UIApplication), and Dump(value) to record intermediate values into the result's dumps[]. Default imports: System, System.Linq, System.Collections.Generic, Autodesk.Revit.DB, Autodesk.Revit.UI — add using directives at the top for sub-namespaces (e.g. using Autodesk.Revit.DB.Architecture;). The entire run is wrapped in ONE transaction named 'execute_csharp': committed on success, rolled back on any exception, so a failed script never changes the model (do not open your own Transaction; sub-transactions are fine). The script's final expression or return statement becomes returnValue; return primitives, strings, or anonymous objects/lists — Revit API values are projected to safe shapes (Element -> {id,name,category,typeName,levelId}, ElementId -> number, XYZ -> {x,y,z}, Parameter -> {name,value,displayValue}; other API objects become strings) with depth and item caps, so never rely on raw API objects round-tripping. Lengths are in internal units (decimal feet) — convert with UnitUtils. Prefer collector-level filtering (FilteredElementCollector .OfCategory/.OfClass/.WhereElementIsNotElementType) and bounded loops: the call budget is 120s and Revit cannot be interrupted mid-script. Scripts must be fully synchronous — await/async is rejected at compile time, and blocking on tasks (Task.Result/.Wait()) can freeze Revit. Modal dialogs raised while running are auto-dismissed and reported in suppressedDialogs. Verify unfamiliar signatures with search_api_docs first.";
|
|
62
|
+
public string Description => "Compile and run a C# script on the Revit API thread against the open model — the escape hatch for anything without a dedicated tool: element creation, deletion, geometry edits (move/copy/rotate), views, sheets, schedules, tagging, families, links, worksets. Globals: doc (Document), uidoc (UIDocument), uiapp (UIApplication), and Dump(value) to record intermediate values into the result's dumps[]. Default imports: System, System.Linq, System.Collections.Generic, Autodesk.Revit.DB, Autodesk.Revit.UI — add using directives at the top for sub-namespaces (e.g. using Autodesk.Revit.DB.Architecture;). The entire run is wrapped in ONE transaction named 'execute_csharp': committed on success, rolled back on any exception, so a failed script never changes the model (do not open your own Transaction; sub-transactions are fine). The script's final expression or return statement becomes returnValue; return primitives, strings, or anonymous objects/lists — Revit API values are projected to safe shapes (Element -> {id,name,category,typeName,levelId}, ElementId -> number, XYZ -> {x,y,z}, Parameter -> {name,value,displayValue}; other API objects become strings) with depth and item caps, so never rely on raw API objects round-tripping. Lengths are in internal units (decimal feet) — convert with UnitUtils. Prefer collector-level filtering (FilteredElementCollector .OfCategory/.OfClass/.WhereElementIsNotElementType) and bounded loops: the call budget is 120s and Revit cannot be interrupted mid-script. Scripts must be fully synchronous — await/async is rejected at compile time, and blocking on tasks (Task.Result/.Wait()) can freeze Revit. Modal dialogs raised while running are auto-dismissed and reported in suppressedDialogs — unrecognized dialogs are answered dismissively (Cancel/Close/No) rather than confirmed, so an operation that raises a confirmation prompt may be cancelled; check suppressedDialogs when a result looks incomplete. Verify unfamiliar signatures with search_api_docs first.";
|
|
63
63
|
public bool Write => true;
|
|
64
64
|
|
|
65
65
|
public object ParametersSchema => new
|
|
@@ -234,9 +234,31 @@ namespace RevitBridge.Tools
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
/// <summary>Auto-dismisses any modal Revit dialog raised while the script runs, so a
|
|
237
|
-
/// popup cannot hang the Revit thread; dismissed dialog ids are
|
|
237
|
+
/// popup cannot hang the Revit thread; dismissed dialog ids and the answer given are
|
|
238
|
+
/// reported. Unrecognized dialogs get the dismissive answer (Cancel, then Close, then
|
|
239
|
+
/// No) — on several Revit dialogs OK is the destructive choice (e.g. "Delete
|
|
240
|
+
/// Element(s)"), so confirming blind can silently damage the model. OK leads only for
|
|
241
|
+
/// dialogs known to be safe to confirm, and is otherwise the last resort: every
|
|
242
|
+
/// override attempt failing would leave the dialog up and hang the Revit thread,
|
|
243
|
+
/// which is the one outcome this guard exists to prevent.</summary>
|
|
238
244
|
private sealed class DialogGuard : IDisposable
|
|
239
245
|
{
|
|
246
|
+
private const int IDOK = 1;
|
|
247
|
+
private const int IDCANCEL = 2;
|
|
248
|
+
private const int IDNO = 7;
|
|
249
|
+
private const int IDCLOSE = 8;
|
|
250
|
+
|
|
251
|
+
/// <summary>Dialogs where confirming is the benign answer and cancelling would
|
|
252
|
+
/// abort the operation the script deliberately started.</summary>
|
|
253
|
+
private static readonly HashSet<string> ConfirmSafeDialogIds = new(StringComparer.OrdinalIgnoreCase)
|
|
254
|
+
{
|
|
255
|
+
// "Export with temporary hide/isolate": OK exports the view as displayed.
|
|
256
|
+
"TaskDialog_Really_Print_Or_Export_Temp_View_Modes",
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
private static readonly int[] ConfirmFirst = { IDOK, IDCANCEL, IDCLOSE };
|
|
260
|
+
private static readonly int[] DismissFirst = { IDCANCEL, IDCLOSE, IDNO, IDOK };
|
|
261
|
+
|
|
240
262
|
private readonly UIApplication _uiapp;
|
|
241
263
|
public List<string> Suppressed { get; } = new();
|
|
242
264
|
|
|
@@ -248,17 +270,35 @@ namespace RevitBridge.Tools
|
|
|
248
270
|
|
|
249
271
|
private void OnDialogBoxShowing(object? sender, DialogBoxShowingEventArgs e)
|
|
250
272
|
{
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
e.OverrideResult(1); // IDOK
|
|
255
|
-
}
|
|
256
|
-
catch
|
|
273
|
+
string id = string.IsNullOrEmpty(e.DialogId) ? e.GetType().Name : e.DialogId;
|
|
274
|
+
int[] answers = ConfirmSafeDialogIds.Contains(id) ? ConfirmFirst : DismissFirst;
|
|
275
|
+
foreach (int answer in answers)
|
|
257
276
|
{
|
|
258
|
-
|
|
277
|
+
try
|
|
278
|
+
{
|
|
279
|
+
if (e.OverrideResult(answer))
|
|
280
|
+
{
|
|
281
|
+
Suppressed.Add($"{id} (answered {AnswerName(answer)})");
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch
|
|
286
|
+
{
|
|
287
|
+
// Some dialogs reject specific overrides; try the next answer.
|
|
288
|
+
}
|
|
259
289
|
}
|
|
290
|
+
Suppressed.Add($"{id} (override rejected — dialog may need manual dismissal)");
|
|
260
291
|
}
|
|
261
292
|
|
|
293
|
+
private static string AnswerName(int answer) => answer switch
|
|
294
|
+
{
|
|
295
|
+
IDOK => "OK",
|
|
296
|
+
IDCANCEL => "Cancel",
|
|
297
|
+
IDNO => "No",
|
|
298
|
+
IDCLOSE => "Close",
|
|
299
|
+
_ => answer.ToString(),
|
|
300
|
+
};
|
|
301
|
+
|
|
262
302
|
public void Dispose()
|
|
263
303
|
{
|
|
264
304
|
try
|