feat: add journal submission kits + paper scaffold; restructure package
- init journal <elsevier|ieee|springer>: self-contained, make-buildable kits (Springer sn-jnl.cls + bst bundled; reuses project references.bib) - init paper scaffold: ctexart + Fandol fonts, bib at root, latexdiff highlighted - move templates/ under mytoolkit/, add info/references, relocate protocols - migrate mytoolkit skill into submodule; update README/CLAUDE docs
This commit is contained in:
@@ -0,0 +1,86 @@
|
|||||||
|
---
|
||||||
|
name: mytoolkit
|
||||||
|
description: |
|
||||||
|
个人 CLI 工具集 mytoolkit 的入口。涵盖:通用格式转换 (convert)、Markdown→PDF (Typst)、
|
||||||
|
PDF 处理、图片转换、LaTeX 编译、BibTeX 处理、视频转换、Docusaurus 网站构建、邮件管理等。
|
||||||
|
用于:文件格式转换、批量处理、压缩优化、文档生成。
|
||||||
|
详情见 references/ 子目录(convert.md / pdf.md / image.md / latex.md / bib.md / video.md / webpage.md / mail.md / others.md)。
|
||||||
|
user-invocable: true
|
||||||
|
triggers:
|
||||||
|
- mytoolkit
|
||||||
|
- convert
|
||||||
|
- 转换格式
|
||||||
|
- md-to-pdf
|
||||||
|
- markdown转pdf
|
||||||
|
- 转pdf
|
||||||
|
- 压缩pdf
|
||||||
|
- 合并pdf
|
||||||
|
- 图片转pdf
|
||||||
|
- 压缩图片
|
||||||
|
- latex编译
|
||||||
|
- bib转markdown
|
||||||
|
- avi转mp4
|
||||||
|
- 更新mytoolkit
|
||||||
|
---
|
||||||
|
|
||||||
|
# MyToolkit 个人 CLI 工具集
|
||||||
|
|
||||||
|
`mytoolkit` 是日常文件处理、格式转换、批量操作的便捷工具集。所有命令统一在 `mytoolkit` 命名空间下,支持 zsh tab completion。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
eval "$(_MYTOOLKIT_COMPLETE=zsh_source mytoolkit)"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 与其他 Skill 的分工
|
||||||
|
|
||||||
|
| 场景 | 该用哪个 Skill |
|
||||||
|
|------|---------------|
|
||||||
|
| 通用格式转换(MD→PDF、图片→PDF、PDF 压缩等) | **mytoolkit** `convert` |
|
||||||
|
| PDF/图片/视频 细节操作 | **mytoolkit** `pdf` / `image` / `video` |
|
||||||
|
| LaTeX 编译 | **mytoolkit** `latex compile` |
|
||||||
|
| 简历内容更新 + 生成 PDF | **mycv**(`mytoolkit convert cv-zh.md -o cv-zh.pdf -t cv`) |
|
||||||
|
| 课题组网站内容更新 | **mywebpage**(Docusaurus 内容维护) |
|
||||||
|
| 邮件收发 | **mail**(`mytoolkit mail` 命令,由 mail skill 主导) |
|
||||||
|
|
||||||
|
## 子命令导航
|
||||||
|
|
||||||
|
| 子命令 | 场景 | 详情 |
|
||||||
|
|--------|------|----------|
|
||||||
|
| `convert` | 通用格式转换:MD→PDF/Word、图片→PDF、PDF 压缩、EPS→PDF、AVI→MP4、BibTeX→Markdown | `mytoolkit info docs convert` |
|
||||||
|
| `pdf` | PDF 细粒度操作:压缩、裁剪、合并、书签层级调整、PDF→TIFF | `mytoolkit info docs pdf` |
|
||||||
|
| `image` | 图片处理:压缩、EPS 修复、AI 生图 | `references/image.md` |
|
||||||
|
| `latex` | LaTeX 编译、字数统计 | `references/latex.md` |
|
||||||
|
| `bib` | BibTeX→Markdown、CV 引用更新 | `references/bib.md` |
|
||||||
|
| `video` | 视频格式转换 | `references/video.md` |
|
||||||
|
| `webpage` | Docusaurus 网站构建、部署、server 管理 | `mytoolkit info docs webpage` |
|
||||||
|
| `mail` | 邮箱管理(inbox、read、draft) | `references/mail.md` |
|
||||||
|
| `env/git/ssh/server/update/uninstall` | 其他辅助命令 | `references/others.md` |
|
||||||
|
|
||||||
|
> 注:`convert`、`pdf`、`webpage` 的完整参考文档已随 mytoolkit 包安装,通过 `mytoolkit info docs <name>` 直接读取;技能内 `references/` 仅保留速查。
|
||||||
|
|
||||||
|
## 快速决策表
|
||||||
|
|
||||||
|
| 需求 | 推荐命令 |
|
||||||
|
|------|---------|
|
||||||
|
| Markdown 转 PDF | `mytoolkit convert doc.md -o doc.pdf [-t cv/textbook/manual]` |
|
||||||
|
| 压缩 PDF | `mytoolkit convert large.pdf -o small.pdf -q screen` |
|
||||||
|
| 合并 PDF/图片 | `mytoolkit pdf merge *.pdf *.png -o out.pdf` |
|
||||||
|
| EPS 插图转 PDF | `mytoolkit convert fig.eps -o fig.pdf` |
|
||||||
|
| 图片太大需压缩 | `mytoolkit image compress *.jpg -t 2.0` |
|
||||||
|
| 照片合成 PDF | `mytoolkit convert *.jpg -o album.pdf` |
|
||||||
|
| LaTeX 编译 | `mytoolkit latex compile paper.tex` |
|
||||||
|
| BibTeX 转 Markdown | `mytoolkit convert refs.bib -o refs.md` |
|
||||||
|
| AVI 视频转 MP4 | `mytoolkit convert video.avi -o video.mp4` |
|
||||||
|
| 更新工具本身 | `cd mytoolkit && make install` |
|
||||||
|
|
||||||
|
## 安装与更新
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/workspace/contrib/mytoolkit && make install
|
||||||
|
mytoolkit --version
|
||||||
|
mytoolkit templates list
|
||||||
|
```
|
||||||
|
|
||||||
|
> **重要**:修改 `contrib/mytoolkit` 中的源码、或用 `git pull` / `git submodule update` 拉取更新后,**都必须重新执行 `make install`**(或 `mytoolkit update`)。Python 的 editable 安装不会自动跟踪源码改动,不重装则 CLI 调用的仍是旧版本。验证方式:`mytoolkit --version` 或 `which mytoolkit`。
|
||||||
|
|
||||||
|
> **唯一真源**:mytoolkit 的具体用法、命令参数、模板说明以 **已安装的 mytoolkit 包** 为准。读取详细文档时,先运行 `mytoolkit info paths` 查看资源路径,或用 `mytoolkit info docs <name>` 直接打印参考文档。若 `mytoolkit` 命令不可用,可按默认开发路径 `~/workspace/contrib/mytoolkit/` 查找。本 skill 的 `references/` 仅作为速查补充。
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# BibTeX(bib)
|
||||||
|
|
||||||
|
> 详细用法以 **mytoolkit 项目 README.md** 为准(可用 `mytoolkit info paths` 辅助定位)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit bib to-markdown refs.bib -o refs.md
|
||||||
|
mytoolkit bib cv-update
|
||||||
|
```
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
> 完整文档:`mytoolkit info docs convert`(不依赖 workspace 路径)。
|
||||||
|
> 本文档仅保留最常用速查。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Markdown → PDF
|
||||||
|
mytoolkit convert doc.md -o doc.pdf
|
||||||
|
mytoolkit convert doc.md -o doc.pdf -t cv
|
||||||
|
mytoolkit convert ch1.md ch2.md -o book.pdf -t textbook
|
||||||
|
|
||||||
|
# Markdown → Word
|
||||||
|
mytoolkit convert doc.md -o doc.docx
|
||||||
|
|
||||||
|
# 图片 / EPS → PDF
|
||||||
|
mytoolkit convert fig.eps -o fig.pdf
|
||||||
|
mytoolkit convert *.jpg -o album.pdf
|
||||||
|
|
||||||
|
# PDF 压缩 / PDF → TIFF / AVI → MP4 / BibTeX → Markdown
|
||||||
|
mytoolkit convert large.pdf -o small.pdf -q screen
|
||||||
|
mytoolkit convert scan.pdf -o scan.tiff -d 300
|
||||||
|
mytoolkit convert video.avi -o video.mp4
|
||||||
|
mytoolkit convert refs.bib -o refs.md
|
||||||
|
```
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# 图片处理(image)
|
||||||
|
|
||||||
|
> 详细用法以 **mytoolkit 项目 README.md** 为准(可用 `mytoolkit info paths` 辅助定位)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 压缩图片(自动调整尺寸/质量)
|
||||||
|
mytoolkit image compress *.png -t 2.0
|
||||||
|
mytoolkit image compress photo.jpg -w 1920 -q 85
|
||||||
|
|
||||||
|
# EPS 修复
|
||||||
|
mytoolkit image eps-fix broken.eps
|
||||||
|
|
||||||
|
# AI 生成图片(豆包/Seedream)
|
||||||
|
mytoolkit image generate "prompt" -o output.png
|
||||||
|
```
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# LaTeX(latex)
|
||||||
|
|
||||||
|
> 详细用法以 **mytoolkit 项目 README.md** 为准(可用 `mytoolkit info paths` 辅助定位)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit latex compile paper.tex
|
||||||
|
mytoolkit latex compile paper.tex -e xelatex
|
||||||
|
mytoolkit latex count paper.tex
|
||||||
|
```
|
||||||
|
|
||||||
|
## 论文脚手架 / 投稿模板
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit init paper <dir> # 新建论文项目(ctexart + Fandol 跨平台字体)
|
||||||
|
mytoolkit init journal # 列出投稿套件
|
||||||
|
mytoolkit init journal elsevier # Elsevier / ieee / springer 套件 → ./submit-<name>/
|
||||||
|
```
|
||||||
|
|
||||||
|
投稿套件自带文档类与 bst,`make`(pdflatex+bibtex)直接编译;自动复用当前目录 `references.bib`。Springer 切样式只改 `\documentclass[...,sn-xxx]{sn-jnl}` 选项,勿写 `\bibliographystyle`。详见 CLAUDE.md §3。
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# 邮件(mail)
|
||||||
|
|
||||||
|
> 详见 `mail` skill。核心命令如下,完整用法以 **mytoolkit 项目 README.md** 为准(可用 `mytoolkit info paths` 辅助定位)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit mail inbox --limit 10
|
||||||
|
mytoolkit mail read <UID>
|
||||||
|
mytoolkit mail download <UID> -o ~/Downloads
|
||||||
|
mytoolkit mail draft --to xxx@example.com --subject "..." --body "..."
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**:
|
||||||
|
- `<UID>` 为真 IMAP UID(`inbox` 列出的就是),跨会话稳定
|
||||||
|
- ⚠️ **绝对禁止发送邮件** —— `draft`/`reply`/`forward` 仅保存到 Drafts,**不会**且**不应**自动发送;即便用户说“发出去”,也只能生成草稿并提示用户去 Web 端点击发送
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# 其他命令
|
||||||
|
|
||||||
|
> 详细用法以 **mytoolkit 项目 README.md** 为准(可用 `mytoolkit info paths` 辅助定位)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit init paper <dir> # 初始化 LaTeX 论文项目
|
||||||
|
mytoolkit env # 环境变量管理
|
||||||
|
mytoolkit git # Git 辅助工具
|
||||||
|
mytoolkit ssh # SSH 快捷连接
|
||||||
|
mytoolkit server # 开发服务器管理
|
||||||
|
mytoolkit update # 从本地仓库更新
|
||||||
|
mytoolkit uninstall # 卸载
|
||||||
|
```
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
> 完整文档:`mytoolkit info docs pdf`(不依赖 workspace 路径)。
|
||||||
|
> 本文档仅保留最常用速查。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 压缩
|
||||||
|
mytoolkit pdf compress paper.pdf -q ebook
|
||||||
|
|
||||||
|
# 裁剪 / 合并 / 调整书签层级
|
||||||
|
mytoolkit pdf crop figure.pdf
|
||||||
|
mytoolkit pdf merge ch*.pdf -o book.pdf
|
||||||
|
mytoolkit pdf bookmark report.pdf --depth 2
|
||||||
|
|
||||||
|
# PDF → TIFF
|
||||||
|
mytoolkit pdf to-tiff scan.pdf -d 300
|
||||||
|
```
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# 视频(video)
|
||||||
|
|
||||||
|
> 详细用法以 **mytoolkit 项目 README.md** 为准(可用 `mytoolkit info paths` 辅助定位)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit video avi-to-mp4 recording.avi
|
||||||
|
```
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
> 完整文档:`mytoolkit info docs webpage`(不依赖 workspace 路径)。
|
||||||
|
> 本文档仅保留最常用速查。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit webpage list
|
||||||
|
mytoolkit webpage mywebpage build --serve
|
||||||
|
mytoolkit webpage mywebpage rebuild
|
||||||
|
mytoolkit webpage mywebpage push
|
||||||
|
mytoolkit webpage mywebpage pdf build
|
||||||
|
```
|
||||||
@@ -12,3 +12,4 @@ build/
|
|||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
.mypy_cache/
|
.mypy_cache/
|
||||||
tmp/
|
tmp/
|
||||||
|
.DS_Store
|
||||||
|
|||||||
@@ -5,12 +5,13 @@ PYTHON ?= python3
|
|||||||
# 手动安装的文件清单(与 bin/commands/self_mgmt.py 中的 _MANUAL_FILES 保持同步)
|
# 手动安装的文件清单(与 bin/commands/self_mgmt.py 中的 _MANUAL_FILES 保持同步)
|
||||||
MANUAL_FILES := $(COMP_DIR)/_mytoolkit $(COMP_DIR)/mytoolkit.bash
|
MANUAL_FILES := $(COMP_DIR)/_mytoolkit $(COMP_DIR)/mytoolkit.bash
|
||||||
|
|
||||||
.PHONY: help install uninstall
|
.PHONY: help install uninstall sync-skill
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Usage: make [target]"
|
@echo "Usage: make [target]"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " install Install mytoolkit in editable mode (current Python)"
|
@echo " install Install mytoolkit in editable mode (current Python) and sync skill"
|
||||||
|
@echo " sync-skill Copy the bundled Claude skill to ~/.claude/skills/mytoolkit/"
|
||||||
@echo " uninstall Uninstall mytoolkit and remove completions"
|
@echo " uninstall Uninstall mytoolkit and remove completions"
|
||||||
|
|
||||||
install:
|
install:
|
||||||
@@ -27,6 +28,17 @@ install:
|
|||||||
echo "bash completion: $(COMP_DIR)/mytoolkit.bash" || \
|
echo "bash completion: $(COMP_DIR)/mytoolkit.bash" || \
|
||||||
echo "Warning: bash completion failed"; \
|
echo "Warning: bash completion failed"; \
|
||||||
fi
|
fi
|
||||||
|
@$(MAKE) -s sync-skill
|
||||||
|
|
||||||
|
sync-skill:
|
||||||
|
@echo "Syncing Claude skill to ~/.claude/skills/mytoolkit/ ..."
|
||||||
|
@mkdir -p "$(HOME)/.claude/skills"
|
||||||
|
@if command -v rsync >/dev/null 2>&1; then \
|
||||||
|
rsync -av --delete "$(ROOT_DIR)/.claude/skills/mytoolkit/" "$(HOME)/.claude/skills/mytoolkit/"; \
|
||||||
|
else \
|
||||||
|
rm -rf "$(HOME)/.claude/skills/mytoolkit"; \
|
||||||
|
cp -R "$(ROOT_DIR)/.claude/skills/mytoolkit" "$(HOME)/.claude/skills/mytoolkit"; \
|
||||||
|
fi
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
$(PYTHON) -m pip uninstall mytoolkit -y
|
$(PYTHON) -m pip uninstall mytoolkit -y
|
||||||
|
|||||||
@@ -5,20 +5,33 @@ Personal CLI toolkit — unified entry point for everyday file conversion, forma
|
|||||||
## Install
|
## Install
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make install # builds + symlinks ~/.local/bin/mytoolkit
|
make install # install CLI + sync bundled Claude skill
|
||||||
mytoolkit --version
|
mytoolkit --version
|
||||||
mytoolkit templates register ~/workspace/contrib/mytoolkit/templates # one-time, points at template root
|
mytoolkit templates list # verify bundled templates are found
|
||||||
|
```
|
||||||
|
|
||||||
|
`make install` 会同时:
|
||||||
|
1. 用 editable 模式安装 `mytoolkit`;
|
||||||
|
2. 生成 zsh/bash 补全;
|
||||||
|
3. 把 bundled Claude skill 同步到 `~/.claude/skills/mytoolkit/`。
|
||||||
|
|
||||||
|
单独同步 skill(不重装 Python 包):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make sync-skill
|
||||||
```
|
```
|
||||||
|
|
||||||
## Update
|
## Update
|
||||||
|
|
||||||
The installed Python package is **not** refreshed automatically when the source tree changes. After editing source files, or after `git pull` / `git submodule update`, rerun:
|
The installed Python package and the bundled Claude skill are **not** refreshed automatically when the source tree changes. After editing source files, skill docs, or after `git pull` / `git submodule update`, rerun:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make install # or: mytoolkit update
|
make install # or: mytoolkit update
|
||||||
mytoolkit --version # verify the new version is active
|
mytoolkit --version # verify the new version is active
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you only changed skill files (`SKILL.md` / `references/`), `make sync-skill` is enough.
|
||||||
|
|
||||||
## Top-level commands
|
## Top-level commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -28,6 +41,8 @@ mytoolkit --help
|
|||||||
| Command | What it does |
|
| Command | What it does |
|
||||||
|---------|--------------|
|
|---------|--------------|
|
||||||
| `convert` | Universal format conversion (md/img/pdf/eps/avi/bib → pdf/docx/tiff/mp4/md). Auto-detects from extensions. |
|
| `convert` | Universal format conversion (md/img/pdf/eps/avi/bib → pdf/docx/tiff/mp4/md). Auto-detects from extensions. |
|
||||||
|
| `init` | Initialize projects/kits from bundled templates (`mytoolkit init paper <dir>`, `mytoolkit init journal <name>`) |
|
||||||
|
| `info` | Show bundled resource paths (`info paths`, `info docs <name>`) |
|
||||||
| `pdf` | `compress` / `crop` / `merge` / `bookmark` / `to-tiff` |
|
| `pdf` | `compress` / `crop` / `merge` / `bookmark` / `to-tiff` |
|
||||||
| `image` | `compress` / `eps-fix` / `eps-to-pdf` / `jpg-to-pdf` / `tiff-to-pdf` / `tiff-compress` / `generate` (Doubao/Seedream) |
|
| `image` | `compress` / `eps-fix` / `eps-to-pdf` / `jpg-to-pdf` / `tiff-to-pdf` / `tiff-compress` / `generate` (Doubao/Seedream) |
|
||||||
| `latex` | `compile` / `count` |
|
| `latex` | `compile` / `count` |
|
||||||
@@ -35,7 +50,7 @@ mytoolkit --help
|
|||||||
| `video` | `avi-to-mp4` |
|
| `video` | `avi-to-mp4` |
|
||||||
| `webpage` | Docusaurus build/list/rebuild/push |
|
| `webpage` | Docusaurus build/list/rebuild/push |
|
||||||
| `mail` | IMAP/SMTP client (read/draft/forward/reply, no auto-send) |
|
| `mail` | IMAP/SMTP client (read/draft/forward/reply, no auto-send) |
|
||||||
| `templates` | Register and inspect external template root |
|
| `templates` | Inspect template root; external override still possible |
|
||||||
| `env` | Manage stored vars (api keys, paths, feishu app credentials) |
|
| `env` | Manage stored vars (api keys, paths, feishu app credentials) |
|
||||||
| `ssh` | `list` / `connect` / `tunnel` / `cmd` |
|
| `ssh` | `list` / `connect` / `tunnel` / `cmd` |
|
||||||
| `git` | `proxy` (set/unset/list/status) |
|
| `git` | `proxy` (set/unset/list/status) |
|
||||||
@@ -47,19 +62,42 @@ For any subcommand: `mytoolkit <cmd> --help`.
|
|||||||
|
|
||||||
## Templates
|
## Templates
|
||||||
|
|
||||||
`mytoolkit convert -t <name>` reads templates from an external directory you register (templates are not bundled). Layout:
|
`mytoolkit convert -t <name>` reads templates bundled with the package by default. External overrides are still supported via `mytoolkit templates register`.
|
||||||
|
|
||||||
|
Bundled layout:
|
||||||
|
|
||||||
```
|
```
|
||||||
<root>/md-to-pdf/<name>/template.typ
|
mytoolkit/templates/md-to-pdf/<name>/template.typ
|
||||||
<root>/md-to-docx/<name>/template.docx
|
mytoolkit/templates/md-to-docx/<name>/template.docx
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mytoolkit templates register /path/to/templates
|
mytoolkit templates list # lists bundled templates with absolute paths
|
||||||
mytoolkit templates list # lists each template with its absolute path
|
mytoolkit templates register /path/to/templates # optional external override
|
||||||
```
|
```
|
||||||
|
|
||||||
Registry is stored at `~/.mytoolkit/templates.json` (or `$MYTOOLKIT_HOME/templates.json`).
|
Registry is stored at `~/.mytoolkit/templates.json` (or `$MYTOOLKIT_HOME/templates.json`). When the registry is missing or invalid, mytoolkit falls back to the bundled templates.
|
||||||
|
|
||||||
|
## Project scaffolds
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit init paper <dir> # create a LaTeX paper project (ctexart + Fandol fonts)
|
||||||
|
```
|
||||||
|
|
||||||
|
This generates `main.tex`, `Makefile`, `references.bib`, `diffpreamble.dtx`, `figs/`, `analysis/`.
|
||||||
|
|
||||||
|
### Journal submission kits
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit init journal # list available kits
|
||||||
|
mytoolkit init journal elsevier # -> ./submit-elsevier/
|
||||||
|
mytoolkit init journal ieee mydir # custom target dir
|
||||||
|
```
|
||||||
|
|
||||||
|
Kits (`elsevier` / `ieee` / `springer`) are self-contained — `main.tex`, a
|
||||||
|
pdflatex+bibtex `Makefile`, and any non-bundled class files (Springer's
|
||||||
|
`sn-jnl.cls` + `bst/`). Each compiles standalone with `make`, and reuses the
|
||||||
|
current directory's `references.bib` if present.
|
||||||
|
|
||||||
## User config
|
## User config
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# MyToolkit 项目配置
|
# MyToolkit 项目配置
|
||||||
|
|
||||||
|
> **唯一真源**:本文档是 `.claude/skills/mytoolkit/` 的唯一真源。mytoolkit 的功能、命令、模板、约定以本文档和 `README.md` 为准;修改 mytoolkit 时请同步更新本文档,skill 本身只保留触发词和简要分工。
|
||||||
|
|
||||||
本项目是个人 CLI 工具集,命令入口为 `mytoolkit`。
|
本项目是个人 CLI 工具集,命令入口为 `mytoolkit`。
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -12,22 +14,33 @@ Markdown 为唯一源格式,正式文档统一通过 `mytoolkit` 生成,不
|
|||||||
|
|
||||||
| 目标格式 | 命令 | 模板 |
|
| 目标格式 | 命令 | 模板 |
|
||||||
|---------|------|------|
|
|---------|------|------|
|
||||||
| PDF | `mytoolkit convert doc.md -o doc.pdf [-t cv/textbook/manual]` | `templates/md-to-pdf/` (Typst) |
|
| PDF | `mytoolkit convert doc.md -o doc.pdf [-t cv/textbook/manual]` | `mytoolkit/templates/md-to-pdf/` (Typst) |
|
||||||
| Word | `mytoolkit convert doc.md -o doc.docx [-t default/review]` | `templates/md-to-docx/` |
|
| Word | `mytoolkit convert doc.md -o doc.docx [-t default/review]` | `mytoolkit/templates/md-to-docx/` |
|
||||||
|
|
||||||
- `templates/md-to-docx/` 含 `default/`(通用文档)和 `review/`(审稿意见)两个 reference docx 模板
|
- `mytoolkit/templates/md-to-docx/` 含 `default/`(通用文档)和 `review/`(审稿意见)两个 reference docx 模板
|
||||||
- `templates/md-to-pdf/` 为 Typst 模板目录,支撑 PDF 生成,直接修改模板需同步更新 mytoolkit
|
- `mytoolkit/templates/md-to-pdf/` 为 Typst 模板目录,支撑 PDF 生成,直接修改模板需同步更新 mytoolkit
|
||||||
|
|
||||||
### 例外:短文档直接手写 Word
|
### 例外:短文档直接手写 Word
|
||||||
|
|
||||||
**审稿意见、评审意见**等 1-2 页的短文档,可直接复制对应 reference docx 模板到目标目录,在 Word 里直接撰写和修改。无需先写 Markdown 再转换。
|
**审稿意见、评审意见**等 1-2 页的短文档,可直接复制对应 reference docx 模板到目标目录,在 Word 里直接撰写和修改。无需先写 Markdown 再转换。
|
||||||
|
|
||||||
- 模板路径:`templates/md-to-docx/review/template.docx`(审稿/评审意见)
|
- 模板路径:`mytoolkit/templates/md-to-docx/review/template.docx`(审稿/评审意见)
|
||||||
- 好处:省去转换步骤,用户可直接在 Word 中调整格式和内容
|
- 好处:省去转换步骤,用户可直接在 Word 中调整格式和内容
|
||||||
- 适用条件:单篇、无复杂版本控制需求、内容较短(通常 < 2 页)
|
- 适用条件:单篇、无复杂版本控制需求、内容较短(通常 < 2 页)
|
||||||
|
|
||||||
批量生成或需要版本控制时,仍回退到 Markdown → docx 工作流。
|
批量生成或需要版本控制时,仍回退到 Markdown → docx 工作流。
|
||||||
|
|
||||||
|
### 资源定位
|
||||||
|
|
||||||
|
模板、参考文档、项目脚手架都随 `mytoolkit` Python 包一起安装,不依赖仓库路径:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit info paths # 打印 package/templates/references/scaffolds 路径
|
||||||
|
mytoolkit info docs convert # 打印 convert 完整参考文档
|
||||||
|
```
|
||||||
|
|
||||||
|
skill 或其他脚本应通过上述命令定位资源,避免硬编码 `~/workspace/contrib/mytoolkit/`。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. 语音合成 (TTS)
|
## 2. 语音合成 (TTS)
|
||||||
@@ -57,7 +70,40 @@ mytoolkit voice tts "文本" -v zh_male_wennuanahu_moon_bigtts --format mp3 --sp
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. 依赖管理
|
## 3. LaTeX 论文脚手架与投稿模板
|
||||||
|
|
||||||
|
### 新建论文项目
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit init paper <dir> # ctexart + Fandol 跨平台中文字体;含 Makefile/diffpreamble/figs/analysis
|
||||||
|
```
|
||||||
|
|
||||||
|
脚手架结构:`main.tex`(`\documentclass[UTF8, fontset=fandol]{ctexart}`)、`references.bib`(根目录)、`Makefile`(latexmk + xelatex,`make` 编译、`make highlighted OLDTEX=...` 出 latexdiff 修订稿)、`figs/`、`analysis/`。字体用 **Fandol**(随 TeX Live 自带,Mac/Win/Linux 编译一致),英文/公式用默认 Latin Modern。
|
||||||
|
|
||||||
|
### 切换投稿期刊模板
|
||||||
|
|
||||||
|
各出版社“投稿套件”预置在包内 `mytoolkit/journals/`,一条命令落地到子目录,自包含、`make` 直接编译(pdflatex + bibtex):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit init journal # 列出可用套件
|
||||||
|
mytoolkit init journal elsevier # -> ./submit-elsevier/
|
||||||
|
mytoolkit init journal springer mydir
|
||||||
|
```
|
||||||
|
|
||||||
|
| 套件 | 文档类 | 类文件来源 |
|
||||||
|
|------|--------|-----------|
|
||||||
|
| `elsevier` | `elsarticle` | TeX Live 自带 |
|
||||||
|
| `ieee` | `IEEEtran` | TeX Live 自带 |
|
||||||
|
| `springer` | `sn-jnl` | 已随套件打包(含全部 `bst/` 样式) |
|
||||||
|
|
||||||
|
- 命令会**自动复用当前目录的 `references.bib`**(若存在)。
|
||||||
|
- 套件 Makefile 用 pdflatex(期刊惯例);`BSTINPUTS` 已配好,Springer 的 `bst/` 子目录样式可直接找到。
|
||||||
|
- **Springer 注意**:参考文献样式由 `\documentclass[...,sn-mathphys-num]{sn-jnl}` 选项决定,**不要再写 `\bibliographystyle`**(重复会让 bibtex 报错)。
|
||||||
|
- 升级 `sn-jnl.cls`:从 Springer 官网下载最新 zip,替换 `mytoolkit/journals/springer/` 下的 `sn-jnl.cls` 与 `bst/`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 依赖管理
|
||||||
|
|
||||||
项目使用 `uv` 管理依赖。修改 `pyproject.toml` 后运行 `uv sync` 同步。
|
项目使用 `uv` 管理依赖。修改 `pyproject.toml` 后运行 `uv sync` 同步。
|
||||||
|
|
||||||
@@ -67,7 +113,7 @@ uv sync
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. 命名规范
|
## 5. 命名规范
|
||||||
|
|
||||||
- **文件与文件夹**:英文统一使用 kebab-case,如 `review-comments.docx`
|
- **文件与文件夹**:英文统一使用 kebab-case,如 `review-comments.docx`
|
||||||
- **代码中的函数与变量**:统一使用 snake_case,如 `review_comments()`
|
- **代码中的函数与变量**:统一使用 snake_case,如 `review_comments()`
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ def synthesize_tts(
|
|||||||
Returns absolute path to the output audio file.
|
Returns absolute path to the output audio file.
|
||||||
"""
|
"""
|
||||||
# Delayed import to avoid circular dependency when bin.commands is not yet loaded
|
# Delayed import to avoid circular dependency when bin.commands is not yet loaded
|
||||||
from mytoolkit.commands.protocols import EventType, MsgType, full_client_request, receive_message
|
from mytoolkit.protocols import EventType, MsgType, full_client_request, receive_message
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import websockets
|
import websockets
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ from mytoolkit.commands import pdf, image, latex, video, bib, voice, docx
|
|||||||
from mytoolkit.commands.convert import convert_cmd
|
from mytoolkit.commands.convert import convert_cmd
|
||||||
from mytoolkit.commands.env import env_cmd
|
from mytoolkit.commands.env import env_cmd
|
||||||
from mytoolkit.commands.templates import templates_cmd
|
from mytoolkit.commands.templates import templates_cmd
|
||||||
|
from mytoolkit.commands.init import init_cmd
|
||||||
|
from mytoolkit.commands.info import info_cmd
|
||||||
from mytoolkit.commands.ssh import ssh_cmd
|
from mytoolkit.commands.ssh import ssh_cmd
|
||||||
from mytoolkit.commands.git import git_cmd
|
from mytoolkit.commands.git import git_cmd
|
||||||
from mytoolkit.commands.server import server_cmd
|
from mytoolkit.commands.server import server_cmd
|
||||||
@@ -35,6 +37,8 @@ cli.add_command(video.video)
|
|||||||
cli.add_command(bib.bib)
|
cli.add_command(bib.bib)
|
||||||
cli.add_command(env_cmd)
|
cli.add_command(env_cmd)
|
||||||
cli.add_command(templates_cmd)
|
cli.add_command(templates_cmd)
|
||||||
|
cli.add_command(init_cmd)
|
||||||
|
cli.add_command(info_cmd)
|
||||||
cli.add_command(ssh_cmd)
|
cli.add_command(ssh_cmd)
|
||||||
cli.add_command(git_cmd)
|
cli.add_command(git_cmd)
|
||||||
cli.add_command(server_cmd)
|
cli.add_command(server_cmd)
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
"""Show mytoolkit installation and bundled resource paths."""
|
||||||
|
|
||||||
|
import importlib.resources as resources
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
|
||||||
|
@click.group(name="info")
|
||||||
|
def info_cmd():
|
||||||
|
"""Show mytoolkit installation and bundled resource paths."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@info_cmd.command("paths")
|
||||||
|
def info_paths():
|
||||||
|
"""Print paths to bundled templates, references and scaffolds.
|
||||||
|
|
||||||
|
Useful for skills / scripts that need to locate mytoolkit resources without
|
||||||
|
hard-coding the repository path.
|
||||||
|
"""
|
||||||
|
pkg = resources.files("mytoolkit")
|
||||||
|
click.echo(f"package: {pkg}")
|
||||||
|
click.echo(f"templates: {pkg / 'templates'}")
|
||||||
|
click.echo(f"references: {pkg / 'references'}")
|
||||||
|
click.echo(f"scaffolds: {pkg / 'scaffolds'}")
|
||||||
|
|
||||||
|
|
||||||
|
@info_cmd.command("docs")
|
||||||
|
@click.argument("name")
|
||||||
|
@click.option("--pager", "-p", is_flag=True, help="Open with less")
|
||||||
|
def info_docs(name, pager):
|
||||||
|
"""Print a bundled reference document (convert, pdf, webpage, ...)."""
|
||||||
|
doc_path = resources.files("mytoolkit") / "references" / f"{name}.md"
|
||||||
|
if not doc_path.is_file():
|
||||||
|
click.secho(f"Reference not found: {name}", fg="red", err=True)
|
||||||
|
raise SystemExit(1)
|
||||||
|
content = doc_path.read_text(encoding="utf-8")
|
||||||
|
if pager:
|
||||||
|
click.echo_via_pager(content)
|
||||||
|
else:
|
||||||
|
click.echo(content)
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
"""Project scaffolding commands."""
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from mytoolkit.utils import handle_errors
|
||||||
|
|
||||||
|
|
||||||
|
def _scaffold_path(name: str):
|
||||||
|
"""Yield a filesystem path to a bundled scaffold directory.
|
||||||
|
|
||||||
|
Uses importlib.resources.as_file so the scaffold works both in editable
|
||||||
|
installs and in packaged wheels.
|
||||||
|
"""
|
||||||
|
import importlib.resources as resources
|
||||||
|
|
||||||
|
return resources.as_file(resources.files("mytoolkit") / "scaffolds" / name)
|
||||||
|
|
||||||
|
|
||||||
|
def _journal_path(name: str):
|
||||||
|
"""Yield a filesystem path to a bundled journal-submission kit."""
|
||||||
|
import importlib.resources as resources
|
||||||
|
|
||||||
|
return resources.as_file(resources.files("mytoolkit") / "journals" / name)
|
||||||
|
|
||||||
|
|
||||||
|
JOURNALS = {
|
||||||
|
"elsevier": "Elsevier (elsarticle.cls, bundled with TeX Live)",
|
||||||
|
"ieee": "IEEE (IEEEtran.cls, bundled with TeX Live)",
|
||||||
|
"springer": "Springer Nature (sn-jnl.cls, shipped inside the kit)",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@click.group(name="init")
|
||||||
|
def init_cmd():
|
||||||
|
"""Initialize new projects from bundled templates."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@init_cmd.command("paper")
|
||||||
|
@click.argument("target", type=click.Path(file_okay=False, dir_okay=True, path_type=Path))
|
||||||
|
@handle_errors
|
||||||
|
def init_paper(target: Path):
|
||||||
|
"""Initialize a LaTeX paper project in TARGET directory."""
|
||||||
|
with _scaffold_path("paper") as scaffold:
|
||||||
|
if not scaffold.is_dir():
|
||||||
|
raise RuntimeError(f"Paper scaffold not found: {scaffold}")
|
||||||
|
|
||||||
|
if target.exists():
|
||||||
|
if any(target.iterdir()):
|
||||||
|
raise RuntimeError(f"Target directory is not empty: {target}")
|
||||||
|
else:
|
||||||
|
target.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
shutil.copytree(scaffold, target, dirs_exist_ok=True)
|
||||||
|
|
||||||
|
created = sorted(p.relative_to(target) for p in target.rglob("*") if p.is_file())
|
||||||
|
|
||||||
|
click.secho(f"Initialized paper project at {target}", fg="green")
|
||||||
|
for path in created:
|
||||||
|
click.echo(f" {path}")
|
||||||
|
|
||||||
|
click.echo("\nRun:")
|
||||||
|
click.echo(f" cd {target}")
|
||||||
|
click.echo(" make")
|
||||||
|
|
||||||
|
|
||||||
|
@init_cmd.command("journal")
|
||||||
|
@click.argument("name", type=click.Choice(sorted(JOURNALS)), required=False)
|
||||||
|
@click.argument("target", type=click.Path(file_okay=False, dir_okay=True, path_type=Path), required=False)
|
||||||
|
@handle_errors
|
||||||
|
def init_journal(name, target):
|
||||||
|
"""Drop a ready-to-compile journal submission kit into TARGET.
|
||||||
|
|
||||||
|
NAME is one of: elsevier, ieee, springer. Without NAME, lists choices.
|
||||||
|
TARGET defaults to ./submit-<NAME>. Each kit is self-contained (main.tex,
|
||||||
|
Makefile using pdflatex+bibtex, references.bib, and any non-bundled class
|
||||||
|
files) so it compiles standalone with `make`.
|
||||||
|
"""
|
||||||
|
if name is None:
|
||||||
|
click.echo("Available journal kits:")
|
||||||
|
for key, desc in sorted(JOURNALS.items()):
|
||||||
|
click.echo(f" {key:10s} {desc}")
|
||||||
|
click.echo("\nUsage: mytoolkit init journal <name> [target]")
|
||||||
|
return
|
||||||
|
|
||||||
|
if target is None:
|
||||||
|
target = Path(f"submit-{name}")
|
||||||
|
|
||||||
|
with _journal_path(name) as kit:
|
||||||
|
if not kit.is_dir():
|
||||||
|
raise RuntimeError(f"Journal kit not found: {kit}")
|
||||||
|
|
||||||
|
if target.exists():
|
||||||
|
if any(target.iterdir()):
|
||||||
|
raise RuntimeError(f"Target directory is not empty: {target}")
|
||||||
|
else:
|
||||||
|
target.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
shutil.copytree(kit, target, dirs_exist_ok=True)
|
||||||
|
|
||||||
|
# Carry over an existing bib from the current directory, if present,
|
||||||
|
# so the submission reuses the project's references.
|
||||||
|
cwd_bib = Path("references.bib")
|
||||||
|
if cwd_bib.is_file() and cwd_bib.resolve() != (target / "references.bib").resolve():
|
||||||
|
shutil.copy2(cwd_bib, target / "references.bib")
|
||||||
|
carried = True
|
||||||
|
else:
|
||||||
|
carried = False
|
||||||
|
|
||||||
|
created = sorted(p.relative_to(target) for p in target.rglob("*") if p.is_file())
|
||||||
|
|
||||||
|
click.secho(f"Initialized {name} submission kit at {target}", fg="green")
|
||||||
|
for path in created:
|
||||||
|
click.echo(f" {path}")
|
||||||
|
if carried:
|
||||||
|
click.echo("\n(reused ./references.bib)")
|
||||||
|
|
||||||
|
click.echo("\nRun:")
|
||||||
|
click.echo(f" cd {target}")
|
||||||
|
click.echo(" make")
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
"""Templates registry CLI."""
|
"""Templates registry CLI."""
|
||||||
|
|
||||||
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import click
|
import click
|
||||||
@@ -24,23 +25,24 @@ def templates_register(path):
|
|||||||
@templates_cmd.command("list")
|
@templates_cmd.command("list")
|
||||||
def templates_list():
|
def templates_list():
|
||||||
"""List the current registry and available templates."""
|
"""List the current registry and available templates."""
|
||||||
if not templates_registry.CONFIG_PATH.exists():
|
root = templates_registry.get_root()
|
||||||
click.echo("No registry. Run: mytoolkit templates register <path>")
|
click.echo(f"Registry: {templates_registry.CONFIG_PATH}")
|
||||||
return
|
if templates_registry.CONFIG_PATH.exists():
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
with open(templates_registry.CONFIG_PATH, encoding="utf-8") as f:
|
with open(templates_registry.CONFIG_PATH, encoding="utf-8") as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
raw = data.get("dir")
|
raw = data.get("dir")
|
||||||
click.echo(f"Registry: {templates_registry.CONFIG_PATH}")
|
if raw:
|
||||||
click.echo(f"Root: {raw}")
|
override = Path(raw)
|
||||||
|
if override.is_dir():
|
||||||
|
click.echo(f"Override: {raw}")
|
||||||
|
else:
|
||||||
|
click.secho(f"Override: {raw} (invalid, using bundled)", fg="yellow")
|
||||||
|
click.echo(f"Root: {root}")
|
||||||
|
|
||||||
if not raw or not Path(raw).is_dir():
|
if not root.is_dir():
|
||||||
click.secho("(root path missing)", fg="red")
|
click.secho("(root path missing)", fg="red")
|
||||||
return
|
return
|
||||||
|
|
||||||
root = Path(raw)
|
|
||||||
pdf_dir = root / "md-to-pdf"
|
pdf_dir = root / "md-to-pdf"
|
||||||
docx_dir = root / "md-to-docx"
|
docx_dir = root / "md-to-docx"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
build/
|
||||||
|
*.aux
|
||||||
|
*.bbl
|
||||||
|
*.blg
|
||||||
|
*.log
|
||||||
|
*.out
|
||||||
|
*.spl
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
.PHONY: all clean show-errors show-log watch help
|
||||||
|
|
||||||
|
# Journal submissions compile with pdflatex (the publisher norm) + bibtex.
|
||||||
|
TEXFILE ?= main.tex
|
||||||
|
PROJECT = $(basename $(TEXFILE))
|
||||||
|
LATEXMK = latexmk
|
||||||
|
OUTDIR = build
|
||||||
|
# Let bibtex find .bst/.bib regardless of latexmk's build/ run dir
|
||||||
|
# (Springer ships its styles under bst/).
|
||||||
|
export BSTINPUTS := $(CURDIR):$(CURDIR)/bst:
|
||||||
|
export BIBINPUTS := $(CURDIR):
|
||||||
|
MAKELOG = $(OUTDIR)/make.log
|
||||||
|
TEXLOG = $(OUTDIR)/$(PROJECT).log
|
||||||
|
ARTIFACTS = $(PROJECT).aux $(PROJECT).bbl $(PROJECT).blg $(PROJECT).log $(PROJECT).out \
|
||||||
|
$(PROJECT).toc $(PROJECT).synctex.gz $(PROJECT).fls $(PROJECT).fdb_latexmk $(PROJECT).spl
|
||||||
|
|
||||||
|
all:
|
||||||
|
@mkdir -p $(OUTDIR)
|
||||||
|
@echo "Compiling $(PROJECT).tex (pdflatex, full log: $(MAKELOG))..."
|
||||||
|
@$(LATEXMK) -pdf -outdir=$(OUTDIR) -interaction=nonstopmode $(PROJECT).tex < /dev/null > $(MAKELOG) 2>&1; \
|
||||||
|
status=$$?; \
|
||||||
|
if [ $$status -ne 0 ]; then \
|
||||||
|
echo "Build failed."; \
|
||||||
|
$(MAKE) -s show-errors; \
|
||||||
|
echo "Full log: $(MAKELOG)"; \
|
||||||
|
exit $$status; \
|
||||||
|
fi
|
||||||
|
@cp $(OUTDIR)/$(PROJECT).pdf ./$(PROJECT).pdf
|
||||||
|
@rm -f $(ARTIFACTS)
|
||||||
|
@echo "Done: $(PROJECT).pdf"
|
||||||
|
|
||||||
|
show-errors:
|
||||||
|
@if [ -f $(TEXLOG) ]; then \
|
||||||
|
grep -E -A2 '^! |^l\.[0-9]+ |LaTeX Error|Undefined control sequence|Missing \$$ inserted|Package .* Error|Emergency stop|Fatal error' \
|
||||||
|
$(TEXLOG) 2>/dev/null \
|
||||||
|
|| tail -30 $(MAKELOG); \
|
||||||
|
else \
|
||||||
|
tail -30 $(MAKELOG); \
|
||||||
|
fi
|
||||||
|
|
||||||
|
show-log:
|
||||||
|
@less $(MAKELOG)
|
||||||
|
|
||||||
|
watch:
|
||||||
|
$(LATEXMK) -pvc -pdf -outdir=$(OUTDIR) -interaction=nonstopmode $(PROJECT).tex
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(LATEXMK) -C -outdir=$(OUTDIR) $(PROJECT).tex
|
||||||
|
rm -rf $(OUTDIR)
|
||||||
|
rm -f $(ARTIFACTS)
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo
|
||||||
|
@echo '1. "make" compile (pdflatex+bibtex via latexmk, PDF copied to root)'
|
||||||
|
@echo '2. "make show-errors" re-print the error lines from the last build'
|
||||||
|
@echo '3. "make show-log" page through the full build log'
|
||||||
|
@echo '4. "make watch" continuous preview-compile'
|
||||||
|
@echo '5. "make clean" remove build/ and stray artifacts'
|
||||||
|
@echo
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
%% Elsevier submission template (elsarticle.cls — bundled with TeX Live).
|
||||||
|
%% Options: review (double-space, line numbers) | preprint | 1p/3p/5p | times.
|
||||||
|
\documentclass[preprint,12pt]{elsarticle}
|
||||||
|
|
||||||
|
\usepackage{amsmath,amssymb,amsfonts}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{lineno}
|
||||||
|
|
||||||
|
\journal{Journal Name}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\begin{frontmatter}
|
||||||
|
|
||||||
|
\title{Paper title}
|
||||||
|
|
||||||
|
\author[inst1]{Zhengshou Lai}
|
||||||
|
\ead{laizhengsh@mail.sysu.edu.cn}
|
||||||
|
|
||||||
|
\affiliation[inst1]{organization={School of Civil Engineering, Sun Yat-sen University},
|
||||||
|
city={Zhuhai},
|
||||||
|
country={China}}
|
||||||
|
|
||||||
|
\begin{abstract}
|
||||||
|
Abstract text goes here.
|
||||||
|
\end{abstract}
|
||||||
|
|
||||||
|
\begin{keyword}
|
||||||
|
keyword one \sep keyword two \sep keyword three
|
||||||
|
\end{keyword}
|
||||||
|
|
||||||
|
\end{frontmatter}
|
||||||
|
|
||||||
|
\section{Introduction}
|
||||||
|
Introduction text~\cite{example2024}.
|
||||||
|
|
||||||
|
\section{Methods}
|
||||||
|
Methods text. An equation:
|
||||||
|
\begin{equation}
|
||||||
|
\frac{\partial u}{\partial t} + \nabla \cdot \mathbf{F} = 0 .
|
||||||
|
\end{equation}
|
||||||
|
|
||||||
|
\section{Conclusions}
|
||||||
|
Conclusions text.
|
||||||
|
|
||||||
|
%% Elsevier numbered style. Use elsarticle-harv for author-year.
|
||||||
|
\bibliographystyle{elsarticle-num}
|
||||||
|
\bibliography{references}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
@article{example2024,
|
||||||
|
title = {An example reference},
|
||||||
|
author = {Doe, Jane and Smith, John},
|
||||||
|
journal = {Journal of Examples},
|
||||||
|
volume = {1},
|
||||||
|
number = {1},
|
||||||
|
pages = {1--10},
|
||||||
|
year = {2024}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
build/
|
||||||
|
*.aux
|
||||||
|
*.bbl
|
||||||
|
*.blg
|
||||||
|
*.log
|
||||||
|
*.out
|
||||||
|
*.spl
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
.PHONY: all clean show-errors show-log watch help
|
||||||
|
|
||||||
|
# Journal submissions compile with pdflatex (the publisher norm) + bibtex.
|
||||||
|
TEXFILE ?= main.tex
|
||||||
|
PROJECT = $(basename $(TEXFILE))
|
||||||
|
LATEXMK = latexmk
|
||||||
|
OUTDIR = build
|
||||||
|
# Let bibtex find .bst/.bib regardless of latexmk's build/ run dir
|
||||||
|
# (Springer ships its styles under bst/).
|
||||||
|
export BSTINPUTS := $(CURDIR):$(CURDIR)/bst:
|
||||||
|
export BIBINPUTS := $(CURDIR):
|
||||||
|
MAKELOG = $(OUTDIR)/make.log
|
||||||
|
TEXLOG = $(OUTDIR)/$(PROJECT).log
|
||||||
|
ARTIFACTS = $(PROJECT).aux $(PROJECT).bbl $(PROJECT).blg $(PROJECT).log $(PROJECT).out \
|
||||||
|
$(PROJECT).toc $(PROJECT).synctex.gz $(PROJECT).fls $(PROJECT).fdb_latexmk $(PROJECT).spl
|
||||||
|
|
||||||
|
all:
|
||||||
|
@mkdir -p $(OUTDIR)
|
||||||
|
@echo "Compiling $(PROJECT).tex (pdflatex, full log: $(MAKELOG))..."
|
||||||
|
@$(LATEXMK) -pdf -outdir=$(OUTDIR) -interaction=nonstopmode $(PROJECT).tex < /dev/null > $(MAKELOG) 2>&1; \
|
||||||
|
status=$$?; \
|
||||||
|
if [ $$status -ne 0 ]; then \
|
||||||
|
echo "Build failed."; \
|
||||||
|
$(MAKE) -s show-errors; \
|
||||||
|
echo "Full log: $(MAKELOG)"; \
|
||||||
|
exit $$status; \
|
||||||
|
fi
|
||||||
|
@cp $(OUTDIR)/$(PROJECT).pdf ./$(PROJECT).pdf
|
||||||
|
@rm -f $(ARTIFACTS)
|
||||||
|
@echo "Done: $(PROJECT).pdf"
|
||||||
|
|
||||||
|
show-errors:
|
||||||
|
@if [ -f $(TEXLOG) ]; then \
|
||||||
|
grep -E -A2 '^! |^l\.[0-9]+ |LaTeX Error|Undefined control sequence|Missing \$$ inserted|Package .* Error|Emergency stop|Fatal error' \
|
||||||
|
$(TEXLOG) 2>/dev/null \
|
||||||
|
|| tail -30 $(MAKELOG); \
|
||||||
|
else \
|
||||||
|
tail -30 $(MAKELOG); \
|
||||||
|
fi
|
||||||
|
|
||||||
|
show-log:
|
||||||
|
@less $(MAKELOG)
|
||||||
|
|
||||||
|
watch:
|
||||||
|
$(LATEXMK) -pvc -pdf -outdir=$(OUTDIR) -interaction=nonstopmode $(PROJECT).tex
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(LATEXMK) -C -outdir=$(OUTDIR) $(PROJECT).tex
|
||||||
|
rm -rf $(OUTDIR)
|
||||||
|
rm -f $(ARTIFACTS)
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo
|
||||||
|
@echo '1. "make" compile (pdflatex+bibtex via latexmk, PDF copied to root)'
|
||||||
|
@echo '2. "make show-errors" re-print the error lines from the last build'
|
||||||
|
@echo '3. "make show-log" page through the full build log'
|
||||||
|
@echo '4. "make watch" continuous preview-compile'
|
||||||
|
@echo '5. "make clean" remove build/ and stray artifacts'
|
||||||
|
@echo
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
%% IEEE submission template (IEEEtran.cls — bundled with TeX Live).
|
||||||
|
%% Options: journal | conference | technote.
|
||||||
|
\documentclass[journal]{IEEEtran}
|
||||||
|
|
||||||
|
\usepackage{amsmath,amssymb,amsfonts}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{cite}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\title{Paper title}
|
||||||
|
|
||||||
|
\author{Zhengshou~Lai%
|
||||||
|
\thanks{Z. Lai is with the School of Civil Engineering,
|
||||||
|
Sun Yat-sen University, Zhuhai, China (e-mail: laizhengsh@mail.sysu.edu.cn).}}
|
||||||
|
|
||||||
|
\maketitle
|
||||||
|
|
||||||
|
\begin{abstract}
|
||||||
|
Abstract text goes here.
|
||||||
|
\end{abstract}
|
||||||
|
|
||||||
|
\begin{IEEEkeywords}
|
||||||
|
keyword one, keyword two, keyword three.
|
||||||
|
\end{IEEEkeywords}
|
||||||
|
|
||||||
|
\section{Introduction}
|
||||||
|
\IEEEPARstart{T}{his} is the introduction~\cite{example2024}.
|
||||||
|
|
||||||
|
\section{Methods}
|
||||||
|
Methods text. An equation:
|
||||||
|
\begin{equation}
|
||||||
|
\frac{\partial u}{\partial t} + \nabla \cdot \mathbf{F} = 0 .
|
||||||
|
\end{equation}
|
||||||
|
|
||||||
|
\section{Conclusion}
|
||||||
|
Conclusion text.
|
||||||
|
|
||||||
|
\bibliographystyle{IEEEtran}
|
||||||
|
\bibliography{references}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
@article{example2024,
|
||||||
|
title = {An example reference},
|
||||||
|
author = {Doe, Jane and Smith, John},
|
||||||
|
journal = {Journal of Examples},
|
||||||
|
volume = {1},
|
||||||
|
number = {1},
|
||||||
|
pages = {1--10},
|
||||||
|
year = {2024}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
build/
|
||||||
|
*.aux
|
||||||
|
*.bbl
|
||||||
|
*.blg
|
||||||
|
*.log
|
||||||
|
*.out
|
||||||
|
*.spl
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
.PHONY: all clean show-errors show-log watch help
|
||||||
|
|
||||||
|
# Journal submissions compile with pdflatex (the publisher norm) + bibtex.
|
||||||
|
TEXFILE ?= main.tex
|
||||||
|
PROJECT = $(basename $(TEXFILE))
|
||||||
|
LATEXMK = latexmk
|
||||||
|
OUTDIR = build
|
||||||
|
# Let bibtex find .bst/.bib regardless of latexmk's build/ run dir
|
||||||
|
# (Springer ships its styles under bst/).
|
||||||
|
export BSTINPUTS := $(CURDIR):$(CURDIR)/bst:
|
||||||
|
export BIBINPUTS := $(CURDIR):
|
||||||
|
MAKELOG = $(OUTDIR)/make.log
|
||||||
|
TEXLOG = $(OUTDIR)/$(PROJECT).log
|
||||||
|
ARTIFACTS = $(PROJECT).aux $(PROJECT).bbl $(PROJECT).blg $(PROJECT).log $(PROJECT).out \
|
||||||
|
$(PROJECT).toc $(PROJECT).synctex.gz $(PROJECT).fls $(PROJECT).fdb_latexmk $(PROJECT).spl
|
||||||
|
|
||||||
|
all:
|
||||||
|
@mkdir -p $(OUTDIR)
|
||||||
|
@echo "Compiling $(PROJECT).tex (pdflatex, full log: $(MAKELOG))..."
|
||||||
|
@$(LATEXMK) -pdf -outdir=$(OUTDIR) -interaction=nonstopmode $(PROJECT).tex < /dev/null > $(MAKELOG) 2>&1; \
|
||||||
|
status=$$?; \
|
||||||
|
if [ $$status -ne 0 ]; then \
|
||||||
|
echo "Build failed."; \
|
||||||
|
$(MAKE) -s show-errors; \
|
||||||
|
echo "Full log: $(MAKELOG)"; \
|
||||||
|
exit $$status; \
|
||||||
|
fi
|
||||||
|
@cp $(OUTDIR)/$(PROJECT).pdf ./$(PROJECT).pdf
|
||||||
|
@rm -f $(ARTIFACTS)
|
||||||
|
@echo "Done: $(PROJECT).pdf"
|
||||||
|
|
||||||
|
show-errors:
|
||||||
|
@if [ -f $(TEXLOG) ]; then \
|
||||||
|
grep -E -A2 '^! |^l\.[0-9]+ |LaTeX Error|Undefined control sequence|Missing \$$ inserted|Package .* Error|Emergency stop|Fatal error' \
|
||||||
|
$(TEXLOG) 2>/dev/null \
|
||||||
|
|| tail -30 $(MAKELOG); \
|
||||||
|
else \
|
||||||
|
tail -30 $(MAKELOG); \
|
||||||
|
fi
|
||||||
|
|
||||||
|
show-log:
|
||||||
|
@less $(MAKELOG)
|
||||||
|
|
||||||
|
watch:
|
||||||
|
$(LATEXMK) -pvc -pdf -outdir=$(OUTDIR) -interaction=nonstopmode $(PROJECT).tex
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(LATEXMK) -C -outdir=$(OUTDIR) $(PROJECT).tex
|
||||||
|
rm -rf $(OUTDIR)
|
||||||
|
rm -f $(ARTIFACTS)
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo
|
||||||
|
@echo '1. "make" compile (pdflatex+bibtex via latexmk, PDF copied to root)'
|
||||||
|
@echo '2. "make show-errors" re-print the error lines from the last build'
|
||||||
|
@echo '3. "make show-log" page through the full build log'
|
||||||
|
@echo '4. "make watch" continuous preview-compile'
|
||||||
|
@echo '5. "make clean" remove build/ and stray artifacts'
|
||||||
|
@echo
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
|||||||
|
%% Springer Nature submission template (sn-jnl.cls — bundled in this kit).
|
||||||
|
%% Reference-style option (pick ONE, matching \bibliographystyle below):
|
||||||
|
%% sn-mathphys-num | sn-mathphys-ay | sn-nature | sn-basic
|
||||||
|
%% sn-vancouver-num | sn-vancouver-ay | sn-apacite | sn-chicago | sn-aps
|
||||||
|
%% Engine option: pdflatex (default) — also works with xelatex.
|
||||||
|
\documentclass[pdflatex,sn-mathphys-num]{sn-jnl}
|
||||||
|
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{amsmath,amssymb,amsfonts}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\title[Short title]{Paper title}
|
||||||
|
|
||||||
|
\author[1]{\fnm{Zhengshou} \sur{Lai}}\email{laizhengsh@mail.sysu.edu.cn}
|
||||||
|
|
||||||
|
\affil[1]{\orgdiv{School of Civil Engineering}, \orgname{Sun Yat-sen University},
|
||||||
|
\city{Zhuhai}, \country{China}}
|
||||||
|
|
||||||
|
\abstract{Abstract text goes here.}
|
||||||
|
|
||||||
|
\keywords{keyword one, keyword two, keyword three}
|
||||||
|
|
||||||
|
\maketitle
|
||||||
|
|
||||||
|
\section{Introduction}\label{sec1}
|
||||||
|
Introduction text~\cite{example2024}.
|
||||||
|
|
||||||
|
\section{Methods}\label{sec2}
|
||||||
|
Methods text. An equation:
|
||||||
|
\begin{equation}
|
||||||
|
\frac{\partial u}{\partial t} + \nabla \cdot \mathbf{F} = 0 .
|
||||||
|
\end{equation}
|
||||||
|
|
||||||
|
\section{Conclusion}\label{sec3}
|
||||||
|
Conclusion text.
|
||||||
|
|
||||||
|
%% Reference style is set by the documentclass option above; do NOT add
|
||||||
|
%% \bibliographystyle (sn-jnl.cls sets it, and a duplicate errors bibtex).
|
||||||
|
\bibliography{references}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
@article{example2024,
|
||||||
|
title = {An example reference},
|
||||||
|
author = {Doe, Jane and Smith, John},
|
||||||
|
journal = {Journal of Examples},
|
||||||
|
volume = {1},
|
||||||
|
number = {1},
|
||||||
|
pages = {1--10},
|
||||||
|
year = {2024}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -9,7 +9,7 @@ import click
|
|||||||
from mytoolkit import templates_registry
|
from mytoolkit import templates_registry
|
||||||
from mytoolkit.utils import run_command
|
from mytoolkit.utils import run_command
|
||||||
|
|
||||||
# Typst callouts exported by templates/md-to-pdf/{textbook,manual}/template.typ.
|
# Typst callouts exported by mytoolkit/templates/md-to-pdf/{textbook,manual}/template.typ.
|
||||||
# Keep this tuple and _extra_imports (below) in sync when adding or removing `#let` callouts.
|
# Keep this tuple and _extra_imports (below) in sync when adding or removing `#let` callouts.
|
||||||
# Pandoc escapes leading `#`, so these names are wrapped in a long-enough `{=typst}` fence
|
# Pandoc escapes leading `#`, so these names are wrapped in a long-enough `{=typst}` fence
|
||||||
# (length chosen so inner ``` from Pandoc does not terminate the fence early).
|
# (length chosen so inner ``` from Pandoc does not terminate the fence early).
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
# 通用格式转换(convert)
|
||||||
|
|
||||||
|
根据输入/输出文件扩展名自动推断转换路径,一个命令覆盖大多数场景。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Markdown → PDF
|
||||||
|
mytoolkit convert doc.md -o doc.pdf
|
||||||
|
mytoolkit convert doc.md -o doc.pdf -t cv # CV 模板
|
||||||
|
mytoolkit convert ch1.md ch2.md -o book.pdf -t textbook
|
||||||
|
|
||||||
|
# Markdown → Word
|
||||||
|
mytoolkit convert doc.md -o doc.docx
|
||||||
|
mytoolkit convert doc.md -o doc.docx --reference-doc template.docx
|
||||||
|
|
||||||
|
# 图片 → PDF(单张或多张合并)
|
||||||
|
mytoolkit convert photo.jpg -o photo.pdf
|
||||||
|
mytoolkit convert *.jpg -o album.pdf
|
||||||
|
|
||||||
|
# EPS → PDF(Matlab/Origin 插图常用)
|
||||||
|
mytoolkit convert fig.eps -o fig.pdf
|
||||||
|
|
||||||
|
# TIFF → PDF
|
||||||
|
mytoolkit convert scan.tiff -o scan.pdf
|
||||||
|
|
||||||
|
# PDF 压缩
|
||||||
|
mytoolkit convert large.pdf -o small.pdf -q screen # screen/ebook/printer/prepress
|
||||||
|
|
||||||
|
# PDF → TIFF
|
||||||
|
mytoolkit convert scan.pdf -o scan.tiff -d 300
|
||||||
|
|
||||||
|
# AVI → MP4
|
||||||
|
mytoolkit convert video.avi -o video.mp4
|
||||||
|
|
||||||
|
# BibTeX → Markdown
|
||||||
|
mytoolkit convert refs.bib -o refs.md
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `-o, --output` | 输出文件路径(必填) |
|
||||||
|
| `-t, --template` | `default` / `cv` / `textbook` / `manual` / `review`(md→pdf 全支持;md→docx 支持 `default` / `review`) |
|
||||||
|
| `-q, --quality` | `screen` / `ebook` / `printer` / `prepress`(仅 PDF 压缩) |
|
||||||
|
| `-d, --density` | DPI(仅 PDF→TIFF,默认 300) |
|
||||||
|
| `--reference-doc` | Word 参考模板路径(仅 md→docx) |
|
||||||
|
| `--bookmark-depth` | PDF 书签展开层级(仅 md→pdf,默认 `2`) |
|
||||||
|
| `-n, --dry-run` | 预览,不实际执行 |
|
||||||
|
|
||||||
|
## Markdown → PDF 模板与混写语法
|
||||||
|
|
||||||
|
`mytoolkit convert *.md -o *.pdf` 走 Pandoc + Typst 管线。所有模板**只接受 body**,不会自动注入标题页/作者/日期,全部内容由用户在 Markdown 源文件中书写。
|
||||||
|
|
||||||
|
| 模板 | 特点 |
|
||||||
|
|------|------|
|
||||||
|
| `default` | A4、Calibri+SimSun,无特殊样式 |
|
||||||
|
| `cv` | 学术蓝配色、章节下划线、紧凑排版、页眉显示更新日期 |
|
||||||
|
| `textbook` | 定理/证明/例题环境、代码高亮、目录 |
|
||||||
|
| `manual` | 暗色代码主题、提示/警告/危险框、目录 |
|
||||||
|
|
||||||
|
支持在 Markdown 中直接调用模板导出的 Typst 函数(`mytoolkit` 会预处理这些**行首**调用,避免 Pandoc 把 `#` 转义掉)。`default` / `cv` 未定义下列函数。
|
||||||
|
|
||||||
|
| 模板 | 支持的调用名 | 说明 |
|
||||||
|
|------|----------------|------|
|
||||||
|
| **textbook** | `theorem`、`lemma`、`example`、`exercise` | 有标题时一律用命名参数:`title: "…"`(不要用 `#foo("…")` 位置参数) |
|
||||||
|
| **textbook** | `proof` | 可用 `#proof[` 或 `#proof(of: <标签>)` |
|
||||||
|
| **manual** | `info-box`、`tip-box`、`warn-box`、`danger-box` | 常用 `title: "…"` |
|
||||||
|
|
||||||
|
在模板中新增其它 `#let foo = …` 并在 Markdown 里以 `#foo[…]` 形式混写时,需同步修改 `mytoolkit` 源码中的调用名列表与驱动 `import`(见 `md_to_pdf.py` 中 `_TY_CALL_NAMES` 与 `build_pdf` 的 `_extra_imports`)。
|
||||||
|
|
||||||
|
**教材模板(textbook)示例:**
|
||||||
|
```markdown
|
||||||
|
#theorem(title: "解的存在唯一性")[
|
||||||
|
设 $f \in L^2(0,1)$……
|
||||||
|
]
|
||||||
|
|
||||||
|
#lemma(title: "…")[
|
||||||
|
…
|
||||||
|
]
|
||||||
|
|
||||||
|
#proof[
|
||||||
|
由 Riesz 表示定理……
|
||||||
|
]
|
||||||
|
|
||||||
|
#example(title: "…")[
|
||||||
|
考虑以下边值问题……
|
||||||
|
]
|
||||||
|
|
||||||
|
#exercise(title: "3.1")[
|
||||||
|
…
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**手册模板(manual)示例:**
|
||||||
|
```markdown
|
||||||
|
#info-box(title: "注意")[
|
||||||
|
此 API 在 v2.0 后已弃用。
|
||||||
|
]
|
||||||
|
|
||||||
|
#tip-box(title: "建议")[
|
||||||
|
使用缓存可提升 10 倍性能。
|
||||||
|
]
|
||||||
|
|
||||||
|
#warn-box(title: "警告")[
|
||||||
|
直接修改生产环境数据可能导致不可逆损坏。
|
||||||
|
]
|
||||||
|
|
||||||
|
#danger-box(title: "危险")[
|
||||||
|
此操作会删除所有历史记录。
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**PDF 书签层级**:用 `--bookmark-depth N` 控制书签默认展开到第 N 层(`1` = 只展开顶层,`2` = 展开到二级,以此类推;默认 `2`)。
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# PDF 处理(pdf)
|
||||||
|
|
||||||
|
`convert` 已覆盖常用场景,以下子命令用于更细粒度的控制:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 压缩(ghostscript)
|
||||||
|
mytoolkit pdf compress *.pdf
|
||||||
|
mytoolkit pdf compress paper.pdf -q ebook
|
||||||
|
mytoolkit pdf compress paper.pdf --bookmark-depth 2 # 压缩后展开二级书签
|
||||||
|
|
||||||
|
# 裁剪白边
|
||||||
|
mytoolkit pdf crop figure.pdf
|
||||||
|
|
||||||
|
# 合并(支持 PDF + 图片混排)
|
||||||
|
mytoolkit pdf merge page1.pdf page2.png img.jpg -o output.pdf
|
||||||
|
mytoolkit pdf merge ch*.pdf -o book.pdf --bookmark-depth 2
|
||||||
|
|
||||||
|
# 调整书签默认展开层级(不重新生成 PDF)
|
||||||
|
mytoolkit pdf bookmark report.pdf --depth 2 # 原地修改
|
||||||
|
mytoolkit pdf bookmark report.pdf --depth 2 -o out.pdf # 输出到新文件
|
||||||
|
|
||||||
|
# PDF 转 TIFF
|
||||||
|
mytoolkit pdf to-tiff scan.pdf -d 300
|
||||||
|
```
|
||||||
|
|
||||||
|
`--bookmark-depth N` / `--depth N` 控制书签默认展开到第 N 层。`1` = 只展顶层(默认),`2` = 展开到二级。
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# 网站构建(webpage)
|
||||||
|
|
||||||
|
格式:`mytoolkit webpage <项目> <动作>`(项目名在前,动作在后)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mytoolkit webpage list # 列出受管项目
|
||||||
|
|
||||||
|
# 项目级动作(以 mywebpage 为例,可替换为 apaam-webpage / xiaohe-webpage)
|
||||||
|
mytoolkit webpage mywebpage build # npm run build
|
||||||
|
mytoolkit webpage mywebpage build --serve # 构建后启动 docusaurus serve
|
||||||
|
mytoolkit webpage mywebpage clear # 清理 build / .docusaurus / 缓存
|
||||||
|
mytoolkit webpage mywebpage rebuild # clear + build
|
||||||
|
mytoolkit webpage mywebpage push # git push 源码仓库
|
||||||
|
mytoolkit webpage mywebpage push -f # force-with-lease
|
||||||
|
mytoolkit webpage mywebpage deploy # 发布到 GitHub Pages
|
||||||
|
mytoolkit webpage mywebpage pdf build # 导出 docs PDF
|
||||||
|
mytoolkit webpage mywebpage pdf open # 打开导出的 PDF
|
||||||
|
|
||||||
|
# 项目级 server 管理(等价于 `mytoolkit server <action> mywebpage`)
|
||||||
|
mytoolkit webpage mywebpage server start # 启动 serve(可加 --dev / --rebuild)
|
||||||
|
mytoolkit webpage mywebpage server stop # 停止 serve(可加 --dev / --all)
|
||||||
|
mytoolkit webpage mywebpage server restart # 重启
|
||||||
|
mytoolkit webpage mywebpage server status # 查看 serve + dev 端口状态
|
||||||
|
```
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
build/
|
||||||
|
*.aux
|
||||||
|
*.bbl
|
||||||
|
*.blg
|
||||||
|
*.log
|
||||||
|
*.out
|
||||||
|
*.toc
|
||||||
|
*.synctex.gz
|
||||||
|
*.fls
|
||||||
|
*.fdb_latexmk
|
||||||
|
*.xdv
|
||||||
|
*.spl
|
||||||
|
highlighted.*
|
||||||
|
.DS_Store
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
.PHONY: all clean show-errors show-log watch highlighted help
|
||||||
|
|
||||||
|
TEXFILE ?= $(if $(wildcard main.tex),main.tex,$(firstword $(filter-out highlighted.tex old.tex,$(wildcard *.tex))))
|
||||||
|
PROJECT = $(basename $(TEXFILE))
|
||||||
|
LATEXMK = latexmk
|
||||||
|
OUTDIR = build
|
||||||
|
OLDTEX ?= old.tex
|
||||||
|
MAKELOG = $(OUTDIR)/make.log
|
||||||
|
TEXLOG = $(OUTDIR)/$(PROJECT).log
|
||||||
|
ARTIFACTS = $(PROJECT).aux $(PROJECT).bbl $(PROJECT).blg $(PROJECT).log $(PROJECT).out \
|
||||||
|
$(PROJECT).toc $(PROJECT).synctex.gz $(PROJECT).fls $(PROJECT).fdb_latexmk $(PROJECT).xdv
|
||||||
|
|
||||||
|
all:
|
||||||
|
@mkdir -p $(OUTDIR)
|
||||||
|
@echo "Compiling $(PROJECT).tex (full log: $(MAKELOG))..."
|
||||||
|
@$(LATEXMK) -xelatex -outdir=$(OUTDIR) -interaction=nonstopmode $(PROJECT).tex < /dev/null > $(MAKELOG) 2>&1; \
|
||||||
|
status=$$?; \
|
||||||
|
if [ $$status -ne 0 ]; then \
|
||||||
|
echo "Build failed."; \
|
||||||
|
$(MAKE) -s show-errors; \
|
||||||
|
echo "Full log: $(MAKELOG)"; \
|
||||||
|
exit $$status; \
|
||||||
|
fi
|
||||||
|
@cp $(OUTDIR)/$(PROJECT).pdf ./$(PROJECT).pdf
|
||||||
|
@rm -f $(ARTIFACTS)
|
||||||
|
@echo "Done: $(PROJECT).pdf"
|
||||||
|
|
||||||
|
show-errors:
|
||||||
|
@if [ -f $(TEXLOG) ]; then \
|
||||||
|
grep -E -A2 '^! |^l\.[0-9]+ |LaTeX Error|Undefined control sequence|Missing \$$ inserted|Package .* Error|Emergency stop|Fatal error' \
|
||||||
|
$(TEXLOG) 2>/dev/null \
|
||||||
|
|| tail -30 $(MAKELOG); \
|
||||||
|
else \
|
||||||
|
tail -30 $(MAKELOG); \
|
||||||
|
fi
|
||||||
|
|
||||||
|
show-log:
|
||||||
|
@less $(MAKELOG)
|
||||||
|
|
||||||
|
highlighted:
|
||||||
|
@latexdiff --preamble=diffpreamble.dtx --allow-spaces $(OLDTEX) $(PROJECT).tex > highlighted.tex
|
||||||
|
@echo "Generated: highlighted.tex"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(LATEXMK) -C -outdir=$(OUTDIR) $(PROJECT).tex
|
||||||
|
rm -rf $(OUTDIR)
|
||||||
|
rm -f highlighted.* $(ARTIFACTS)
|
||||||
|
|
||||||
|
watch:
|
||||||
|
$(LATEXMK) -pvc -xelatex -outdir=$(OUTDIR) -interaction=nonstopmode $(PROJECT).tex
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo
|
||||||
|
@echo '1. "make" compile (latexmk, output in build/, PDF copied to root; on error prints the failing lines and stops)'
|
||||||
|
@echo '2. "make show-errors" re-print the error lines from the last build'
|
||||||
|
@echo '3. "make show-log" page through the full build log'
|
||||||
|
@echo '4. "make highlighted" generate latexdiff highlighted.tex (default OLDTEX=old.tex; override with make highlighted OLDTEX=path/to/prev.tex)'
|
||||||
|
@echo '5. "make watch" continuous preview-compile (latexmk -pvc)'
|
||||||
|
@echo '6. "make clean" remove build/ and stray artifacts'
|
||||||
|
@echo
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# 论文项目
|
||||||
|
|
||||||
|
本项目由 `mytoolkit init paper` 初始化。
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
- `main.tex`:论文主文件
|
||||||
|
- `Makefile`:编译脚本
|
||||||
|
- `diffpreamble.dtx`:`latexdiff` 样式 preamble
|
||||||
|
- `references.bib`:参考文献
|
||||||
|
- `figs/`:图片
|
||||||
|
- `analysis/`:分析脚本与数据
|
||||||
|
- `build/`:编译输出(自动生成)
|
||||||
|
|
||||||
|
## 编译
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
编译成功后生成 `main.pdf`。
|
||||||
|
|
||||||
|
## 生成修订高亮稿
|
||||||
|
|
||||||
|
把上一版论文 tex 备份为 `old.tex`(或任意路径),然后:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make highlighted # 默认对比 old.tex
|
||||||
|
make highlighted OLDTEX=path/to/prev.tex
|
||||||
|
```
|
||||||
|
|
||||||
|
生成 `highlighted.tex`,编译后即为带修订标记的 PDF。
|
||||||
|
|
||||||
|
## 其他命令
|
||||||
|
|
||||||
|
- `make clean`:清理编译产物
|
||||||
|
- `make watch`:持续编译预览
|
||||||
|
- `make show-errors`:查看最近编译错误
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
\RequirePackage[normalem]{ulem} %DIF PREAMBLE
|
||||||
|
\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFaddtex}[1]{{\protect\color{red}{#1}}} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFdeltex}[1]{} %DIF PREAMBLE
|
||||||
|
%DIF SAFE PREAMBLE %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFaddbegin}{} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFaddend}{} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFdelbegin}{} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFdelend}{} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFmodbegin}{} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFmodend}{} %DIF PREAMBLE
|
||||||
|
%DIF FLOATSAFE PREAMBLE %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFaddbeginFL}{} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFaddendFL}{} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFdelbeginFL}{} %DIF PREAMBLE
|
||||||
|
\providecommand{\DIFdelendFL}{} %DIF PREAMBLE
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
\documentclass[UTF8, fontset=fandol]{ctexart}
|
||||||
|
\usepackage{amsmath, amssymb, amsfonts}
|
||||||
|
\usepackage{geometry}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\usepackage[numbers]{natbib}
|
||||||
|
|
||||||
|
\geometry{a4paper, margin=2.5cm}
|
||||||
|
|
||||||
|
\title{论文标题}
|
||||||
|
\author{作者姓名}
|
||||||
|
\date{\today}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\maketitle
|
||||||
|
|
||||||
|
\begin{abstract}
|
||||||
|
在此撰写摘要。
|
||||||
|
\end{abstract}
|
||||||
|
|
||||||
|
\section{引言}
|
||||||
|
|
||||||
|
引言部分。
|
||||||
|
|
||||||
|
\section{方法}
|
||||||
|
|
||||||
|
方法部分。可插入公式:
|
||||||
|
\begin{equation}
|
||||||
|
\frac{\partial u}{\partial t} + \nabla \cdot \mathbf{F} = 0 .
|
||||||
|
\end{equation}
|
||||||
|
|
||||||
|
\section{结果与讨论}
|
||||||
|
|
||||||
|
结果部分。可按以下方式插入图片:
|
||||||
|
%
|
||||||
|
% \begin{figure}[htbp]
|
||||||
|
% \centering
|
||||||
|
% \includegraphics[width=0.8\textwidth]{figs/example.pdf}
|
||||||
|
% \caption{示例图片}
|
||||||
|
% \label{fig:example}
|
||||||
|
% \end{figure}
|
||||||
|
%
|
||||||
|
|
||||||
|
\section{结论}
|
||||||
|
|
||||||
|
结论部分。
|
||||||
|
|
||||||
|
\bibliographystyle{plainnat}
|
||||||
|
\bibliography{references}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@comment{Placeholder bibliography file. Add BibTeX entries below.}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
"""External templates registry for md→pdf / md→docx conversion."""
|
"""Templates registry for md→pdf / md→docx conversion."""
|
||||||
|
|
||||||
|
import importlib.resources as resources
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -24,28 +25,31 @@ def _write(data: dict) -> None:
|
|||||||
f.write("\n")
|
f.write("\n")
|
||||||
|
|
||||||
|
|
||||||
|
def _package_root() -> Path:
|
||||||
|
"""Return the templates directory bundled with the package."""
|
||||||
|
return Path(str(resources.files("mytoolkit") / "templates"))
|
||||||
|
|
||||||
|
|
||||||
def set_root(path: Path) -> Path:
|
def set_root(path: Path) -> Path:
|
||||||
"""Register the templates root directory. Returns the resolved path."""
|
"""Register an external templates root directory (override bundled templates)."""
|
||||||
resolved = Path(path).expanduser().resolve()
|
resolved = Path(path).expanduser().resolve()
|
||||||
_write({"dir": str(resolved)})
|
_write({"dir": str(resolved)})
|
||||||
return resolved
|
return resolved
|
||||||
|
|
||||||
|
|
||||||
def get_root() -> Path:
|
def get_root() -> Path:
|
||||||
"""Return the registered templates root, or raise UsageError if missing."""
|
"""Return the active templates root.
|
||||||
|
|
||||||
|
Uses the externally registered path if it exists and is valid; otherwise
|
||||||
|
falls back to the templates directory bundled with the package.
|
||||||
|
"""
|
||||||
data = _read()
|
data = _read()
|
||||||
raw = data.get("dir")
|
raw = data.get("dir")
|
||||||
if not raw:
|
if raw:
|
||||||
raise click.UsageError(
|
|
||||||
"Templates not registered. Run: mytoolkit templates register <path>"
|
|
||||||
)
|
|
||||||
root = Path(raw)
|
root = Path(raw)
|
||||||
if not root.is_dir():
|
if root.is_dir():
|
||||||
raise click.UsageError(
|
|
||||||
f"Registered templates dir does not exist: {root}\n"
|
|
||||||
"Re-run: mytoolkit templates register <path>"
|
|
||||||
)
|
|
||||||
return root
|
return root
|
||||||
|
return _package_root()
|
||||||
|
|
||||||
|
|
||||||
def get_md_to_pdf_root() -> Path:
|
def get_md_to_pdf_root() -> Path:
|
||||||
|
|||||||
Reference in New Issue
Block a user