API 参考¶
Tinyleaf 暴露 RESTful HTTP API,由浏览器前端消费。所有响应使用 UTF-8 编码。错误统一返回 {"error": "描述"}。
单项目 vs. 多项目模式
在单项目模式下,项目管理端点(POST /api/projects、DELETE 等)不可用。在多项目模式下,所有端点均可用。
模式与 Docker¶
GET /api/mode¶
返回服务器模式和 Docker 配置。
响应:
{
"mode": "single",
"docker": true,
"image": "oaklight/texlive:alpine-science-cn",
"version": "0.1.0"
}
GET /api/docker/images¶
列出可用的 Docker 镜像标签及是否已本地拉取。
响应:
[
{"tag": "alpine-science-cn", "name": "oaklight/texlive:alpine-science-cn", "local": true},
{"tag": "alpine-science", "name": "oaklight/texlive:alpine-science", "local": false}
]
POST /api/docker/pull¶
拉取 Docker 镜像。拉取完成后返回。
请求: {"image": "oaklight/texlive:alpine-science"}
响应: {"success": true, "message": "Pulled oaklight/texlive:alpine-science"}
POST /api/docker/rmi¶
删除本地 Docker 镜像。
请求: {"image": "oaklight/texlive:alpine-science"}
响应: {"success": true, "message": "Removed oaklight/texlive:alpine-science"}
项目¶
GET /api/projects¶
列出所有已注册项目。
响应:
[
{
"name": "my-thesis",
"path": "/home/user/documents/thesis",
"added_at": "2025-01-15T10:30:00",
"exists": true,
"git": true
}
]
| 字段 | 类型 | 说明 |
|---|---|---|
name |
string | 项目显示名称 |
path |
string | 绝对文件系统路径 |
exists |
bool | 目录是否存在于磁盘上 |
git |
bool | 目录是否为 Git 仓库 |
POST /api/projects¶
创建包含默认 main.tex 的新项目。
请求:
响应(201):
错误: 409 目录已存在,400 名称无效。
POST /api/projects/register¶
注册已有目录为项目。
请求:
name 字段可选 — 默认使用目录名。
响应(201):
DELETE /api/projects/{name}¶
取消注册项目。可选择同时从磁盘删除文件。
请求:
响应:
POST /api/projects/{name}/rename-project¶
重命名项目的显示名称。
请求: {"new_name": "thesis-v2"}
响应: {"old_name": "my-thesis", "new_name": "thesis-v2"}
文件系统浏览¶
GET /api/fs/browse?path={dir_path}¶
列出指定路径下的子目录。供"打开文件夹"对话框使用。
响应:
文件¶
GET /api/projects/{name}/files¶
返回完整文件树(嵌套结构)。
响应:
[
{
"name": "main.tex",
"path": "main.tex",
"type": "file",
"mtime": 1706000000
},
{
"name": "sections",
"path": "sections",
"type": "dir",
"children": [
{"name": "intro.tex", "path": "sections/intro.tex", "type": "file", "mtime": 1706000000}
]
}
]
GET /api/projects/{name}/files/{file_path}¶
读取文件内容(仅 UTF-8 文本文件)。
响应:
错误: 400 二进制文件,404 文件不存在。
GET /api/projects/{name}/check/{file_path}¶
检查文件是否存在并获取修改时间。用于检测外部更改。
响应:
文件不存在时返回 {"exists": false}。
PUT /api/projects/{name}/files/{file_path}¶
写入文件内容。自动创建父目录。
请求:
响应: {"path": "main.tex", "saved": true}
DELETE /api/projects/{name}/files/{file_path}¶
删除文件或目录(递归删除)。
响应: {"path": "old-file.tex", "deleted": true}
POST /api/projects/{name}/mkdir¶
创建新目录。
请求: {"path": "figures/plots"}
响应: {"path": "figures/plots", "created": true}
错误: 409 路径已存在。
POST /api/projects/{name}/rename¶
重命名或移动文件/目录。
请求:
响应: {"old_path": "intro.tex", "new_path": "sections/intro.tex", "renamed": true}
POST /api/projects/{name}/upload¶
通过 multipart 表单上传文件。
请求: Content-Type: multipart/form-data
| 字段 | 类型 | 说明 |
|---|---|---|
files |
file(s) | 一个或多个文件 |
target_dir |
string | 可选目标子目录路径 |
响应:
配置¶
GET /api/projects/{name}/config¶
读取项目配置。若无 .tinyleaf.json 则返回自动检测值。
响应:
{
"main_file": "main.tex",
"engine": "pdflatex",
"use_docker": true,
"docker_image": "oaklight/texlive:alpine-science-cn"
}
PUT /api/projects/{name}/config¶
更新项目配置。字段与现有值合并。
请求:
响应: 合并后的完整配置对象。
GET /api/settings¶
读取全局设置(仅多项目模式)。
PUT /api/settings¶
更新全局设置。与现有值合并。
请求:
编译¶
POST /api/projects/{name}/compile¶
启动异步编译任务。
请求(所有字段可选):
{
"main_file": "main.tex",
"engine": "pdflatex",
"use_docker": true,
"docker_image": "oaklight/texlive:alpine-science-cn"
}
响应:
GET /api/projects/{name}/compile/{compile_id}/stream¶
编译日志的 Server-Sent Events (SSE) 流。
事件类型:
| 事件 | 数据 | 说明 |
|---|---|---|
log |
{"line": "...", "level": "info"} |
一行编译输出 |
done |
{"status": "success", "pdf_url": "/api/projects/.../output/main.pdf"} |
编译完成 |
level 字段为 info、warning 或 error。status 字段为 success、error 或 cancelled。
POST /api/projects/{name}/compile/{compile_id}/cancel¶
取消正在运行的编译。
响应: {"cancelled": true}
GET /api/projects/{name}/output/{file_path}¶
下载编译产物(PDF、图片等)。返回二进制文件并设置相应的 Content-Type。
POST /api/projects/{name}/clean¶
清除 LaTeX 构建产物(.aux、.log、.synctex.gz 等)。
响应:
Git¶
所有 Git 端点在项目非 Git 仓库时返回 {"git": false}。
GET /api/projects/{name}/git/status¶
响应:
{
"git": true,
"branch": "main",
"files": [
{"path": "main.tex", "status": "M"},
{"path": "new-file.tex", "status": "??"}
],
"ahead": 1,
"behind": 0
}
状态码遵循 git porcelain 格式:M(已修改)、A(已添加)、D(已删除)、??(未跟踪)等。
GET /api/projects/{name}/git/diff¶
返回完整项目差异(纯文本)。
GET /api/projects/{name}/git/diff/{file_path}¶
返回单个文件的差异(纯文本)。
GET /api/projects/{name}/git/log¶
返回最近 20 条提交。
响应:
[
{
"hash": "a1b2c3d",
"message": "Add introduction section",
"author": "Alice",
"date": "2025-01-15T10:30:00"
}
]
POST /api/projects/{name}/git/commit¶
暂存文件并创建提交。
请求:
省略 files 时暂存所有已更改文件。
响应: {"success": true, "message": "Committed a1b2c3d"}
POST /api/projects/{name}/git/push¶
推送到远程仓库。
响应: {"success": true, "message": "Pushed to origin/main"}
POST /api/projects/{name}/git/pull¶
从远程仓库拉取。
响应: {"success": true, "message": "Already up to date"}
SyncTeX¶
SyncTeX 提供源文件与编译 PDF 之间的双向导航。需要编译时生成的 .synctex.gz 文件(tinyleaf 默认使用 -synctex=1 编译)。
GET /api/projects/{name}/synctex?page={N}&x={X}&y={Y}¶
反向搜索:根据 PDF 页面上的位置查找对应源码位置。
查询参数:
| 参数 | 类型 | 说明 |
|---|---|---|
page |
int | 从 1 开始的页码 |
x |
float | 水平位置,PDF 点(72 DPI) |
y |
float | 垂直位置,PDF 点(72 DPI) |
响应:
错误: 404 无 SyncTeX 文件或无匹配结果。
GET /api/projects/{name}/synctex/forward?file={path}&line={N}¶
正向搜索:根据源文件和行号查找 PDF 对应位置。
查询参数:
| 参数 | 类型 | 说明 |
|---|---|---|
file |
string | 源文件路径(相对于项目根目录) |
line |
int | 从 1 开始的行号 |
响应:
坐标单位为 PDF 点(72 DPI)。
错误: 400 缺少参数,404 无 SyncTeX 文件或无匹配结果。
搜索¶
GET /api/projects/{name}/search?q={keyword}&case={0|1}¶
在项目所有文件中搜索文本(grep 风格)。自动跳过二进制文件和隐藏目录(.git、__pycache__ 等)。
查询参数:
| 参数 | 类型 | 说明 |
|---|---|---|
q |
string | 搜索关键词(必填) |
case |
0 或 1 |
区分大小写搜索(默认:0) |
响应:
{
"query": "documentclass",
"case_sensitive": false,
"results": {
"main.tex": [
{"line": 1, "text": "\\documentclass{article}"}
],
"sections/intro.tex": [
{"line": 3, "text": "% see documentclass options above"}
]
},
"total": 2,
"truncated": false
}
| 字段 | 类型 | 说明 |
|---|---|---|
results |
object | 按相对文件路径分组的匹配结果 |
total |
int | 匹配行总数 |
truncated |
bool | 结果超过 500 条上限时为 true |
错误: 400 缺少 q 参数。