diff --git a/.agents/skills/mytoolkit/references/latex.md b/.agents/skills/mytoolkit/references/latex.md index b7ed9e4..3037d45 100644 --- a/.agents/skills/mytoolkit/references/latex.md +++ b/.agents/skills/mytoolkit/references/latex.md @@ -8,15 +8,16 @@ mytoolkit latex compile paper.tex -e xelatex mytoolkit latex count paper.tex ``` -## 论文脚手架 / 投稿模板 +## 论文/手册脚手架 · 投稿模板 ```bash -mytoolkit init paper # 新建论文项目(elsarticle 脚手架,xelatex,可移植;精确配置见生成的 main.tex 头部注释,设计约束见仓库 AGENTS.md §3) +mytoolkit init paper # 新建论文项目(elsarticle 脚手架,xelatex,可移植;精确配置见生成的 main.tex 头部注释,设计约束见仓库 AGENTS.md §4) +mytoolkit init manual # 新建手册项目(技术与使用文档;与 md-to-pdf/manual Typst 模板同一视觉风格,ctexart + xelatex) mytoolkit init journal # 列出投稿套件 mytoolkit init journal elsevier # Elsevier / ieee / springer 套件 → ./submit-/ ``` -投稿套件自带文档类与 bst,`make`(pdflatex+bibtex)直接编译;自动复用当前目录 `references.bib`。Springer 切样式只改 `\documentclass[...,sn-xxx]{sn-jnl}` 选项,勿写 `\bibliographystyle`。详见 AGENTS.md §3。 +投稿套件自带文档类与 bst,`make`(pdflatex+bibtex)直接编译;自动复用当前目录 `references.bib`。Springer 切样式只改 `\documentclass[...,sn-xxx]{sn-jnl}` 选项,勿写 `\bibliographystyle`。详见 AGENTS.md §4。 ### PDF 命名约定 diff --git a/.agents/skills/mytoolkit/references/others.md b/.agents/skills/mytoolkit/references/others.md index 355237c..94de5d2 100644 --- a/.agents/skills/mytoolkit/references/others.md +++ b/.agents/skills/mytoolkit/references/others.md @@ -4,6 +4,7 @@ ```bash mytoolkit init paper # 初始化 LaTeX 论文项目 +mytoolkit init manual # 初始化 LaTeX 手册项目(技术与使用文档) mytoolkit env # 环境变量管理 mytoolkit git # Git 辅助工具 mytoolkit ssh # SSH 快捷连接 diff --git a/AGENTS.md b/AGENTS.md index d8b3f4f..64650cc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -79,7 +79,9 @@ mytoolkit voice tts "文本" -v zh_male_wennuanahu_moon_bigtts --format mp3 --sp --- -## 4. LaTeX 论文脚手架与投稿模板 +## 4. LaTeX 脚手架与投稿模板 + +模板三分法(按用途,勿混放):`templates/`(convert 转换模板,md 为源)/ `scaffolds/`(init 项目脚手架,LaTeX 源工程)/ `journals/`(init journal 投稿套件,自包含)。 ### 新建论文项目 @@ -94,6 +96,14 @@ mytoolkit init paper # 默认 Elsevier elsarticle 模板(全平 - 统一 **xelatex** 一个引擎(latexmk 驱动),便于后续加中文/系统字体; - `make` 编译、`make highlighted OLDTEX=...` 出 latexdiff 修订稿;`diffpreamble.dtx` 标记增删。 +### 新建手册项目(技术与使用文档) + +```bash +mytoolkit init manual # LaTeX 手册模板(ctexart,xelatex) +``` + +与 Typst `md-to-pdf/manual` 模板同一视觉风格(封面 + 目录 + 彩色标题 + 四色提示框 + 代码高亮 + 三线表),**配色与版式改动须两个模板同步**。生成 `main.tex`/`Makefile`/`README.md`;字体走 ctex 自动字体集,不写死系统字体。 + ### 切换投稿期刊模板 各出版社“投稿套件”预置在包内 `mytoolkit/journals/`,一条命令落地到子目录,自包含、`make` 直接编译(pdflatex + bibtex): diff --git a/README.md b/README.md index 99075ce..9551b98 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ mytoolkit --help | Command | What it does | |---------|--------------| | `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 `, `mytoolkit init journal `) | +| `init` | Initialize projects/kits from bundled templates (`mytoolkit init paper|manual `, `mytoolkit init journal `) | | `info` | Show bundled resource paths (`info paths`, `info docs `) | | `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) | @@ -92,9 +92,11 @@ Registry is stored at `~/.mytoolkit/templates.json` (or `$MYTOOLKIT_HOME/templat ```bash mytoolkit init paper # create a LaTeX paper project (Elsevier elsarticle, xelatex, fully portable) +mytoolkit init manual # create a LaTeX manual project (technical/user docs, same style as md-to-pdf/manual) ``` -This generates `main.tex`, `Makefile`, `references.bib`, `diffpreamble.dtx`, `figs/`. +`init paper` generates `main.tex`, `Makefile`, `references.bib`, `diffpreamble.dtx`, `figs/`. +`init manual` generates `main.tex` (cover + TOC + callout boxes + code listing + three-line tables), `Makefile`, `README.md`. ### Journal submission kits diff --git a/mytoolkit/commands/init.py b/mytoolkit/commands/init.py index adfd8b3..a5acc96 100644 --- a/mytoolkit/commands/init.py +++ b/mytoolkit/commands/init.py @@ -39,14 +39,11 @@ def init_cmd(): 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: +def _init_scaffold(name: str, target: Path) -> None: + """Copy the bundled scaffold NAME into TARGET (must be empty or absent).""" + with _scaffold_path(name) as scaffold: if not scaffold.is_dir(): - raise RuntimeError(f"Paper scaffold not found: {scaffold}") + raise RuntimeError(f"Scaffold not found: {scaffold}") if target.exists(): if any(target.iterdir()): @@ -58,7 +55,7 @@ def init_paper(target: Path): 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") + click.secho(f"Initialized {name} project at {target}", fg="green") for path in created: click.echo(f" {path}") @@ -67,6 +64,22 @@ def init_paper(target: Path): click.echo(" make") +@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.""" + _init_scaffold("paper", target) + + +@init_cmd.command("manual") +@click.argument("target", type=click.Path(file_okay=False, dir_okay=True, path_type=Path)) +@handle_errors +def init_manual(target: Path): + """Initialize a LaTeX manual (technical/user doc) project in TARGET.""" + _init_scaffold("manual", target) + + @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) diff --git a/mytoolkit/scaffolds/manual/Makefile b/mytoolkit/scaffolds/manual/Makefile new file mode 100644 index 0000000..8c50bad --- /dev/null +++ b/mytoolkit/scaffolds/manual/Makefile @@ -0,0 +1,54 @@ +.PHONY: all clean show-errors show-log watch help + +TEXFILE ?= $(if $(wildcard main.tex),main.tex,$(firstword $(filter-out highlighted.tex old.tex,$(wildcard *.tex)))) +PROJECT = $(basename $(TEXFILE)) +LATEXMK = latexmk +OUTDIR = build +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 $(PROJECT).spl + +all: + @mkdir -p $(OUTDIR) + @echo "Compiling $(PROJECT).tex (xelatex, 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) + +clean: + $(LATEXMK) -C -outdir=$(OUTDIR) $(PROJECT).tex + rm -rf $(OUTDIR) + rm -f $(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 watch" continuous preview-compile (latexmk -pvc)' + @echo '5. "make clean" remove build/ and stray artifacts' + @echo diff --git a/mytoolkit/scaffolds/manual/README.md b/mytoolkit/scaffolds/manual/README.md new file mode 100644 index 0000000..bc942c3 --- /dev/null +++ b/mytoolkit/scaffolds/manual/README.md @@ -0,0 +1,38 @@ +# Manual Project + +This project was initialized with `mytoolkit init manual`. It is a LaTeX +manual template (technical & user documentation) with the same visual style as +the Typst `md-to-pdf/manual` template: cover page, TOC, colored headings, +callout boxes, code listings, and three-line tables. Compiles with `xelatex` +via `latexmk`; CJK fonts are resolved by `ctex` automatically. + +## Directory Structure + +- `main.tex`: main document (cover, styles, demo content — replace with yours) +- `Makefile`: build script +- `build/`: build output (auto-generated) + +## Build + +```bash +make +``` + +A successful build produces `main.pdf`. + +## Callout Boxes + +Four colored boxes are predefined (optional argument overrides the title): + +```latex +\begin{infobox}[自定义标题] ... \end{infobox} +\begin{tipbox} ... \end{tipbox} +\begin{warnbox} ... \end{warnbox} +\begin{dangerbox} ... \end{dangerbox} +``` + +## Other Commands + +- `make clean`: remove build artifacts +- `make watch`: continuous preview compilation +- `make show-errors`: show the most recent build errors diff --git a/mytoolkit/scaffolds/manual/main.tex b/mytoolkit/scaffolds/manual/main.tex new file mode 100644 index 0000000..989934e --- /dev/null +++ b/mytoolkit/scaffolds/manual/main.tex @@ -0,0 +1,227 @@ +%% Manual template (technical & user documentation). +%% Same visual style as the Typst md-to-pdf/manual template: +%% cover page + TOC + colored headings + callout boxes + code listing + three-line tables. +%% Engine: xelatex (via latexmk); CJK fonts resolved by ctex automatically (portable). +\documentclass[UTF8,10pt]{ctexart} + +\usepackage[a4paper,margin=2cm]{geometry} +\usepackage{xcolor} +\usepackage{graphicx} +\usepackage{booktabs} +\usepackage{colortbl} +\usepackage{listings} +\usepackage[most]{tcolorbox} +\usepackage{titlesec} +\usepackage{fancyhdr} +\usepackage{enumitem} +\usepackage{hyperref} + +% ---- palette (keep in sync with templates/md-to-pdf/manual/template.typ) ---- +\definecolor{primary}{HTML}{1F4E79} +\definecolor{secondary}{HTML}{2C3E50} +\definecolor{accent}{HTML}{3467A8} +\definecolor{light}{HTML}{96A0AA} +\colorlet{ruleblue}{accent!46!white} + +\definecolor{infocolor}{HTML}{0EA5E9} +\definecolor{tipcolor}{HTML}{10B981} +\definecolor{warncolor}{HTML}{F59E0B} +\definecolor{dangercolor}{HTML}{EF4444} + +\definecolor{codebg}{HTML}{F8F9FA} +\definecolor{codenum}{HTML}{6E7681} + +\hypersetup{colorlinks=true, linkcolor=accent, urlcolor=accent, citecolor=accent, + bookmarksopen=true, bookmarksopenlevel=2} + +% ---- headings (numbered; add \setcounter{secnumdepth}{-2} to go unnumbered) ---- +\setcounter{tocdepth}{2} +\titleformat{\section}{\fontsize{18}{22}\selectfont\bfseries\color{primary}} + {\thesection}{0.6em}{} +\titlespacing*{\section}{0pt}{1.45em plus 4pt}{0.55em} +\titleformat{\subsection}{\fontsize{13}{16}\selectfont\bfseries\color{accent}} + {\thesubsection}{0.6em}{} +\titlespacing*{\subsection}{0pt}{1.1em plus 3pt}{0.5em} +\titleformat{\subsubsection}{\fontsize{11}{14}\selectfont\bfseries\color{secondary}} + {\thesubsubsection}{0.6em}{} +\titlespacing*{\subsubsection}{0pt}{0.8em plus 2pt}{0.4em} + +% ---- header: current section (right); footer: page number (center) ---- +\pagestyle{fancy} +\fancyhf{} +\setlength{\headheight}{14pt} +\renewcommand{\headrulewidth}{0pt} +\renewcommand{\sectionmark}[1]{\markright{#1}} +\fancyhead[R]{\fontsize{8}{10}\selectfont\color{light}\rightmark} +\fancyfoot[C]{\fontsize{8}{10}\selectfont\color{light}--- \thepage\ ---} + +% ---- compact lists ---- +\setlist{nosep, leftmargin=1.8em} + +% ---- three-line tables: \toprule / \midrule / \bottomrule ---- +\arrayrulecolor{ruleblue} + +% ---- code listing (rounded corners need tcolorbox; plain frame keeps it light) ---- +\lstset{ + basicstyle=\ttfamily\small, + backgroundcolor=\color{codebg}, + frame=single, framerule=0.5pt, rulecolor=\color{ruleblue}, + framesep=3pt, xleftmargin=2em, + numbers=left, numberstyle=\tiny\color{codenum}, numbersep=8pt, + breaklines=true, columns=fullflexible, keepspaces=true, + showstringspaces=false, + keywordstyle=\color{accent}\bfseries, + commentstyle=\color{light}\itshape, + stringstyle=\color{tipcolor}, +} + +% ---- callout boxes: title bar colored, body white (mirrors Typst showybox) ---- +\newtcolorbox{infobox}[1][信息]{enhanced, breakable, + colback=white, colframe=infocolor, colbacktitle=infocolor, coltitle=white, + fonttitle=\bfseries, title={#1}, boxrule=1pt, arc=2mm, + left=2mm, right=2mm, top=1.5mm, bottom=1.5mm} +\newtcolorbox{tipbox}[1][提示]{enhanced, breakable, + colback=white, colframe=tipcolor, colbacktitle=tipcolor, coltitle=white, + fonttitle=\bfseries, title={#1}, boxrule=1pt, arc=2mm, + left=2mm, right=2mm, top=1.5mm, bottom=1.5mm} +\newtcolorbox{warnbox}[1][注意]{enhanced, breakable, + colback=white, colframe=warncolor, colbacktitle=warncolor, coltitle=white, + fonttitle=\bfseries, title={#1}, boxrule=1pt, arc=2mm, + left=2mm, right=2mm, top=1.5mm, bottom=1.5mm} +\newtcolorbox{dangerbox}[1][危险]{enhanced, breakable, + colback=white, colframe=dangercolor, colbacktitle=dangercolor, coltitle=white, + fonttitle=\bfseries, title={#1}, boxrule=1pt, arc=2mm, + left=2mm, right=2mm, top=1.5mm, bottom=1.5mm} + +\begin{document} + +% ---- cover page ---- +\begin{titlepage} + \centering + \vspace*{2cm} + {\fontsize{28}{34}\selectfont\bfseries\color{primary} Phynexis Python API 参考手册\par} + \vspace{0.8cm} + {\fontsize{16}{20}\selectfont\color{accent} 技术与使用文档\par} + \vspace{2cm} + {\fontsize{12}{16}\selectfont\color{light} 2026 年 7 月\par} + \vfill +\end{titlepage} + +\tableofcontents +\newpage + +\section{快速开始} + +\subsection{安装} + +通过 pip 安装 Phynexis: + +\begin{lstlisting}[language=bash] +pip install phynexis +\end{lstlisting} + +\begin{tipbox}[提示] +建议使用虚拟环境安装,避免与系统 Python 包冲突: + +\begin{lstlisting}[language=bash] +python -m venv venv +source venv/bin/activate # Linux/macOS +\end{lstlisting} +\end{tipbox} + +\subsection{第一个示例} + +\begin{lstlisting}[language=Python] +from phynexis import Model, Mesh + +# 创建简单网格 +mesh = Mesh.rectangle(width=1.0, height=1.0, nx=20, ny=20) + +# 定义材料模型并求解 +model = Model(mesh) +model.set_material(young=210e9, nu=0.3, rho=7850) +result = model.solve() +print(f"最大位移: {result.max_displacement:.6f} m") +\end{lstlisting} + +\section{核心 API} + +\subsection{Mesh 类} + +网格是有限元分析的基础。\lstinline|Mesh| 类提供多种工厂方法创建常见几何。 + +\begin{infobox}[\lstinline|Mesh.rectangle|] +\textbf{签名}: \lstinline|Mesh.rectangle(width, height, nx, ny)| + +\textbf{参数}: + +\begin{center} +\begin{tabular}{lll} +\toprule +参数 & 类型 & 说明 \\ +\midrule +\lstinline|width| & float & 矩形宽度 \\ +\lstinline|height| & float & 矩形高度 \\ +\lstinline|nx| & int & x 方向单元数 \\ +\lstinline|ny| & int & y 方向单元数 \\ +\bottomrule +\end{tabular} +\end{center} + +\textbf{返回}: \lstinline|Mesh| 实例 +\end{infobox} + +\subsection{Model 类} + +\lstinline|Model| 封装了物理场求解的完整流程: + +\begin{lstlisting}[language=Python] +model = Model(mesh) +model.set_material(young=210e9, nu=0.3) +model.fix_boundary(tag="left") # 固定左侧边界 +model.apply_force(tag="right", fx=1e6) # 右侧施加力 +result = model.solve(solver="direct") +\end{lstlisting} + +\begin{warnbox}[注意] +\lstinline|solve()| 默认使用直接求解器。大规模问题(> 100,000 DOF)建议改用迭代求解器: + +\begin{lstlisting}[language=Python] +result = model.solve(solver="cg", preconditioner="ilu") +\end{lstlisting} +\end{warnbox} + +\section{高级用法} + +\subsection{并行计算} + +\begin{dangerbox}[危险] +在并行环境内分配数组时,务必确保每个进程只分配自己的局部部分。全局数组会导致内存溢出: + +\begin{lstlisting}[language=Python] +local_K = np.zeros((n_local, n_local)) # 正确:只分配局部矩阵 +\end{lstlisting} +\end{dangerbox} + +\section{故障排除} + +\textbf{Q: 求解器收敛失败} + +检查以下事项: + +\begin{enumerate} + \item 边界条件是否充分约束了刚体位移 + \item 材料参数是否合理(特别是泊松比接近 0.5 时) + \item 网格质量是否太差 +\end{enumerate} + +\section{版本历史} + +\subsection{v2.1.0 (2026-05-01)} + +\begin{itemize} + \item 新增 GPU 加速求解器(CUDA 后端) + \item 支持非线性材料模型 +\end{itemize} + +\end{document}