Дублирование знаков математических операций при переносе внутритекстовых формул

Sep 21, 2009 00:46

Традиции русской типографики требуют, чтобы при переносе длинных формул разрыв происходил по одному из знаков математических действий, а сам знак дублировался в начале следующей строки. Тем не менее, TeX изначально знаки не дублирует. И несмотря на то, что попытки научить TeX действовать в русских традициях производились более 10 лет назад (см., например, M.I. Grinchuk «TeX and Russian Traditions of Typesetting», TUGboat 17(4) (1996) 385), готового пакета для решения этой задачи я не встречал. Поэтому и набросал свою версию на базе идей, описанных М.И. Гринчуком.


Пакет для LaTeX был назван rumathbr.sty (Russian Math Breaking) и его текст приведен ниже (когда появится свободное время - постараюсь оформить пакет в виде dtx с подробными комментариями). Надеюсь, что кому-нибудь он пригодится. Обо всех найденных ошибках пишите в комментариях

rumathbr.sty

% ================================================================
% Russian-style hyphenation of inline equations
% (C) 2009 Denis Ryabov.
%
% Based on ideas and code from M.I.Grinchuk "TeX and Russian
% Traditions of Typesetting", TUGboat 17 (1996) 4.
%
% CHANGELOG:
% -------------------- 0.97 [08-October-2009] --------------------
% [#] problem with operators like '+^\leq'
% -------------------- 0.96 [29-September-2009] ------------------
% [#] problem with '-' in AMS \DeclareMathOperator
% [#] problem with \ldots in text mode
% -------------------- 0.95 [28-September-2009] ------------------
% [#] problem with sub/sup-scripts after relations
% [+] hyphenation on \ldots
% [+] AMS/Lucida left brackets (lvert, lVert, ulcorner, llcorner)
% support
% [+] mathbbol.sty left bracket (Lbrack) support
% [^] huge code refactoring
% -------------------- 0.91 [21-September-2009] ------------------
% [#] problem with space after brackets
% -------------------- 0.90 [20-September-2009] ------------------
% [!] first public release
%
%
% KNOWN ISSUES:
% 'xy' package: should be loaded after 'rumathbr' to work properly
% 'breqn' package: cannot work together with 'rumathbr'
% ================================================================
%
% Перенос строчных формул в русском стиле (с дублированием знаков)
% (C) 2009 Денис Рябов.
%
% Основано на идеях и коде из M.I.Grinchuk "TeX and Russian
% Traditions of Typesetting", TUGboat 17 (1996) 4.
%
% ИЗМЕНЕНИЯ:
% -------------------- 0.97 [08 октября 2009] --------------------
% [#] решена проблема с операторами типа '+^\leq'
% -------------------- 0.96 [29 сентября 2009] -------------------
% [#] решена проблема с '-' в AMS \DeclareMathOperator
% [#] решена проблема с \ldots в текстовой моде
% -------------------- 0.95 [28 сентября 2009] -------------------
% [#] решена проблема с над- и подстрочными индексами после знаков
% [+] перенос на \ldots
% [+] учитываются открывающие скобки из AMS/Lucida (lvert, lVert,
% ulcorner, llcorner)
% [+] учитываются открывающие скобки из mathbbol.sty (Lbrack)
% [^] код пакета в значительной степени переработан
% -------------------- 0.91 [21 сентября 2009] -------------------
% [#] решена проблема с отступами после скобок
% -------------------- 0.90 [20 сентября 2009] -------------------
% [!] первая публичная версия
%
%
% ИЗВЕСТНЫЕ ПРОБЛЕМЫ:
% пакет xy: для корректной работы должен загружать после rumathbr
% пакет breqn: не может работать совместно с rumathbr
% ================================================================
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{rumathbr}[2009/10/08 v0.97]

% to make next symbol nonbreakable
\def\nobr{\penalty\relpenalty}

% penalties (disable default breaks)
\relpenalty=13131
\binoppenalty=14141

% first symbol in equation is nonbreakable
\expandafter\everymath\expandafter{\the\everymath %
\penalty\relpenalty %
}

% shrink space in math (C) kst-777 & v782
% from http://community.livejournal.com/ru_tex/62487.html
% TODO: should be optionally
\expandafter\everymath\expandafter{\the\everymath %
\medmuskip=3mu plus 1mu minus 1mu %
\thickmuskip=3mu plus 1mu minus 1mu %
}

\let\lowerindex=_
\let\upperindex=^
\catcode`\_=12
\catcode`\^=12

\def\set@brokens{%
\def\brokenbin##1{\protect\prbr@bin{##1}}%
\def\brokenrel##1{\protect\prbr@rel{##1}}%
\def\brokeninner##1{\protect\prbr@inner{##1}}%
}
\def\unset@brokens{%
\def\brokenbin##1{##1}%
\def\brokenrel##1{##1}%
\def\brokeninner##1{##1}%
}

\set@brokens

\def\prbr@bin#1%
{%
\def\@tempa{#1}%
\def\@tempb{\prbr@bin}%
\def\@tempc{\@brokenbin}%
\futurelet\@tempd\@brokenop%
}
\def\@brokenbin#1%
{%
\ifnum\lastpenalty=\relpenalty%
\mathbin{#1}%
\else%
\mathbin{#1}\@selector{#1}%
\fi%
\set@brokens%
\penalty\binoppenalty %
}

\def\prbr@rel#1%
{%
\def\@tempa{#1}%
\def\@tempb{\prbr@rel}%
\def\@tempc{\@brokenrel}%
\futurelet\@tempd\@brokenop%
}
\def\@brokenrel#1%
{%
\ifnum\lastpenalty=\relpenalty%
\mathrel{#1}%
\else%
\mathrel{#1}\@selector{#1}%
\fi%
\set@brokens%
\penalty\relpenalty %
}

\def\prbr@inner#1%
{%
\def\@tempa{#1}%
\def\@tempb{\prbr@inner}%
\def\@tempc{\@brokeninner}%
\futurelet\@tempd\@brokenop%
}
\def\@brokeninner#1%
{%
\ifnum\lastpenalty=\relpenalty%
\mathinner{#1}%
\else%
\mathinner{#1}\@selector{#1}%
\fi%
\set@brokens%
\penalty\relpenalty %
}

\def\@selector#1%
{%
\mathchoice%
{\discretionary{}{\hbox{$\displaystyle#1$}}{}}%
{\discretionary{}{\hbox{$\textstyle#1$}}{}}%
{\discretionary{}{\hbox{$\scriptstyle#1$}}{}}%
{\discretionary{}{\hbox{$\scriptscriptstyle#1$}}{}} %
}
\def\@brokenop%
{%
\ifmmode%
\unset@brokens
\ifx_\@tempd%
\let\@command=\@brokenglue%
\else\ifx^\@tempd%
\let\@command=\@brokenglue%
\else%
\let\@command=\@tempc%
\fi\fi%
\else%
\let\@command=\relax%
\fi%
\expandafter\@command{\@tempa}%
}
\def\@brokenglue#1#2#3%
{%
\edef\@tempe{#1#2{#3}}%
\expandafter\@tempb{\@tempe}%
}

\begingroup
\catcode`\=\active \xdef={\noexpand\brokenrel{\mathchar\number\mathcode`\=}}
\catcode`\<\active \xdef<{\noexpand\brokenrel{\mathchar\number\mathcode`\<}}
\catcode`\>\active \xdef>{\noexpand\brokenrel{\mathchar\number\mathcode`\>}}
\catcode`\+\active \xdef+{\noexpand\brokenbin{\mathchar\number\mathcode`\+}}
\catcode`\-\active \xdef-{\noexpand\brokenbin{\mathchar\number\mathcode`\-}}
\catcode`\_\active \gdef_#1{\lowerindex{{#1}}}
\catcode`\^\active \gdef^#1{\upperindex{{#1}}}
\catcode`\(\active \xdef({\mathopen\delimiter\number\delcode`\(\nobr}
\catcode`\[\active \xdef[{\mathopen\delimiter\number\delcode`\[\nobr}
\catcode`\:\active \xdef:{\mathchar\number\mathcode`\:\nobr} % patch for :=
\endgroup

\AtBeginDocument%
{%
\mathcode`\==32768%
\mathcode`\<=32768%
\mathcode`\>=32768%
\mathcode`\+=32768%
\mathcode`\-=32768%
\mathcode`\_=32768%
\mathcode`\^=32768%
\mathcode`\(=32768%
\mathcode`\[=32768%
\mathcode`\:=32768%
\let\orig@resetMathstrut=\resetMathstrut@%
\begingroup%
\catcode`\"=12%
\gdef\resetMathstrut@%
{%
\mathcode`\(="4028%
\orig@resetMathstrut%
\mathcode`\(="8000%
}%
\gdef\newmcodes@%
{%
\mathcode`\'=39%
\mathcode`\*=42%
\mathcode`\.="613A%
\mathcode`\-=45%
\mathcode`\/=47%
\mathcode`\:="603A%
\relax%
}%
\endgroup %
}

\def\setopenbracket#1{\ifx#1\undefined\else\xdef#1{#1\nobr}\fi}
\def\setbreakablebin#1{\@setbreakable{#1}{\brokenbin}}
\def\setbreakablerel#1{\@setbreakable{#1}{\brokenrel}}
\def\setbreakablerelex#1#2{\gdef#1{#2}\setbreakablerel{#1}}
\def\setbreakableinner#1{\@setbreakable{#1}{\brokeninner}}

\def\@setbreakable#1#2%
{%
\begingroup%
\ifx#1\undefined%
\else%
\escapechar`\@%
\edef\test@a{orig\string#1}%
\escapechar`\\%
\@ifundefined\test@a{%
\edef\cs@temp##1##2{\gdef##1{##2{\csname\test@a\endcsname}}}
\global\expandafter\let\csname\test@a\endcsname=#1%
\cs@temp{#1}{#2}
}\relax%
\fi%
\endgroup%
}

% \not
\let\originalnot=\not
\def\not#1%
{%
\begingroup%
\escapechar`\@%
\edef\test@a{orig\string#1}%
\escapechar`\\%
\@ifundefined\test@a{%
\brokenrel{\originalnot#1}%
}{%
\brokenrel{\originalnot\csname\test@a\endcsname}%
}%
\endgroup%
}

% Open brackets
\def\bigl#1{\mathopen\big#1\penalty\relpenalty}
\def\Bigl#1{\mathopen\Big#1\penalty\relpenalty}
\def\biggl#1{\mathopen\bigg#1\penalty\relpenalty}
\def\Biggl#1{\mathopen\Bigg#1\penalty\relpenalty}
\setopenbracket{\lmoustache}
\setopenbracket{\langle}
\setopenbracket{\lbrace}
\setopenbracket{\lceil}
\setopenbracket{\lfloor}
\setopenbracket{\lgroup}
\setopenbracket{\lvert}
\setopenbracket{\lVert}
\setopenbracket{\ulcorner}
\setopenbracket{\llcorner}
\setopenbracket{\Lbrack}

% Inners
\setbreakableinner{\ldots}
\setbreakableinner{\cdots}

% Binary Operations
\setbreakablebin{\triangleleft}
\setbreakablebin{\triangleright}
\setbreakablebin{\bigtriangleup}
\setbreakablebin{\bigtriangledown}
\setbreakablebin{\wedge} \let\land=\wedge
\setbreakablebin{\vee} \let\lor=\vee
\setbreakablebin{\cap}
\setbreakablebin{\cup}
\setbreakablebin{\ddagger}
\setbreakablebin{\dagger}
\setbreakablebin{\sqcap}
\setbreakablebin{\sqcup}
\setbreakablebin{\uplus}
\setbreakablebin{\amalg}
\setbreakablebin{\diamond}
\setbreakablebin{\bullet}
\setbreakablebin{\wr}
\setbreakablebin{\div}
\setbreakablebin{\odot}
\setbreakablebin{\oslash}
\setbreakablebin{\otimes}
\setbreakablebin{\ominus}
\setbreakablebin{\oplus}
\setbreakablebin{\mp}
\setbreakablebin{\pm}
\setbreakablebin{\circ}
\setbreakablebin{\bigcirc}
\setbreakablebin{\setminus}
\setbreakablebin{\ast}
\setbreakablebin{\star}
\setbreakablebin{\times}
%\setbreakablebin{\cdot} % TODO (if possible)
\def\*{\discretionary{\thinspace\the\textfont2\char2}%
{\the\textfont2\char2\thinspace}{}}

% Relations
\setbreakablerel{\propto}
\setbreakablerel{\sqsubseteq}
\setbreakablerel{\sqsupseteq}
\setbreakablerel{\parallel}
\setbreakablerel{\mid}
\setbreakablerel{\dashv}
\setbreakablerel{\vdash}
\setbreakablerel{\leq} \let\le=\leq
\setbreakablerel{\geq} \let\ge=\geq
\setbreakablerel{\succ}
\setbreakablerel{\prec}
\setbreakablerel{\approx}
\setbreakablerel{\succeq}
\setbreakablerel{\preceq}
\setbreakablerel{\supset}
\setbreakablerel{\subset}
\setbreakablerel{\supseteq}
\setbreakablerel{\subseteq}
\setbreakablerel{\in}
\setbreakablerel{\ni} \let\owns=\ni
\setbreakablerel{\gg}
\setbreakablerel{\ll}
\setbreakablerel{\sim}
\setbreakablerel{\simeq}
\setbreakablerel{\perp}
\setbreakablerel{\equiv}
\setbreakablerel{\asymp}
\setbreakablerel{\smile}
\setbreakablerel{\frown}
\setbreakablerel{\models}
\setbreakablerel{\cong}
\setbreakablerel{\notin}
\setbreakablerel{\doteq}
% TODO: using of Lucida font for \bowtie, if loaded
\setbreakablerelex{\bowtie}{\orig@triangleright\mkern-3mu\orig@triangleleft}
%\setbreakablerel{\neq} % Works well without \setbreakablerel
%\setbreakablerel{\ne} % Works well without \setbreakablerel

% Arrows
\setbreakablerel{\nearrow}
\setbreakablerel{\searrow}
\setbreakablerel{\nwarrow}
\setbreakablerel{\swarrow}
\setbreakablerel{\Leftrightarrow}
\setbreakablerel{\Leftarrow}
\setbreakablerel{\Rightarrow}
\setbreakablerel{\leftrightarrow}
\setbreakablerel{\leftarrow} \let\gets=\leftarrow
\setbreakablerel{\rightarrow} \let\to=\rightarrow
\setbreakablerel{\leftharpoonup}
\setbreakablerel{\leftharpoondown}
\setbreakablerel{\rightharpoonup}
\setbreakablerel{\rightharpoondown}
\setbreakablerel{\longleftarrow}
\setbreakablerel{\Longleftarrow}
\setbreakablerel{\longrightarrow}
\setbreakablerel{\Longrightarrow}
\setbreakablerel{\longleftrightarrow}
\setbreakablerel{\Longleftrightarrow}
%\mapstochar
\setbreakablerel{\mapsto}
\setbreakablerel{\longmapsto}
%\lhook
%\rhook
\setbreakablerel{\hookleftarrow}
\setbreakablerel{\hookrightarrow}
\setbreakablerel{\rightleftharpoons}

\@ifpackageloaded{latexsym}{ % latexsym
\setbreakablebin{\lhd}
\setbreakablebin{\unlhd}
\setbreakablebin{\rhd}
\setbreakablebin{\unrhd}
\setbreakablerel{\Join}
\setbreakablerel{\leadsto}
\setbreakablerel{\sqsubset}
\setbreakablerel{\sqsupset}
}{}

\@ifpackageloaded{amstex}{ % amstex
\setbreakablerel{\rightleftharpoons}
\setbreakablerel{\sqsubset}
\setbreakablerel{\sqsupset}
\setbreakablerel{\vartriangleright}
\setbreakablerel{\vartriangleleft}
\setbreakablerel{\trianglerighteq}
\setbreakablerel{\trianglelefteq}
\setbreakablerel{\rightsquigarrow}
}{}

\@ifpackageloaded{amsfont}{ % amsfont
\setbreakablerel{\rightleftharpoons}
\setbreakablerel{\sqsubset}
\setbreakablerel{\sqsupset}
\setbreakablerel{\vartriangleright}
\setbreakablerel{\vartriangleleft}
\setbreakablerel{\trianglerighteq}
\setbreakablerel{\trianglelefteq}
\setbreakablerel{\rightsquigarrow}
}{}

\@ifpackageloaded{amssymb}{ % amssymb
\setbreakablebin{\boxdot}
\setbreakablebin{\boxplus}
\setbreakablebin{\boxtimes}
\setbreakablebin{\centerdot}
\setbreakablebin{\boxminus}
\setbreakablebin{\veebar}
\setbreakablebin{\barwedge}
\setbreakablebin{\doublebarwedge}
\setbreakablebin{\Cup}
\setbreakablebin{\Cap}
\setbreakablebin{\curlywedge}
\setbreakablebin{\curlyvee}
\setbreakablebin{\leftthreetimes}
\setbreakablebin{\rightthreetimes}
\setbreakablebin{\dotplus}
\setbreakablebin{\intercal}
\setbreakablebin{\circledcirc}
\setbreakablebin{\circledast}
\setbreakablebin{\circleddash}
\setbreakablebin{\divideontimes}
\setbreakablebin{\lessdot}
\setbreakablebin{\gtrdot}
\setbreakablebin{\ltimes}
\setbreakablebin{\rtimes}
\setbreakablebin{\smallsetminus}
\setbreakablerel{\circlearrowright}
\setbreakablerel{\circlearrowleft}
\setbreakablerel{\leftrightharpoons}
\setbreakablerel{\Vdash}
\setbreakablerel{\Vvdash}
\setbreakablerel{\vDash}
\setbreakablerel{\twoheadrightarrow}
\setbreakablerel{\twoheadleftarrow}
\setbreakablerel{\leftleftarrows}
\setbreakablerel{\rightrightarrows}
\setbreakablerel{\upuparrows}
\setbreakablerel{\downdownarrows}
\setbreakablerel{\upharpoonright}
\setbreakablerel{\downharpoonright}
\setbreakablerel{\upharpoonleft}
\setbreakablerel{\downharpoonleft}
\setbreakablerel{\rightarrowtail}
\setbreakablerel{\leftarrowtail}
\setbreakablerel{\leftrightarrows}
\setbreakablerel{\rightleftarrows}
\setbreakablerel{\Lsh}
\setbreakablerel{\Rsh}
\setbreakablerel{\rightsquigarrow}
\setbreakablerel{\leftrightsquigarrow}
\setbreakablerel{\looparrowleft}
\setbreakablerel{\looparrowright}
\setbreakablerel{\circeq}
\setbreakablerel{\succsim}
\setbreakablerel{\gtrsim}
\setbreakablerel{\gtrapprox}
\setbreakablerel{\multimap}
\setbreakablerel{\therefore}
\setbreakablerel{\because}
\setbreakablerel{\doteqdot}
\setbreakablerel{\triangleq}
\setbreakablerel{\precsim}
\setbreakablerel{\lesssim}
\setbreakablerel{\lessapprox}
\setbreakablerel{\eqslantless}
\setbreakablerel{\eqslantgtr}
\setbreakablerel{\curlyeqprec}
\setbreakablerel{\curlyeqsucc}
\setbreakablerel{\preccurlyeq}
\setbreakablerel{\leqq}
\setbreakablerel{\leqslant}
\setbreakablerel{\lessgtr}
\setbreakablerel{\risingdotseq}
\setbreakablerel{\fallingdotseq}
\setbreakablerel{\succcurlyeq}
\setbreakablerel{\geqq}
\setbreakablerel{\geqslant}
\setbreakablerel{\gtrless}
\setbreakablerel{\vartriangleright}
\setbreakablerel{\vartriangleleft}
\setbreakablerel{\trianglerighteq}
\setbreakablerel{\trianglelefteq}
\setbreakablerel{\between}
\setbreakablerel{\blacktriangleright}
\setbreakablerel{\blacktriangleleft}
\setbreakablerel{\vartriangle}
\setbreakablerel{\eqcirc}
\setbreakablerel{\lesseqgtr}
\setbreakablerel{\gtreqless}
\setbreakablerel{\lesseqqgtr}
\setbreakablerel{\gtreqqless}
\setbreakablerel{\Rrightarrow}
\setbreakablerel{\Lleftarrow}
\setbreakablerel{\varpropto}
\setbreakablerel{\smallsmile}
\setbreakablerel{\smallfrown}
\setbreakablerel{\Subset}
\setbreakablerel{\Supset}
\setbreakablerel{\subseteqq}
\setbreakablerel{\supseteqq}
\setbreakablerel{\bumpeq}
\setbreakablerel{\Bumpeq}
\setbreakablerel{\lll}
\setbreakablerel{\ggg}
\setbreakablerel{\pitchfork}
\setbreakablerel{\backsim}
\setbreakablerel{\backsimeq}
\setbreakablerel{\lvertneqq}
\setbreakablerel{\gvertneqq}
\setbreakablerel{\nleq}
\setbreakablerel{\ngeq}
\setbreakablerel{\nless}
\setbreakablerel{\ngtr}
\setbreakablerel{\nprec}
\setbreakablerel{\nsucc}
\setbreakablerel{\lneqq}
\setbreakablerel{\gneqq}
\setbreakablerel{\nleqslant}
\setbreakablerel{\ngeqslant}
\setbreakablerel{\lneq}
\setbreakablerel{\gneq}
\setbreakablerel{\npreceq}
\setbreakablerel{\nsucceq}
\setbreakablerel{\precnsim}
\setbreakablerel{\succnsim}
\setbreakablerel{\lnsim}
\setbreakablerel{\gnsim}
\setbreakablerel{\nleqq}
\setbreakablerel{\ngeqq}
\setbreakablerel{\precneqq}
\setbreakablerel{\succneqq}
\setbreakablerel{\precnapprox}
\setbreakablerel{\succnapprox}
\setbreakablerel{\lnapprox}
\setbreakablerel{\gnapprox}
\setbreakablerel{\nsim}
\setbreakablerel{\ncong}
\setbreakablerel{\varsubsetneq}
\setbreakablerel{\varsupsetneq}
\setbreakablerel{\nsubseteqq}
\setbreakablerel{\nsupseteqq}
\setbreakablerel{\subsetneqq}
\setbreakablerel{\supsetneqq}
\setbreakablerel{\varsubsetneqq}
\setbreakablerel{\varsupsetneqq}
\setbreakablerel{\subsetneq}
\setbreakablerel{\supsetneq}
\setbreakablerel{\nsubseteq}
\setbreakablerel{\nsupseteq}
\setbreakablerel{\nparallel}
\setbreakablerel{\nmid}
\setbreakablerel{\nshortmid}
\setbreakablerel{\nshortparallel}
\setbreakablerel{\nvdash}
\setbreakablerel{\nVdash}
\setbreakablerel{\nvDash}
\setbreakablerel{\nVDash}
\setbreakablerel{\ntrianglerighteq}
\setbreakablerel{\ntrianglelefteq}
\setbreakablerel{\ntriangleleft}
\setbreakablerel{\ntriangleright}
\setbreakablerel{\nleftarrow}
\setbreakablerel{\nrightarrow}
\setbreakablerel{\nLeftarrow}
\setbreakablerel{\nRightarrow}
\setbreakablerel{\nLeftrightarrow}
\setbreakablerel{\nleftrightarrow}
\setbreakablerel{\eqsim}
\setbreakablerel{\shortmid}
\setbreakablerel{\shortparallel}
\setbreakablerel{\thicksim}
\setbreakablerel{\thickapprox}
\setbreakablerel{\approxeq}
\setbreakablerel{\succapprox}
\setbreakablerel{\precapprox}
\setbreakablerel{\curvearrowleft}
\setbreakablerel{\curvearrowright}
\setbreakablerel{\backepsilon}
}{}

latex, tex, rumathbr

Next post
Up