pi-revit 0.2.1 → 0.2.3
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/package.json +1 -1
- package/src/Revit/Tools/SearchApiDocs.cs +104 -15
package/package.json
CHANGED
|
@@ -21,16 +21,19 @@ namespace RevitBridge.Tools
|
|
|
21
21
|
{
|
|
22
22
|
private const int DefaultMaxResults = 10;
|
|
23
23
|
private const int MaxResultsCap = 50;
|
|
24
|
+
|
|
25
|
+
// The Max*Chars caps apply to the model-visible markdown only; the index and
|
|
26
|
+
// the details payload keep the full documentation text.
|
|
24
27
|
private const int MaxMarkdownChars = 6_000;
|
|
25
|
-
private const int MaxSummaryChars = 600;
|
|
26
28
|
private const int MaxRemarksChars = 600;
|
|
27
29
|
private const int MaxReturnsChars = 300;
|
|
28
30
|
private const int MaxParamDocChars = 240;
|
|
29
31
|
private const int MaxParamsPerMember = 10;
|
|
32
|
+
private const int MaxExceptionsPerMember = 8;
|
|
30
33
|
|
|
31
34
|
public string Name => "search_api_docs";
|
|
32
35
|
public string Label => "Search API Docs";
|
|
33
|
-
public string Description => "Search the offline Revit API documentation (the RevitAPI.xml and RevitAPIUI.xml files shipped with Revit) for types, methods, constructors, properties, fields, and events; every public API enum is fully searchable by value name (values the XML leaves undocumented are synthesized from the API assemblies). query is a single name or substring — e.g. 'FilteredElementCollector', 'Wall.Create', 'WALL_BASE_OFFSET' — ranked: exact name first, then prefix, then substring; dotted Type.Member queries match composites. Returns signatures with summary, remarks, parameter docs, return docs, and the Revit version a member was introduced in ('since'). Works with no document open. Use it to verify exact classes, members, and signatures before writing execute_csharp code. The first query builds the index (a few seconds); later queries are instant.";
|
|
36
|
+
public string Description => "Search the offline Revit API documentation (the RevitAPI.xml and RevitAPIUI.xml files shipped with Revit) for types, methods, constructors, properties, fields, and events; every public API enum is fully searchable by value name (values the XML leaves undocumented are synthesized from the API assemblies). query is a single name or substring — e.g. 'FilteredElementCollector', 'Wall.Create', 'WALL_BASE_OFFSET' — ranked: exact name first, then prefix, then substring; dotted Type.Member queries match composites, and same-named overloads rank simplest-first. To target one overload, continue the query past a parenthesis with parameter types, e.g. 'Wall.Create(Document, Curve'. Returns signatures with summary, remarks, parameter docs, return docs, exception docs, and the Revit version a member was introduced in ('since'); the top match shows its full docs inline. Works with no document open. Use it to verify exact classes, members, and signatures before writing execute_csharp code. The first query builds the index (a few seconds); later queries are instant.";
|
|
34
37
|
|
|
35
38
|
public bool RequiresDocument => false;
|
|
36
39
|
|
|
@@ -97,6 +100,9 @@ namespace RevitBridge.Tools
|
|
|
97
100
|
.Select(pair => new Dictionary<string, object?> { ["name"] = pair.Key, ["description"] = pair.Value })
|
|
98
101
|
.ToList(),
|
|
99
102
|
["returns"] = member.Returns,
|
|
103
|
+
["exceptions"] = member.Exceptions?
|
|
104
|
+
.Select(pair => new Dictionary<string, object?> { ["type"] = pair.Key, ["description"] = pair.Value })
|
|
105
|
+
.ToList(),
|
|
100
106
|
});
|
|
101
107
|
}
|
|
102
108
|
|
|
@@ -134,6 +140,7 @@ namespace RevitBridge.Tools
|
|
|
134
140
|
var top = scored
|
|
135
141
|
.OrderByDescending(entry => entry.Score)
|
|
136
142
|
.ThenBy(entry => entry.Member.Composite.Length)
|
|
143
|
+
.ThenBy(entry => entry.Member.ParameterCount)
|
|
137
144
|
.ThenBy(entry => entry.Member.FullName, StringComparer.Ordinal)
|
|
138
145
|
.Take(maxResults)
|
|
139
146
|
.Select(entry => entry.Member)
|
|
@@ -143,8 +150,15 @@ namespace RevitBridge.Tools
|
|
|
143
150
|
|
|
144
151
|
private static int Score(ApiMember member, string q, string[] words)
|
|
145
152
|
{
|
|
153
|
+
// A query with a parenthesis targets a specific overload by signature,
|
|
154
|
+
// e.g. 'wall.create(document, curve' — matched against the shortened
|
|
155
|
+
// signature text before any name-based ranking.
|
|
156
|
+
bool signatureQuery = q.Contains('(');
|
|
157
|
+
|
|
146
158
|
int score;
|
|
147
159
|
if (member.CompositeLower == q) score = 1000;
|
|
160
|
+
else if (signatureQuery && member.SignatureLower == q) score = 980;
|
|
161
|
+
else if (signatureQuery && member.SignatureLower.StartsWith(q, StringComparison.Ordinal)) score = 950;
|
|
148
162
|
else if (member.ShortNameLower == q) score = 900;
|
|
149
163
|
else if (member.CompositeLower.StartsWith(q, StringComparison.Ordinal)) score = 700;
|
|
150
164
|
else if (member.ShortNameLower.StartsWith(q, StringComparison.Ordinal)) score = 650;
|
|
@@ -169,10 +183,22 @@ namespace RevitBridge.Tools
|
|
|
169
183
|
else
|
|
170
184
|
{
|
|
171
185
|
markdown.Append(total == top.Count ? $"{total} match(es)." : $"top {top.Count} of {total} matches.");
|
|
186
|
+
|
|
187
|
+
// Same-named members from different namespaces (XYZ exists in
|
|
188
|
+
// Autodesk.Revit.DB and in helper namespaces) render identical
|
|
189
|
+
// signatures; disambiguate those lines with their full container path.
|
|
190
|
+
var ambiguous = top
|
|
191
|
+
.GroupBy(member => member.Signature, StringComparer.Ordinal)
|
|
192
|
+
.Where(group => group.Count() > 1)
|
|
193
|
+
.Select(group => group.Key)
|
|
194
|
+
.ToHashSet(StringComparer.Ordinal);
|
|
195
|
+
|
|
172
196
|
for (int i = 0; i < top.Count; i++)
|
|
173
197
|
{
|
|
174
198
|
var member = top[i];
|
|
175
199
|
string origin = member.Since is null ? member.Assembly : $"{member.Assembly}, since {member.Since}";
|
|
200
|
+
if (ambiguous.Contains(member.Signature))
|
|
201
|
+
origin += $", in {ContainingPath(member)}";
|
|
176
202
|
string line = $"\n{i + 1}. **{member.Signature}** — {KindLabel(member)} ({origin}) — {FirstSentence(member.Summary) ?? "(no summary)"}";
|
|
177
203
|
if (markdown.Length + line.Length > MaxMarkdownChars)
|
|
178
204
|
{
|
|
@@ -181,7 +207,7 @@ namespace RevitBridge.Tools
|
|
|
181
207
|
}
|
|
182
208
|
markdown.Append(line);
|
|
183
209
|
if (i == 0)
|
|
184
|
-
AppendTopMatchDocs(markdown, member);
|
|
210
|
+
AppendTopMatchDocs(markdown, member, top.Count(other => other.CompositeLower == member.CompositeLower));
|
|
185
211
|
}
|
|
186
212
|
}
|
|
187
213
|
foreach (string warning in index.Warnings)
|
|
@@ -190,18 +216,30 @@ namespace RevitBridge.Tools
|
|
|
190
216
|
}
|
|
191
217
|
|
|
192
218
|
/// <summary>The model sees only this markdown — details.payload never reaches it —
|
|
193
|
-
/// so the top match carries its remarks, parameter, and
|
|
194
|
-
///
|
|
195
|
-
///
|
|
196
|
-
|
|
219
|
+
/// so the top match carries its remarks, parameter, return, and exception docs
|
|
220
|
+
/// inline (capped for display; the payload keeps full text). Lines that would blow
|
|
221
|
+
/// the markdown budget are dropped individually. When the top match is one of
|
|
222
|
+
/// several same-named overloads, a note says how to target another one.</summary>
|
|
223
|
+
private static void AppendTopMatchDocs(StringBuilder markdown, ApiMember member, int overloadCount)
|
|
197
224
|
{
|
|
198
|
-
var lines = new List<string>(
|
|
225
|
+
var lines = new List<string>(5);
|
|
199
226
|
if (member.Remarks is { } remarks)
|
|
200
|
-
lines.Add($"\n remarks: {remarks}");
|
|
227
|
+
lines.Add($"\n remarks: {Cap(remarks, MaxRemarksChars)}");
|
|
201
228
|
if (member.Parameters is { Count: > 0 } parameters)
|
|
202
|
-
lines.Add($"\n params: {string.Join("; ", parameters.Select(pair => $"{pair.Key} — {pair.Value}"))}");
|
|
229
|
+
lines.Add($"\n params: {string.Join("; ", parameters.Select(pair => $"{pair.Key} — {Cap(pair.Value, MaxParamDocChars)}"))}");
|
|
203
230
|
if (member.Returns is { } returns)
|
|
204
|
-
lines.Add($"\n returns: {returns}");
|
|
231
|
+
lines.Add($"\n returns: {Cap(returns, MaxReturnsChars)}");
|
|
232
|
+
if (member.Exceptions is { Count: > 0 } exceptions)
|
|
233
|
+
lines.Add($"\n throws: {string.Join("; ", exceptions.Select(pair => $"{pair.Key} — {Cap(pair.Value, MaxParamDocChars)}"))}");
|
|
234
|
+
if (overloadCount > 1)
|
|
235
|
+
{
|
|
236
|
+
// The targeting example must be the query form the signature matcher
|
|
237
|
+
// actually accepts, so it is cut from the displayed signature itself —
|
|
238
|
+
// 'new XYZ(' for constructors, 'Wall.Create(' for methods.
|
|
239
|
+
int paren = member.Signature.IndexOf('(');
|
|
240
|
+
string example = paren >= 0 ? member.Signature[..(paren + 1)] : member.Composite + "(";
|
|
241
|
+
lines.Add($"\n note: {member.Composite} has {overloadCount} overload(s) listed; full docs shown for the simplest top-ranked one. To target another, continue the query past a parenthesis with its parameter types, e.g. '{example}'.");
|
|
242
|
+
}
|
|
205
243
|
foreach (string line in lines)
|
|
206
244
|
{
|
|
207
245
|
if (markdown.Length + line.Length > MaxMarkdownChars)
|
|
@@ -210,6 +248,16 @@ namespace RevitBridge.Tools
|
|
|
210
248
|
}
|
|
211
249
|
}
|
|
212
250
|
|
|
251
|
+
/// <summary>Namespace-qualified container for disambiguating display lines:
|
|
252
|
+
/// the type itself for types, the declaring type's full path for members.</summary>
|
|
253
|
+
private static string ContainingPath(ApiMember member)
|
|
254
|
+
{
|
|
255
|
+
if (member.Kind == 'T')
|
|
256
|
+
return member.FullName;
|
|
257
|
+
int dot = member.FullName.LastIndexOf('.');
|
|
258
|
+
return dot > 0 ? member.FullName[..dot] : member.FullName;
|
|
259
|
+
}
|
|
260
|
+
|
|
213
261
|
private static string KindLabel(ApiMember member) => member.IsConstructor ? "constructor" : member.Kind switch
|
|
214
262
|
{
|
|
215
263
|
'T' => "type",
|
|
@@ -262,11 +310,18 @@ namespace RevitBridge.Tools
|
|
|
262
310
|
public required string FullNameLower { get; init; }
|
|
263
311
|
public required string CompositeLower { get; init; }
|
|
264
312
|
public required string ShortNameLower { get; init; }
|
|
313
|
+
public required string SignatureLower { get; init; }
|
|
314
|
+
|
|
315
|
+
/// <summary>Top-level parameter count from the doc id; overload tie-breaks
|
|
316
|
+
/// rank the simplest overload first.</summary>
|
|
317
|
+
public required int ParameterCount { get; init; }
|
|
318
|
+
|
|
265
319
|
public string? Summary { get; init; }
|
|
266
320
|
public string? Remarks { get; init; }
|
|
267
321
|
public string? Returns { get; init; }
|
|
268
322
|
public string? Since { get; init; }
|
|
269
323
|
public IReadOnlyList<KeyValuePair<string, string>>? Parameters { get; init; }
|
|
324
|
+
public IReadOnlyList<KeyValuePair<string, string>>? Exceptions { get; init; }
|
|
270
325
|
}
|
|
271
326
|
|
|
272
327
|
private sealed class DocIndex
|
|
@@ -364,6 +419,8 @@ namespace RevitBridge.Tools
|
|
|
364
419
|
FullNameLower = fullName.ToLowerInvariant(),
|
|
365
420
|
CompositeLower = composite.ToLowerInvariant(),
|
|
366
421
|
ShortNameLower = name.ToLowerInvariant(),
|
|
422
|
+
SignatureLower = composite.ToLowerInvariant(),
|
|
423
|
+
ParameterCount = 0,
|
|
367
424
|
Summary = enumType == typeof(BuiltInCategory)
|
|
368
425
|
? "BuiltInCategory enum value — usable as the 'category' argument of get_elements/get_element_types and with FilteredElementCollector.OfCategory in execute_csharp."
|
|
369
426
|
: $"{typeName} enum value (not documented in the XML; synthesized from {assemblyName} metadata).",
|
|
@@ -481,12 +538,24 @@ namespace RevitBridge.Tools
|
|
|
481
538
|
if (parameters is { Count: >= MaxParamsPerMember })
|
|
482
539
|
break;
|
|
483
540
|
string? name = param.Attribute("name")?.Value;
|
|
484
|
-
string? text =
|
|
541
|
+
string? text = CleanDocText(param);
|
|
485
542
|
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(text))
|
|
486
543
|
continue;
|
|
487
544
|
(parameters ??= new List<KeyValuePair<string, string>>()).Add(new KeyValuePair<string, string>(name, text));
|
|
488
545
|
}
|
|
489
546
|
|
|
547
|
+
List<KeyValuePair<string, string>>? exceptions = null;
|
|
548
|
+
foreach (var exception in element.Elements("exception"))
|
|
549
|
+
{
|
|
550
|
+
if (exceptions is { Count: >= MaxExceptionsPerMember })
|
|
551
|
+
break;
|
|
552
|
+
string? cref = exception.Attribute("cref")?.Value;
|
|
553
|
+
string? text = CleanDocText(exception);
|
|
554
|
+
if (string.IsNullOrEmpty(cref) || string.IsNullOrEmpty(text))
|
|
555
|
+
continue;
|
|
556
|
+
(exceptions ??= new List<KeyValuePair<string, string>>()).Add(new KeyValuePair<string, string>(ShortCref(cref), text));
|
|
557
|
+
}
|
|
558
|
+
|
|
490
559
|
return new ApiMember
|
|
491
560
|
{
|
|
492
561
|
Kind = kind,
|
|
@@ -498,14 +567,34 @@ namespace RevitBridge.Tools
|
|
|
498
567
|
FullNameLower = path.ToLowerInvariant(),
|
|
499
568
|
CompositeLower = composite.ToLowerInvariant(),
|
|
500
569
|
ShortNameLower = shortName.ToLowerInvariant(),
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
570
|
+
SignatureLower = signature.ToLowerInvariant(),
|
|
571
|
+
ParameterCount = CountTopLevelParameters(paramText),
|
|
572
|
+
Summary = CleanDocText(element.Element("summary")),
|
|
573
|
+
Remarks = CleanDocText(element.Element("remarks")),
|
|
574
|
+
Returns = CleanDocText(element.Element("returns")),
|
|
504
575
|
Since = CleanDocText(element.Element("since")),
|
|
505
576
|
Parameters = parameters,
|
|
577
|
+
Exceptions = exceptions,
|
|
506
578
|
};
|
|
507
579
|
}
|
|
508
580
|
|
|
581
|
+
/// <summary>Parameter count of a doc-id parameter list; commas inside generic
|
|
582
|
+
/// braces (Dictionary{K,V}) do not separate parameters.</summary>
|
|
583
|
+
private static int CountTopLevelParameters(string? paramText)
|
|
584
|
+
{
|
|
585
|
+
if (string.IsNullOrEmpty(paramText))
|
|
586
|
+
return 0;
|
|
587
|
+
int count = 1;
|
|
588
|
+
int depth = 0;
|
|
589
|
+
foreach (char c in paramText)
|
|
590
|
+
{
|
|
591
|
+
if (c == '{') depth++;
|
|
592
|
+
else if (c == '}') depth--;
|
|
593
|
+
else if (c == ',' && depth == 0) count++;
|
|
594
|
+
}
|
|
595
|
+
return count;
|
|
596
|
+
}
|
|
597
|
+
|
|
509
598
|
// ------------------------------------------------------------- text utils
|
|
510
599
|
|
|
511
600
|
/// <summary>Flattens doc XML to plain text: see/seealso cref -> short type name,
|