summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/kanbun/kanbun.sty
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/kanbun/kanbun.sty')
-rw-r--r--macros/latex/contrib/kanbun/kanbun.sty317
1 files changed, 317 insertions, 0 deletions
diff --git a/macros/latex/contrib/kanbun/kanbun.sty b/macros/latex/contrib/kanbun/kanbun.sty
new file mode 100644
index 0000000000..70994ab463
--- /dev/null
+++ b/macros/latex/contrib/kanbun/kanbun.sty
@@ -0,0 +1,317 @@
+%% Copyright 2022 Yuanhao Chen
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+% http://www.latex-project.org/lppl.txt
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is Yuanhao Chen.
+%
+% This work consists of the files kanbun.sty, kanbun.lua,
+% kanbun-example.tex and kanbun.tex.
+%
+\NeedsTeXFormat{LaTeX2e}[2021/06/01]
+\RequirePackage{expl3,xparse,l3keys2e,ifluatex}
+\ProvidesExplClass{kanbun}
+ {2022/01/15} {1.0} {漢文の訓点文の組版}
+
+\ExplSyntaxOn
+\cs_generate_variant:Nn \str_if_eq:nnTF { V }
+\cs_generate_variant:Nn \str_case:nnTF { V }
+
+% vars used in options
+\tl_set:Nn \kanbun_scale { 2 }
+\newlength\kanbun_init_zw
+\setlength\kanbun_init_zw{1em}
+\@ifpackageloaded{luatexja-fontspec}{
+ \tl_set:Nn \kanbun_rubyfontcmd_default { \addjfontfeatures{RawFeature={+ruby}} }
+ \tl_set:Nn \kanbun_fontcmd_default { \addjfontfeatures{RawFeature={+trad}} }
+}{
+ \tl_set:Nn \kanbun_rubyfontcmd_default {}
+ \tl_set:Nn \kanbun_fontcmd_default {}
+}
+
+% options
+\keys_define:nn { kanbun }
+ {
+ , scale .tl_set:N = \kanbun_scale
+ , scale .initial:n = { 2 }
+ , fontcmd .tl_set:N = \kanbun_fontcmd
+ , fontcmd .initial:n = \kanbun_fontcmd_default
+ , rubyfontcmd .tl_set:N = \kanbun_rubyfontcmd
+ , rubyfontcmd .initial:n = \kanbun_rubyfontcmd_default
+ , unit .tl_set:N = \kanbun_zw
+ , unit .initial:n = { \kanbun_init_zw }
+ , yokoaki .tl_set:N = \kanbun_yokoaki
+ , yokoaki .initial:n = { \kanbun_scale }
+ , tateaki .tl_set:N = \kanbun_tateaki
+ , tateaki .initial:n = { 2 }
+ , okuriprotrusion .tl_set:N = \kanbun_okuriprotrusion
+ , okuriprotrusion .initial:n = { 1 }
+ , kumi .tl_set:N = \kanbun_kumi
+ , kumi .initial:n = { aki }
+ , aki .code:n = \keys_set:nn { kanbun } { kumi = aki }
+ , beta .code:n = \keys_set:nn { kanbun } { kumi = beta }
+ }
+\ProcessKeysOptions { kanbun }
+
+% other vars
+\tl_set:Nn \kanbun_rubyfontsize_rubyfontcmd { \kanbun_rubyfontcmd\fontsize{\fp_eval:n {1/\kanbun_scale}\kanbun_zw}{0pt}\selectfont }
+\newlength{\kanbun_furilen}
+\tl_set:Nn \kanbun_tateten_width { 1/30 }
+\tl_set:Nn \kanbunzwtosp { \fp_eval:n {\dim_ratio:nn { 1 \kanbun_zw } { 1 sp } } }
+\tl_set:Nn \kanbun_unit_glue {
+ \str_if_eq:VnTF \kanbun_kumi { aki } {
+ \penalty0
+ }
+ {
+ \hskip 0\kanbun_zw plus 0.25\kanbun_zw minus 0\kanbun_zw
+ }
+}
+\tl_set:Nn \kanbun_punct_glue {
+ \hskip 0\kanbun_zw plus 0.5\kanbun_zw minus 0\kanbun_zw
+}
+
+% \kanjiunit and other macros to be used in a \kanjiunit
+\NewDocumentCommand { \kanbun_ensure_height } { m m }
+ {
+ \vbox to #1{\vss{#2}\vss}
+ }
+\newbox\kanbun_current_kanjiunit
+\NewDocumentCommand { \kanjiunit } { m m m m m m }
+ {
+ \tl_set:Nn \ninojiten_punct {}
+ \tl_set:Nn \right_punct {}
+ \tl_set:Nn \central_punct {}
+ \process_punct{ #4 }
+ \tl_set:Nn \kanbun_central_punct_box {
+ \kanbun_ensure_height{1\kanbun_zw} {
+ \str_if_eq:VnTF \kanbun_kumi { aki }
+ {
+ \hbox{\kern 1\kanbun_zw{\hbox to \fp_eval:n { \kanbun_tateaki/\kanbun_scale }\kanbun_zw{\hss{\central_punct}\hss}}}
+ }
+ {
+ \hbox{\kern 1\kanbun_zw{\central_punct}}
+ }
+ }
+ }
+ \tl_set:Nn \kanbun_left_punct_phantom {
+ \kanbun_ensure_height{1\kanbun_zw} {
+ \str_if_eq:VnTF \kanbun_kumi { aki } { }
+ {
+ \str_if_eq:nnTF { #2 } { } { } {
+ \hbox{\phantom{\hbox to 0.5\kanbun_zw{\hss#2\hfil}}}
+ }
+ }
+ }
+ }
+ \tl_set:Nn \kanbun_right_punct_box {
+ \kanbun_ensure_height{1\kanbun_zw} {
+ \str_if_eq:VnTF \right_punct { } { } {
+ \hbox{\kern 1\kanbun_zw{\right_punct}}
+ }
+ }
+ }
+ %
+ \tl_set:Nn \unit_content {
+ \kanbun_left_punct_phantom % compensate for width of left punct
+ \vbox{
+ \kanbun_ensure_height{\fp_eval:n { 1/\kanbun_scale }\kanbun_zw}{\hbox{\kanbun_rubyfontsize_rubyfontcmd{#1}}} % right kana
+ \nointerlineskip %
+ \kanbun_ensure_height{1\kanbun_zw}{\llap{#2}} % left punct
+ \nointerlineskip %
+ \vspace*{-1 \kanbun_zw}
+ \kanbun_ensure_height{1\kanbun_zw}{
+ \hbox to 1\kanbun_zw{\hss{#3}\hss}
+ } % kanji
+ \nointerlineskip %
+ \vspace*{-1 \kanbun_zw}
+ \kanbun_ensure_height{\fp_eval:n { 1/\kanbun_scale }\kanbun_zw}{\hbox{\kern 1\kanbun_zw{\ninojiten_punct}}} % ninojiten
+ \nointerlineskip %
+ \vspace*{\fp_eval:n { -1/\kanbun_scale }\kanbun_zw}
+ \kanbun_right_punct_box % right punct
+ \nointerlineskip %
+ \vspace*{-1\kanbun_zw}
+ \kanbun_central_punct_box % central punct
+ \nointerlineskip %
+ \vspace*{ \fp_eval:n { -1/\kanbun_scale }\kanbun_zw }
+ \kanbun_ensure_height{\fp_eval:n { 1/\kanbun_scale }\kanbun_zw}{\hbox{\kanbun_rubyfontsize_rubyfontcmd\kern 1\kanbun_zw{\kaeriten{#5}}}} % kaeriten
+ \nointerlineskip %
+ \kanbun_ensure_height{\fp_eval:n { 1/\kanbun_scale }\kanbun_zw}{\hbox{\kanbun_rubyfontsize_rubyfontcmd{#6}}} % left kana
+ }
+ }
+ \str_if_eq:VnTF \kanbun_kumi { aki } {
+ \setbox\kanbun_current_kanjiunit \hbox to \fp_eval:n { 1+\kanbun_tateaki/\kanbun_scale }\kanbun_zw{ \unit_content }
+ }{
+ \setbox\kanbun_current_kanjiunit \hbox{ \unit_content }
+ }
+ %
+ % output
+ \str_if_eq:VnTF \kanbun_kumi { aki } { }
+ {
+ \str_if_eq:nnTF { #2 } { } { } {
+ \kanbun_punct_glue
+ }
+ }
+ \nobreak
+ \str_if_eq:VnTF \kanbun_kumi { aki }
+ {
+ \usebox\kanbun_current_kanjiunit
+ }
+ {
+ \discretionary{
+ \usebox\kanbun_current_kanjiunit\kern\dimexpr1\kanbun_zw-\wd\kanbun_current_kanjiunit\relax
+ }{
+ %
+ }{
+ \usebox\kanbun_current_kanjiunit
+ }
+ }
+ \nobreak
+ \str_if_eq:VnTF \kanbun_kumi { aki } { }
+ {
+ \str_if_eq:VnTF \right_punct { } { } {
+ \kanbun_punct_glue
+ }
+ }
+ \nobreak
+ \kanbun_unit_glue
+ }
+\NewDocumentCommand { \furiokuri } { m m }
+ {
+ \settowidth{\kanbun_furilen}{#1}
+ \ifdim\kanbun_furilen < \fp_eval:n {1-\kanbun_okuriprotrusion/\kanbun_scale}\kanbun_zw
+ \makebox[\fp_eval:n {1-\kanbun_okuriprotrusion/\kanbun_scale}\kanbun_zw][l]{#1}
+ \else
+ #1
+ \fi
+ #2
+ }
+\NewDocumentCommand { \kaeriten } { m }
+ {
+ \tl_set:Nn \kaeriten_output { #1 }
+ \sys_if_engine_xetex:TF {} {
+ \platex_if_direction_tate:TF {
+ \str_case:VnTF \kaeriten_output {
+ { 一レ } { \tl_set:Nn \kaeriten_output { \kern \fp_eval:n {-0.25/\kanbun_scale}\kanbun_zw 一\kern \fp_eval:n {-0.75/\kanbun_scale}\kanbun_zw レ } }
+ { 甲レ } { \tl_set:Nn \kaeriten_output { 甲\kern \fp_eval:n {-0.25/\kanbun_scale}\kanbun_zw レ } }
+ { 上レ } { \tl_set:Nn \kaeriten_output { 上\kern \fp_eval:n {-0.25/\kanbun_scale}\kanbun_zw レ } }
+ { 天レ } { \tl_set:Nn \kaeriten_output { 天\kern \fp_eval:n {-0.25/\kanbun_scale}\kanbun_zw レ } }
+ } {} {}
+ } {}
+ }
+ \tl_use:N \kaeriten_output
+ }
+\NewDocumentCommand { \process_punct_map } { m } {
+ \str_case:nnTF { #1 } {
+ { — } { \tl_put_right:Nn \central_punct { \tateten } }
+ { ― } { \tl_put_right:Nn \central_punct { \tateten } }
+ { ㆐ } { \tl_put_right:Nn \central_punct { \tateten } }
+ % { : } { \tl_put_right:Nn \central_punct { \hbox to 1\kanbun_zw{\hss{:}\hss} } }
+ % { ・ } { \tl_put_right:Nn \central_punct { \hbox to 1\kanbun_zw{\hss{・}\hss} } }
+ { : } { \tl_put_right:Nn \right_punct { \hbox to 0.5\kanbun_zw{\hss{:}\hss} } }
+ { ・ } { \tl_put_right:Nn \right_punct { \hbox to 0.5\kanbun_zw{\hss{・}\hss} } }
+ { … } { \tl_put_right:Nn \central_punct { \hbox to 1\kanbun_zw{\hss{…}\hss} } }
+ { ! } { \tl_put_right:Nn \central_punct { \hbox to 1\kanbun_zw{\hss{!}\hss} } }
+ { ? } { \tl_put_right:Nn \central_punct { \hbox to 1\kanbun_zw{\hss{?}\hss} } }
+ { 〻 } {
+ \tl_put_right:Nn \ninojiten_punct { \ninojiten }
+ \tl_put_right:Nn \right_punct { \phantom{\ninojiten} }
+ }
+ } {} {
+ \tl_put_right:Nn \right_punct { \hbox to 0.5\kanbun_zw{\hfil#1\hss} }
+ }
+}
+\NewDocumentCommand { \process_punct } { m }
+ {
+ \str_map_function:nN { #1 } \process_punct_map
+ }
+\NewDocumentCommand { \multifuriokuri } { O{2\kanbun_zw} m m }
+ {
+ \kanbun_rubyfontcmd
+ \kern \fp_eval:n { -(#1) }\kanbun_zw
+ \makebox[\fp_eval:n { (#1) + 1 - \kanbun_okuriprotrusion/\kanbun_scale }\kanbun_zw][s]{#2}
+ #3
+ }
+
+% these commands are used as punct
+\NewDocumentCommand { \tateten } {}
+ {
+ \str_if_eq:VnTF \kanbun_kumi { aki } {
+ \makebox[\fp_eval:n {\kanbun_tateaki/\kanbun_scale}\kanbun_zw][c]{
+ \rule[\fp_eval:n {-\kanbun_tateten_width/2}\kanbun_zw]{\fp_eval:n {\kanbun_tateaki/\kanbun_scale}\kanbun_zw}{\fp_eval:n {\kanbun_tateten_width}\kanbun_zw}
+ }
+ }{
+ \makebox[\fp_eval:n {1/\kanbun_scale}\kanbun_zw][c]{
+ \rule[\fp_eval:n {-\kanbun_tateten_width/2}\kanbun_zw]{\fp_eval:n {1/\kanbun_scale}\kanbun_zw}{\fp_eval:n {\kanbun_tateten_width}\kanbun_zw}
+ }
+ }
+ }
+\NewDocumentCommand { \ninojiten } {}
+ { \kanbun_rubyfontsize_rubyfontcmd 〻 }
+
+% corrects fontsize of ruby base
+\NewDocumentCommand { \kanbunfont } {} { \parindent=0pt\kanbun_fontcmd\fontsize{\kanbun_zw}{\fp_eval:n {1+\kanbun_yokoaki/\kanbun_scale}\kanbun_zw}\selectfont}
+\NewDocumentEnvironment { kanjipar } { +b }
+ {
+ {
+ \kanbunfont
+ #1
+ \par
+ }
+ } {}
+
+% for LuaLaTeX to parse Kanbun annotation
+\NewDocumentCommand{\matchkana}{ m }{
+ \regex_set:Nn \c_kana_regex {[\x{3040}-\x{30FA}\x{30FC}-\x{30FF}\x{31F0}-\x{31FF}\x{FF66}-\x{FF9F}\x{1B100}-\x{1B122}\x{1AFF0}-\x{1AFFF}\x{1B000}-\x{1B0FF}\x{1B130}-\x{1B16F}]}
+ \regex_match:NnTF \c_kana_regex { #1 } { \bool_set_true:N \g_kana_bool } { \bool_set_false:N \g_kana_bool }
+}
+%
+\ExplSyntaxOff
+%
+\ifluatex
+% verbatim reader adapted from https://tex.stackexchange.com/a/361759
+\directlua{
+verb_table = {}
+function store_lines (str)
+ if string.find (str , "\noexpand\\EndKanbun" ) then
+ luatexbase.remove_from_callback (
+ "process_input_buffer" , "store_lines")
+ return "\\newif\\ifcontinue\\continuetrue\\directlua { co = coroutine.create(main_loop) }\\loop\\directlua{ ok,b=coroutine.resume(co) tex.sprint(b) }\\ifcontinue\\repeat"
+ else
+ table.insert(verb_table, str)
+ end
+ return ""
+end
+function register_verbatim ()
+ verb_table = {}
+ luatexbase.add_to_callback(
+ "process_input_buffer" , store_lines , "store_lines")
+end
+% require main loop
+kanbunzwtosp = \luaescapestring{\kanbunzwtosp}
+require("kanbun.lua")
+}
+\def\Kanbun{\directlua{register_verbatim()}}
+\def\createcatcodes{%
+ \bgroup%
+ \catcode`\\=12 \catcode`\{=12 \catcode`\}=12%
+ \catcode`\$=12 \catcode`\&=12 \catcode`\^^M=13%
+ \catcode`\#=12 \catcode`\^=12 \catcode`\_=12%
+ \catcode`\ =13 \catcode`\~=12 \catcode`\%=12%
+ \savecatcodetable 1%
+ \egroup%
+}
+\createcatcodes
+\bgroup%
+ \catcode`\^^M=13\gdef^^M{\quitvmode\par}%
+ \catcode`\ = 13\gdef {\quitvmode\Space}%
+\egroup%
+\def\Space{ }
+%
+\fi