示例插件
Hello World
最简单的插件示例:
javascript
/* hello - TSH Hello World Plugin */
var name = args.slice(1).join(' ').trim() || 'World'
return '\x1b[32mHello, ' + name + '!\x1b[0m\r\n'安装和使用:
bash
plugin install /path/to/hello.js
hello
# 输出: Hello, World!
hello TSH
# 输出: Hello, TSH!calx — 计算器插件
calx 是 TSH 内置的计算器插件,支持数学表达式计算。
用法
bash
calx 2+3*4 # 输出: 14
calx sqrt(144) # 输出: 12
calx sin(PI/2) # 输出: 1
calx "1 + 2 * 3" # 输出: 7
calx 2**10 # 输出: 1024
calx 10 % 3 # 输出: 1支持的运算符
| 运算符 | 说明 |
|---|---|
+ - | 加减 |
* / | 乘除 |
% | 取模 |
** 或 ^ | 幂运算 |
() | 括号优先级 |
支持的函数
| 函数 | 说明 |
|---|---|
sin cos tan | 三角函数 |
asin acos atan | 反三角函数 |
sqrt | 平方根 |
abs | 绝对值 |
log | 常用对数 (log10) |
ln | 自然对数 |
ceil floor round | 取整 |
min max | 最值 |
pow exp | 幂/指数 |
cbrt sign trunc | 立方根/符号/截断 |
常量
| 常量 | 值 |
|---|---|
PI | 3.141592653589793 |
E | 2.718281828459045 |
错误处理
bash
calx
# 输出: calx: no expression provided (红色)
calx 1/0
# 输出: calx: division by zero (红色)
calx 2+
# 输出: calx: unexpected end of expression (红色)核心实现
calx 使用手写的递归下降解析器:
- 词法分析 — 将表达式拆分为数字、运算符、标识符 Token
- 递归下降解析 — 按优先级解析:表达式 → 项 → 幂 → 一元 → 基元
- 求值 — 解析同时计算结果
parseExpr → parseTerm (+|-) parseTerm
parseTerm → parsePower (*|/|%) parsePower
parsePower → parseUnary (** ) parsePower
parseUnary → (-|+) parseUnary | parsePrimary
parsePrimary → number | function(args) | (expr) | constantck — 设备检测插件
ck 检测访问网页的设备信息、IP 地址和浏览器指纹。
用法
bash
ck # 显示所有信息
ck device # 仅设备信息
ck screen # 仅屏幕信息
ck browser # 仅浏览器信息
ck ip # 仅 IP/网络信息
ck fp # 仅浏览器指纹检测项目
| 分类 | 项目 |
|---|---|
| Device | 设备类型、OS、平台、CPU 核心数、内存、触控 |
| Screen | 分辨率、可用区域、色深、像素比 |
| Browser | 浏览器版本、语言、Cookies、DNT、在线状态、时区、连接类型 |
| Network | 公网 IP、地理位置、ISP |
| Fingerprint | Canvas 哈希、WebGL 厂商/渲染器、设备综合指纹 |
输出示例
▸ Device
Type: Desktop
OS: Windows 10/11
CPU Cores: 8
Memory: 8 GB
▸ Network
IP Address: 203.0.113.42
Location: Shanghai, Shanghai, China | ISP: China Telecom
▸ Fingerprint
Canvas Hash: A1B2C3D4
Device FP: E5F6A7B8技术要点
- IP 检测 — 客户端 fetch
ipwho.is(返回 IP+地理+ISP),失败回退api.ipify.org - Canvas 指纹 — 绘制特定图形后用 DJB2 哈希生成 8 位标识
- WebGL 指纹 — 通过
WEBGL_debug_renderer_info获取 GPU 厂商和渲染器 - 异步支持 — 返回 async IIFE 的 Promise
管道插件示例
利用 stdin 处理管道输入:
javascript
/* wc - 统计行数/单词数 */
var text = stdin || ''
if (!text) return '0 0\r\n'
var lines = text.split('\n').length
var words = text.trim().split(/\s+/).filter(function(w) { return w }).length
return lines + ' ' + words + '\r\n'使用:
bash
echo "hello world foo" | wc
# 输出: 1 3异步插件示例
调用外部 API 获取数据:
javascript
/* weather - 天气查询 */
var city = args.slice(1).join(' ').trim()
if (!city) return '\x1b[31mweather: please specify a city\x1b[0m\r\n'
return (async function() {
try {
var resp = await fetch('https://wttr.in/' + encodeURIComponent(city) + '?format=3')
var text = await resp.text()
return '\x1b[36m' + text.trim() + '\x1b[0m\r\n'
} catch(e) {
return '\x1b[31mweather: ' + e.message + '\x1b[0m\r\n'
}
})()文件操作插件示例
通过 host 读取文件:
javascript
/* head - 显示文件前几行 */
var file = args[1]
if (!file) return '\x1b[31mhead: missing filename\x1b[0m\r\n'
var n = parseInt(args[2]) || 10
return (async function() {
try {
var content = await host.readFile(file)
var lines = content.split('\n').slice(0, n)
return lines.join('\r\n') + '\r\n'
} catch(e) {
return '\x1b[31mhead: ' + e.message + '\x1b[0m\r\n'
}
})()发布插件
将插件 JS 文件上传到任意可访问的 URL,然后安装:
bash
# GitHub
plugin install https://github.com/user/repo/raw/main/myplugin.js
# Codeberg
plugin install https://codeberg.org/user/repo/raw/branch/main/myplugin.js
# Gist
plugin install gist:user/gist_id
# 本地路径(需 TSH 内置)
plugin install /plugins/myplugin.jsCORS 说明
外部 URL 的插件通过 TSH Worker 的 /proxy 端点代理加载,无需目标服务器支持 CORS。任意 HTTPS URL 均可使用。