✨ feat(tsl-api-reference): improve tagged API discovery
This commit is contained in:
@@ -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)`
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user