feat(tsl-api-reference): improve tagged API discovery

This commit is contained in:
csh
2026-07-31 12:37:59 +08:00
parent 736d1a8ad7
commit 29d110110b
5 changed files with 136 additions and 67 deletions
+15 -6
View File
@@ -29,12 +29,21 @@ description: "当编写、修改或审查 TSL 代码时需要确认 builtin、do
- 未知名称,但知道其行为或中文关键词:
```bash
python <this-skill-dir>/scripts/lookup.py --kw 数组 排序
python <this-skill-dir>/scripts/lookup.py --kw 最大值 位置
```
- 关键词采用 AND 语义;增加关键词可缩小结果范围。
- 关键词会搜索原有字段及 `qualified_name`、`owner`、`kind`、`binding`、
`visibility`;因此可用 `--kw protected method` 等组合缩小成员范围。
- 只查询一个 scope
```bash
python <this-skill-dir>/scripts/lookup.py --scope builtin --name boolToStr
python <this-skill-dir>/scripts/lookup.py --scope dotnet --kw argmax
```
- 关键词采用字面 AND 语义;增加关键词可缩小结果范围。常用同义词由 API 条目的
Tags 提供,例如“位置/下标”“列表/数组”“打印/输出”。
- 关键词会搜索 `name`、`signature`、`tags`、`summary`、`module`、`scope` 及
`qualified_name`、`owner`、`kind`、`binding`、`visibility`,并按字段加权稳定排序;
因此也可用 `--kw dotnet argmax` 或 `--kw protected method` 缩小范围。
- 使用 `--limit N` 调整打印的候选行数量,N 必须 >= 1。
精确查询会打印完整的条目正文和来源标记。关键词查询打印候选行;
@@ -52,8 +61,8 @@ method 显示 `function`,类方法显示 `class function`,静态字段与常
`static field`、`static const`。
同名 API 存在于多个 scope 或模块时(如 `host`、`login`、`port`),`--name`
会依次打印全部同名条目,每条带自己的来源标记。按当前代码所处的 scope 和模块
选择条目,不要默认取第一条。
会依次打印全部同名条目,每条带自己的来源标记。已知 scope 时先用 `--scope`
过滤;否则按当前代码所处的 scope 和模块选择条目,不要默认取第一条。
查询脚本兼容旧 8 列和新 13 列 `function_index.tsv`。旧 8 列索引仍可查询原有
function;完全限定名称、owner、kind、binding、visibility 依赖新索引中的扩展列。
@@ -182,7 +182,7 @@ arcTan builtin math arcTan(x) builtin/math/numeric.md arctan 反正切函数,
arcTan2 builtin math arcTan2(x, y) builtin/math/numeric.md arctan2 反正切函数,求正切值等于Y/X的弧度值,[-π,π] function arcTan2
arcTanh builtin math arcTanh(x) builtin/math/numeric.md arctanh 反双曲正切函数,计算参数X的反双曲正切值,是双曲正切函数TanH(X)的反函数 function arcTanh
argconfirst dotnet runtime argconfirst(a, v, _type) dotnet/runtime/array.md argconfirst 第一次满足条件的位置, 原数组必须为有序表且元素应可比较。 function argconfirst
argmax dotnet runtime argmax(x) dotnet/runtime/array.md argmax 1、返回一维数组中最大值所在下标 function argmax
argmax dotnet runtime argmax(x) dotnet/runtime/array.md argmax 数组 列表 array list 最大值 最大 maximum max 下标 索引 位置 index position 1、返回一维数组中最大值所在下标 function argmax
argmin dotnet runtime argmin(x) dotnet/runtime/array.md argmin 1、返回一维数组中最小值所在下标 function argmin
argsort dotnet runtime argsort(value, sortdir) dotnet/runtime/array.md argsort 返回可以用于排序的一维数组下标 function argsort
arma dotnet runtime arma(series, p, q) dotnet/runtime/math_stats.md arma 自回归移动平均模型,ARMA(p,q)模型,采用逆函数去估计自回归系数和移动平均系数,返回结果有自回归系数、移动平均系数、残差方差等信息 ARMA模型: 其中:为原序列零均值化的新序列,是自回归方程系数,为移动平均系数,是零均值、方差为的平稳白噪声 function arma
@@ -197,7 +197,7 @@ arrayinsert dotnet runtime arrayinsert(a, ind, v) dotnet/runtime/array.md arrayi
arraysetdefault dotnet runtime arraysetdefault(r, k, v) dotnet/runtime/array.md arraysetdefault 带默认值的数组赋值(字段未使用则赋值) function arraysetdefault
arraysetdefault2 dotnet runtime arraysetdefault2(r, k, v) dotnet/runtime/array.md arraysetdefault2 带默认值的数组赋值(值为nil则赋值) function arraysetdefault2
arrayToFm builtin base arrayToFm(value, sample_value) builtin/base/array.md arraytofm 将数组转换为 FMArray,并按样例值确定单元格类型。 function arrayToFm
arrDropDuplicate dotnet runtime arrDropDuplicate(data) dotnet/runtime/array.md arrdropduplicate 数组去重(包含NAN)。 function arrDropDuplicate
arrDropDuplicate dotnet runtime arrDropDuplicate(data) dotnet/runtime/array.md arrdropduplicate 数组 列表 array list 去重 删除重复 deduplicate duplicate dropduplicate 数组去重(包含NAN)。 function arrDropDuplicate
AsBinary builtin language AsBinary builtin/language/legacy_pending.md asbinary 消息的原始内容,二进制数据类型。 function AsBinary
AsBinary builtin language AsBinary builtin/language/legacy_pending.md asbinary-1 内容以二进制类型的原始值。 function AsBinary
asBlank dotnet document asBlank(col, row) dotnet/document/excel_class.md asblank 是否为空白单元格 function asBlank
@@ -12287,7 +12287,7 @@ WR_v dotnet quant WR_v(n) dotnet/quant/ma_indicator.md wr_v 威廉指标WR
wrapText builtin base wrapText(max_col) builtin/base/string.md wraptext 按照最大行长为MaxCol自动分行。 function wrapText
wrapText dotnet document wrapText(col, row) dotnet/document/excel_class.md wraptext 单元格的是否换行 function wrapText
wrcoef dotnet runtime wrcoef(o, c, l, wname, n) dotnet/runtime/math_stats.md wrcoef 一维离散小波单支重构,小波分析,小波重构中间函数或者细节系数(高频)提取 function wrcoef
write builtin external write(p1, pn) builtin/external/cgi.md write 输出字符串,如果在平台运行,会输出信息到客户端。 function write
write builtin external write(p1, pn) builtin/external/cgi.md write 打印 输出 output print write writeln 输出字符串,如果在平台运行,会输出信息到客户端。 function write
WriteBinaryStream builtin language WriteBinaryStream(section, ident, value) builtin/language/object_tsl.md writebinarystream 写INI内容。 function WriteBinaryStream
WriteBoolean builtin language WriteBoolean(section, ident, value) builtin/language/object_tsl.md writeboolean 写INI内容。 function WriteBoolean
WriteClient builtin language WriteClient(buffer, count) builtin/language/object_tsl.md writeclient 向客户端发送的数据。 function WriteClient
@@ -12297,7 +12297,7 @@ writeFile dotnet runtime writeFile(data_type, alias, file_name, pos, length, dat
WriteFloat builtin language WriteFloat(section, ident, value) builtin/language/object_tsl.md writefloat 写INI内容。 function WriteFloat
WriteHeaders builtin language WriteHeaders(status_code, headers) builtin/language/object_tsl.md writeheaders 向客户端发送头部。 function WriteHeaders
WriteInteger builtin language WriteInteger(section, ident, value) builtin/language/object_tsl.md writeinteger 写INI内容。 function WriteInteger
writeln builtin external writeln(p1, pn) builtin/external/cgi.md writeln 带回车地输出字符串,如果在平台运行,会输出信息到客户端。 function writeln
writeln builtin external writeln(p1, pn) builtin/external/cgi.md writeln 打印 输出 output print write writeln 带回车地输出字符串,如果在平台运行,会输出信息到客户端。 function writeln
WriteString builtin language WriteString(s) builtin/language/object_tsl.md writestring 向客户端发送的数据。 function WriteString
WriteString builtin language WriteString(section, ident, value) builtin/language/object_tsl.md writestring-1 写INI内容。 function WriteString
writeToLog dotnet runtime writeToLog(dir, sub_dir, value) dotnet/runtime/file_dir.md writetolog 向虚拟目录写日志。其中Dir为虚拟目录名,SubDir为文件名,成功写入日志后,会生成命名为’SubDir’+写入日期+’.log’的TXT文件,文件内容为写入时间->Value。用户使用其应当申请好服务器权限。 20250512升级:优化多个线程同时写入时存在丢失情况: 1、增加重试次数,重试20次间隔0.5秒。 2、增加返回内容。 注意:在极端情况下(超多多线程下同时写入)可能还会存在写入失败情况,此时可通过返回结果继续处理 function writeToLog
Can't render this file because it is too large.
@@ -30,6 +30,8 @@
带回车地输出字符串,如果在平台运行,会输出信息到客户端。
<!-- tags: 打印 输出 output print write writeln -->
| 参数 | 类型 | 说明 |
| ---- | ------ | -------------- |
| `p1` | string | string 字符串1 |
@@ -40,13 +42,9 @@
### 示例
```tsl
// 先输出111222,接着另起一行显示空白,再接着另起一行输出333
// 需平台运行环境查看客户端输出
writeln("111", "222");
writeln("333");
{结果页面中,运行信息下打印:
111222
333
}
```
## `write(p1, pn)`
@@ -55,6 +53,8 @@ writeln("333");
输出字符串,如果在平台运行,会输出信息到客户端。
<!-- tags: 打印 输出 output print write writeln -->
| 参数 | 类型 | 说明 |
| ---- | ------ | -------------- |
| `p1` | string | string 字符串1 |
@@ -65,13 +65,10 @@ writeln("333");
### 示例
```tsl
// 先输出123456,接着另起一行输出789
// 需平台运行环境查看客户端输出
write("123", "456");
write("789");
return;
{在结果页面中打印:
123456
789}
```
## `httpGetContent()`
@@ -1459,6 +1459,8 @@ return fieldCountOfStrSubscript(s);
1、返回一维数组中最大值所在下标
<!-- tags: 数组 列表 array list 最大值 最大 maximum max 下标 索引 位置 index position -->
| 参数 | 类型 | 说明 |
| ---- | ---------------- | ------------ |
| `x` | array,tablearray | 一维数字数组 |
@@ -1469,7 +1471,8 @@ return fieldCountOfStrSubscript(s);
```tsl
x := array(9, 8, 10);
return argmax(x); // 2
return argmax(x);
// 输出:2
```
## `argmin(x)`
@@ -2688,6 +2691,8 @@ return groupDemeanIt(t, 'G', array('V1', 'V2'));
数组去重(包含NAN)。
<!-- tags: 数组 列表 array list 去重 删除重复 deduplicate duplicate dropduplicate -->
| 参数 | 类型 | 说明 |
| ------ | ----- | -------------------- |
| `data` | array | 数据表类型。数据表。 |
@@ -2699,7 +2704,7 @@ return groupDemeanIt(t, 'G', array('V1', 'V2'));
```tsl
data := array(("A": 1, "B": nan), ("A": 1, "B": 2), ("A": 1, "B": nan), ("A": 1, "B": 2));
return arrDropDuplicate(data);
// 结果array(("A":1,"B":NAN),("A":1,"B":2))
// 输出array(("A":1,"B":NAN),("A":1,"B":2))
```
## `getSubTableByField(t)`
+104 -46
View File
@@ -3,6 +3,7 @@
import argparse
import re
import sys
import unicodedata
from pathlib import Path
TOP_LEVEL_RE = re.compile(r"^##(?!#)\s+`(.+?)`\s*$")
@@ -43,6 +44,25 @@ OPTIONAL_COLUMNS = (
"owner",
"qualified_name",
)
SEARCH_FIELD_WEIGHTS = (
("name", 120),
("qualified_name", 120),
("signature", 90),
("tags", 70),
("summary", 50),
("module", 30),
("scope", 30),
("owner", 25),
("kind", 20),
("binding", 20),
("visibility", 20),
)
# Complete coverage in curated semantic text must outrank incidental short
# aliases in composite identifiers, such as "index" and "max".
SEMANTIC_COVERAGE_BONUSES = (
("tags", 240),
("summary", 200),
)
HELP_EPILOG = """\
检索分两步--kw 的摘要不能直接作为 API 事实
@@ -53,6 +73,7 @@ HELP_EPILOG = """\
lookup.py --name arrDropDuplicate
已知确切名称时可以直接用 --name跳过第 1
只查询一个 API scope 时使用 --scope例如 --scope builtin --scope dotnet
退出码
0 取回成功--name 无匹配也是 0打印提示不算错误
@@ -67,20 +88,6 @@ def non_empty(value):
return value
def find_tsv(start):
"""Walk upward from start and find a bundled or legacy function_index.tsv."""
for directory in [start, *start.parents]:
candidates = [
directory / "data" / "function_index.tsv",
directory / "function_index.tsv",
directory / "docs" / "tsl" / "codegen" / "function_index.tsv",
]
for candidate in candidates:
if candidate.is_file():
return candidate
return None
def load_rows(tsv_path):
lines = tsv_path.read_text(encoding="utf-8").splitlines()
if not lines:
@@ -108,6 +115,45 @@ def load_rows(tsv_path):
return rows
def normalize(value):
return unicodedata.normalize("NFKC", value).casefold().strip()
def field_match_score(value, variant, weight):
normalized = normalize(value)
if not normalized or not variant:
return 0
if normalized == variant:
return weight + 20
if variant in normalized:
return weight
return 0
def term_score(row, term):
best = 0
for field, weight in SEARCH_FIELD_WEIGHTS:
score = field_match_score(row.get(field, ""), term, weight)
if score:
best = max(best, score)
return best
def field_covers_terms(row, field, terms):
value = normalize(row.get(field, ""))
return bool(value) and all(term in value for term in terms)
def keyword_sort_key(row):
return (
normalize(row.get("qualified_name", "") or row.get("name", "")),
normalize(row.get("signature", "")),
normalize(row.get("scope", "")),
row.get("page", ""),
row.get("anchor", ""),
)
def search_exact(rows, name):
key = name.casefold()
return [
@@ -122,26 +168,19 @@ def search_exact(rows, name):
def search_keyword(rows, terms):
lowered_terms = [term.lower() for term in terms]
matches = []
normalized_terms = [normalize(term) for term in terms]
ranked = []
for row in rows:
haystack = " ".join(
[
row.get("name", ""),
row.get("signature", ""),
row.get("module", ""),
row.get("tags", ""),
row.get("summary", ""),
row.get("kind", ""),
row.get("binding", ""),
row.get("visibility", ""),
row.get("owner", ""),
row.get("qualified_name", ""),
]
).casefold()
if all(term in haystack for term in lowered_terms):
matches.append(row)
return matches
scores = [term_score(row, term) for term in normalized_terms]
if scores and all(scores):
coverage_bonus = sum(
bonus
for field, bonus in SEMANTIC_COVERAGE_BONUSES
if field_covers_terms(row, field, normalized_terms)
)
ranked.append((sum(scores) + coverage_bonus, row))
ranked.sort(key=lambda item: (-item[0], *keyword_sort_key(item[1])))
return [row for _, row in ranked]
def slug(text):
@@ -334,12 +373,6 @@ def codegen_root_for_tsv(tsv_path):
return DEFAULT_CODEGEN_ROOT
def default_tsv_path():
if DEFAULT_TSV.is_file():
return DEFAULT_TSV
return find_tsv(Path.cwd())
def main(argv=None):
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8")
@@ -372,15 +405,24 @@ def main(argv=None):
"--kw",
nargs="+",
type=non_empty,
help="按关键词检索候选清单多个词是 AND 关系(全部命中才返回)"
"行搜索 name、signature、module、tags、summary、kind、binding、"
"visibility、owner 和 qualified_name 这些列的拼接文本,"
"大小写不敏感且按子串匹配。只返回摘要表格,不含条目正文",
help="按关键词检索候选清单多个查询词是 AND 关系;"
"词在 name、signature、tags、summary、module、scope、kind、binding、"
"visibility、owner 和 qualified_name 中做字面子串匹配,按字段加权并稳定排序。"
"同义词由索引的 tags 字段提供。"
"大小写不敏感,只返回摘要表格,不含条目正文",
)
parser.add_argument(
"--tsv",
metavar="PATH",
help="显式指定 function_index.tsv;默认使用本 skill 内置的 data/function_index.tsv",
help="显式指定 function_index.tsv;默认使用本 skill 内置的 "
"data/function_index.tsv,不从工作目录回退查找旧索引",
)
parser.add_argument(
"--scope",
type=non_empty,
metavar="SCOPE",
help="只查询指定 scope,大小写不敏感;作用于 --name 和 --kw。"
"内置索引当前提供 builtin 与 dotnet",
)
parser.add_argument(
"--limit",
@@ -394,8 +436,8 @@ def main(argv=None):
if args.limit < 1:
parser.error("--limit must be >= 1")
tsv_path = Path(args.tsv) if args.tsv else default_tsv_path()
if not tsv_path or not tsv_path.is_file():
tsv_path = Path(args.tsv) if args.tsv else DEFAULT_TSV
if not tsv_path.is_file():
print(
"ERROR: function_index.tsv not found; reinstall tsl-api-reference "
"or pass --tsv PATH",
@@ -415,6 +457,20 @@ def main(argv=None):
file=sys.stderr,
)
return 1
if args.scope is not None:
requested_scope = normalize(args.scope)
available_scopes = sorted(
{row["scope"] for row in rows if row.get("scope")},
key=normalize,
)
if requested_scope not in {normalize(scope) for scope in available_scopes}:
print(
f"ERROR: unknown scope {args.scope!r}; available scopes: "
f"{', '.join(available_scopes)}",
file=sys.stderr,
)
return 2
rows = [row for row in rows if normalize(row["scope"]) == requested_scope]
codegen_root = codegen_root_for_tsv(tsv_path)
if args.name is not None:
@@ -450,6 +506,8 @@ def main(argv=None):
print(format_row(row))
if len(matches) > args.limit:
print(f"... {len(matches) - args.limit} more; refine keywords or raise --limit")
if not matches:
print("No matching API candidates; do not infer an API name.")
return 0