共计 6986 个字符,预计需要花费 18 分钟才能阅读完成。
上一篇:伪竖排
对每个人最偏心的莫过于工夫。绝大多数人的工夫,被极少数的人以花样繁多的管理学伎俩轻轻偷去了一部分。窃钱者蹲监狱,窃工夫者为老板。若每个人都能管好本人的工夫,天下必将大同。
工夫戳增强版
回顾一下之前在 card-env.tex 文件里定义的工夫戳:
\startluacode | |
my = {} | |
function my.is_cjk_char(c) | |
if c >= 0x3400 and c <= 0x4db5 | |
or c >= 0x4e00 and c <= 0x9fa5 | |
or c >= 0x9fa6 and c <= 0x9fbb | |
or c >= 0xf900 and c <= 0xfa2d | |
or c >= 0xfa30 and c <= 0xfa6a | |
or c >= 0xfa70 and c <= 0xfad9 | |
or c >= 0x20000 and c <= 0x2a6d6 | |
or c >= 0x2f800 and c <= 0x2fa1d | |
or c >= 0xff00 and c <= 0xffef | |
or c >= 0x2e80 and c <= 0x2eff | |
or c >= 0x3000 and c <= 0x303f | |
or c >= 0x31c0 and c <= 0x31ef then | |
return true; | |
else | |
return false; | |
end | |
end | |
function my.rotate(x, a) | |
pad = "\\kern.125em" | |
for _, c in utf8.codes(x) do | |
if my.is_cjk_char(c) then | |
context("%s{\\rotate[rotation=%d]{%s}}%s", pad, a, utf8.char(c), pad) | |
else | |
context("{\\raise.5\\maxdepth\\hbox{%s}}", utf8.char(c)) | |
end | |
end | |
end | |
\stopluacode | |
\def\timestamp#1{\rotate[rotation=270]{\ctxlua{my.rotate("#1", 90)}}} | |
\setuptexttexts | |
[margin] | |
[][\hfill{\timestamp{2023 年 01 月 26 日 凌晨 04 时 44 分}}\hfill] |
当初,将 \timestamp
定义为
\def\timestamp#1{% | |
\page | |
\setuptexttexts | |
[margin][][\hfill{\rotate[rotation=270]{\ctxlua{my.rotate("#1", 90)}}}\hfill] | |
} |
重定义的 \timestamp
宏承受一个参数,应用 \page
另起新页,将参数内容安放于页面右侧留白区域。上面是 \timestamp
的用法示例:
\environment card-env | |
\starttext | |
\timestamp{2023 年 01 月 30 日} | |
测试页 1 | |
\timestamp{2023 年 01 月 31 日} | |
测试页 2 | |
\stoptext |
\page
宏用于分页,仅在前后皆有内容时无效,例如
\starttext | |
\page | |
foo | |
\page | |
bar | |
\page | |
\stoptext |
其中,第一个和第三个 \page
是无用的,会被 TeX 编译器疏忽,只有第二个 \page
无效,使得 foo
和 bar
各占一页。
待办事项
用 ConTeXt 的 xtable 能够模仿风行一时的 To do List。
首先,结构一个三列的表格:
\environment card-env | |
\starttext | |
\timestamp{2023 年 01 月 31 日} | |
\definextable[todolist] | |
\startxtable[todolist] | |
\startxrow | |
\startxcell $\circ$ \stopxcell | |
\startxcell 晒太阳 \stopxcell | |
\startxcell $\checkmark$ \stopxcell | |
\stopxrow | |
\startxrow | |
\startxcell $\circ$ \stopxcell | |
\startxcell 包饺子 \stopxcell | |
\startxcell $\checkmark$ \stopxcell | |
\stopxrow | |
\startxrow | |
\startxcell $\circ$ \stopxcell | |
\startxcell 拖地板 \stopxcell | |
\startxcell $\checkmark$ \stopxcell | |
\stopxrow | |
\stopxtable | |
\stoptext |
假使排版后果未呈现 $\cdot$ 和 $\checkmark$ 符号,可在 card-env.tex 里设定数学字体:
\definefontfamily[myfont][serif][sourcehanserifcn] | |
\definefontfamily[myfont][math][xitsmath] % <--- 增加这一行!\setscript[hanzi] | |
\setupbodyfont[myfont,7pt] |
当初暗藏表格的边框,将第一列宽度调整为 1.5em
,第二列宽度设置为 .9\textwidth
,即版心宽度的 0.9 倍,第三列宽度设置为 .1\textwidth
:
\setupxtable[todolist][frame=off] | |
\startxtable[todolist] | |
\startxrow | |
\startxcell[width=1.5em] $\circ$ \stopxcell | |
\startxcell[width=.9\textwidth] 晒太阳 \stopxcell | |
\startxcell[width=.1\textwidth] $\checkmark$ \stopxcell | |
\stopxrow | |
\startxrow | |
\startxcell $\circ$ \stopxcell | |
\startxcell 包饺子 \stopxcell | |
\startxcell $\checkmark$ \stopxcell | |
\stopxrow | |
\startxrow | |
\startxcell $\circ$ \stopxcell | |
\startxcell 拖地板 \stopxcell | |
\startxcell \stopxcell | |
\stopxrow | |
\stopxtable |
Lua 表 -> ConTeXt 表格
为了减少一条待办事项,须要写一堆命令,不胜其繁。因为这些宏的呈现具备重复性,因而能够思考用 Lua 编程的形式予以简化,因为在 Lua 语言里,表格的语法非常简单。例如
\startxtable | |
\startxrow | |
\startxcell 1\stopxcell | |
\startxcell 2\stopxcell | |
\startxcell 3\stopxcell | |
\stopxrow | |
\stopxtable |
所表白的表格模式,用 Lua 的表构造可表述为
{1, 2, 3}
上面的示例可将 Lua 表构造转化为 ConTeXt 表格:
\environment card-env | |
\startluacode | |
my = my or {} | |
local ctx = context | |
function my.add(row) | |
ctx.startxrow() | |
for _, v in ipairs(row) do | |
ctx.startxcell(); context(v); ctx.stopxcell() | |
end | |
ctx.stopxrow() | |
end | |
\stopluacode | |
\def\foo#1{\ctxlua{my.add({#1})}} | |
\starttext | |
% 将表格单元长宽均设为 2em,且令内容居中 | |
\setupxtable[width=2em, height=2em, align={middle,lohi}] | |
\startxtable | |
\foo{4, 9, 2} | |
\foo{3, 5, 7} | |
\foo{8, 1, 6} | |
\stopxtable | |
\stoptext |
以上述 Lua 代码为根底,略加修改,便可简化待办事项的增加:
\environment card-env | |
\definextable[todolist] | |
\setupxtable[todolist][frame=off] | |
\startluacode | |
my = my or {} | |
local ctx = context | |
local dim = number.todimen | |
local textwidth = tex.dimen.textwidth | |
function my.task(task, status) | |
ctx.startxrow() | |
-- 第一列 | |
ctx.startxcell{width=dim(tex.sp("1.5em"))}; | |
context("$\\circ$"); | |
ctx.stopxcell() | |
-- 第二列 | |
ctx.startxcell{width=dim(0.9 * textwidth)}; | |
context("%s", task); | |
ctx.stopxcell() | |
-- 第三列 | |
ctx.startxcell{width=dim(0.1 * textwidth),align="{middle,lohi}"}; | |
context(status); | |
ctx.stopxcell() | |
ctx.stopxrow() | |
end | |
\stopluacode | |
\def\task#1#2{\ctxlua{my.task("#1", "#2")}} | |
\starttext | |
\timestamp{2023 年 01 月 31 日} | |
\startxtable[todolist] | |
\task{晒太阳}{$\\checkmark$} | |
\task{包饺子}{$\\checkmark$} | |
\task{拖地板}{} | |
\stopxtable | |
\stoptext |
留神,在上述代码里,\circ
和 \checkmark
里的反斜线符号 \
呈现在 Lua 语境里时,须要增加反斜线 \
予以本义。若要躲避该问题,能够应用 Lua 的长字串语法。
Lua 长字串
以下 Lua i 代码定义了 4 个字符串变量:
local a = "\\starttext ... \\stoptext" | |
local b = [[\starttext ... \stoptext]] | |
local c = [=[\starttext ... \stoptext]=] | |
local d = [==[\starttext ... \stoptext]==] |
其中,a
的值用的是 Lua 短字符串语法,而 b
,c
和 d
的值用的是 Lua 长字符串语法。在长字符串语法中,\
符号无需本义,且字符串能够间接换行,无需应用换行符 \n
。例如,短字符串
local a = "\\starttext\n ... \n\\stoptext"
与之等价的长字符串为
local a = [[\starttext | |
... | |
\stoptext]] |
基于 Lua 长字串语法,待办事项的宏定义与用法示例可批改为
\environment card-env | |
\definextable[todolist] | |
\setupxtable[todolist][frame=off] | |
\startluacode | |
my = my or {} | |
local ctx = context | |
local dim = number.todimen | |
local textwidth = tex.dimen.textwidth | |
function my.task(task, status) | |
ctx.startxrow() | |
-- 第一列 | |
ctx.startxcell{width=dim(tex.sp("1.5em"))}; | |
context([[$\circ$]]); | |
ctx.stopxcell() | |
-- 第二列 | |
ctx.startxcell{width=dim(0.9 * textwidth)}; | |
context([[%s]], task); | |
ctx.stopxcell() | |
-- 第三列 | |
ctx.startxcell{width=dim(0.1 * textwidth),align="{middle,lohi}"}; | |
context(status); | |
ctx.stopxcell() | |
ctx.stopxrow() | |
end | |
\stopluacode | |
\def\task#1#2{\ctxlua{my.task([[#1]], [[#2]])}} | |
\starttext | |
\timestamp{2023 年 01 月 31 日} | |
\startxtable[todolist] | |
\task{晒太阳}{$\checkmark$} | |
\task{包饺子}{$\checkmark$} | |
\task{拖地板}{} | |
\stopxtable | |
\stoptext |
将上述代码中的 \environment
和 \starttext
语句之间的代码挪移到 card-env.tex 文件。
结语
card.tex:
\environment card-env | |
\starttext | |
\timestamp{2023 年 01 月 31 日} | |
\startxtable[todolist] | |
\task{晒太阳}{$\checkmark$} | |
\task{包饺子}{$\checkmark$} | |
\task{拖地板}{} | |
\stopxtable | |
\stoptext |
card-env.tex:
% 页面布局 | |
\definepapersize[card][width=85.6mm,height=53.98mm] | |
\setuppapersize[card] | |
\setuplayout | |
[backspace=.1\paperwidth, | |
width=.8\paperwidth, | |
topspace=.015\paperheight, | |
height=.97\paperheight, | |
leftmargin=.666\backspace, | |
rightmargin=.666\cutspace, | |
headerdistance=.025\makeupheight, | |
footerdistance=.025\makeupheight, | |
textheight=.95\makeupheight] | |
% 字体 | |
\definefontfamily[myfont][serif][sourcehanserifcn] | |
\definefontfamily[myfont][math][xitsmath] | |
\setscript[hanzi] | |
\setupbodyfont[myfont,7pt] | |
% 页码 | |
\setuppagenumbering[location=] | |
\setupfootertexts[margin][][\hfill\pagenumber\hfill] | |
% 题目 | |
\setuphead[title][align=middle] | |
% 工夫戳 | |
\startluacode | |
my = {} | |
function my.is_cjk_char(c) | |
if c >= 0x3400 and c <= 0x4db5 | |
or c >= 0x4e00 and c <= 0x9fa5 | |
or c >= 0x9fa6 and c <= 0x9fbb | |
or c >= 0xf900 and c <= 0xfa2d | |
or c >= 0xfa30 and c <= 0xfa6a | |
or c >= 0xfa70 and c <= 0xfad9 | |
or c >= 0x20000 and c <= 0x2a6d6 | |
or c >= 0x2f800 and c <= 0x2fa1d | |
or c >= 0xff00 and c <= 0xffef | |
or c >= 0x2e80 and c <= 0x2eff | |
or c >= 0x3000 and c <= 0x303f | |
or c >= 0x31c0 and c <= 0x31ef then | |
return true; | |
else | |
return false; | |
end | |
end | |
function my.rotate(x, a) | |
pad = "\\kern.125em" | |
for _, c in utf8.codes(x) do | |
if my.is_cjk_char(c) then | |
context("%s{\\rotate[rotation=%d]{%s}}%s", pad, a, utf8.char(c), pad) | |
else | |
context("{\\raise.5\\maxdepth\\hbox{%s}}", utf8.char(c)) | |
end | |
end | |
end | |
\stopluacode | |
\def\timestamp#1{% | |
\page | |
\setuptexttexts | |
[margin] | |
[][\hfill{\rotate[rotation=270]{\ctxlua{my.rotate("#1", 90)}}}\hfill] | |
} | |
% 待办事项 | |
\definextable[todolist] | |
\setupxtable[todolist][frame=off] | |
\startluacode | |
my = my or {} | |
local ctx = context | |
local dim = number.todimen | |
local textwidth = tex.dimen.textwidth | |
function my.task(task, status) | |
ctx.startxrow() | |
-- 第一列 | |
ctx.startxcell{width=dim(tex.sp("1.5em"))}; | |
context([[$\circ$]]); | |
ctx.stopxcell() | |
-- 第二列 | |
ctx.startxcell{width=dim(0.9 * textwidth)}; | |
context([[%s]], task); | |
ctx.stopxcell() | |
-- 第三列 | |
ctx.startxcell{width=dim(0.1 * textwidth),align="{middle,lohi}"}; | |
context(status); | |
ctx.stopxcell() | |
ctx.stopxrow() | |
end | |
\stopluacode | |
\def\task#1#2{\ctxlua{my.task([[#1]], [[#2]])}} |