Я пытаюсь отладить часть своего кода, который работает, когда все написано слева направо, и работает, когда все написано справа налево, но дает сбой, когда направление основного документа отличается от направления внутри одной из моих сред.
Мне удалось сократить свой код до чего-то довольно простого, но я признаю, что это не будет ясно из вопроса, зачем мне вообще делать то, что я делаю... Кроме того, поведение немного отличается от моего гораздо более сложного реального кода, так что я мог что-то упустить.
Проблема
- В приведенном ниже коде я использую
\predisplaysize
для измерения длины последней строки абзаца. - Когда вы это сделаете, вам нужно будет извлечь данные
\prevgraf
из внутренней части отображения математики, чтобы впоследствии сбросить их и сохранить интервалы. - В коде ниже
\prevgraf
сбрасывается 4 раза в конце каждого из моих списковых окружений. Но его значение отличается в зависимости от того, меняю ли я язык перед первым списковым окружением или в начале спискового окружения. В MWE ниже каждый последующий вызов\measureline
дает\prevgraf
1, 1, 1, затем 0.
Почему это так? И как мне добиться последовательного поведения?
Я знаю, что пример странный, но почему должна быть разница в зависимости от того, звоню ли я \setlanguage{ukenglish}
раньше listenva
, а не первым, что внутри listenva
???
(Я хочу поведение второго примера в MWE ниже. То есть шаблон \prevgraf
для четырех вызовов \measureline
должен быть: 1, 0, 1, 0. Вы можете увидеть это, когда закомментируете \babelprovide[import, main]{persian}
, гарантируя, что язык перед началом listenva
такой же, как тот, что установлен внутри listenva
)
Вещи, которые я замечаю
Вызов
\@noparlistfalse
перед\endlist
в\listenvb
среде — это то, что гарантирует, что\prevgraf
при втором вызове будет 0. Другими словами, если я закомментирую эту строку,\prevgraf
будет 1 для каждого из четырех вызовов\measureline
.Та же проблема возникает, когда основным языком документа является язык с написанием слева направо, а в моей среде задан язык с написанием справа налево.
Группировка также влияет на вещи:
Это работает:
\listenva \begin{listenvb} Test. \end{listenvb} \endlistenva
Но это не срабатывает:
\begingroup \selectlanguage{ukenglish} \begin{listenva} \begin{listenvb} Test. \end{listenvb} \end{listenva} \endgroup
МВЭ
%! TeX Program = lualatex
\documentclass{article}
\pagestyle{empty}
\usepackage[bidi=basic, layout=lists]{babel}
\babelprovide[import, main]{persian}
\babelprovide[import]{ukenglish}
\newdimen\linelen
\newcommand{\measureline}{%
\abovedisplayshortskip -\baselineskip
\abovedisplayskip\abovedisplayshortskip
\belowdisplayshortskip 0pt
\belowdisplayskip\belowdisplayshortskip
$$
\ifdim\predisplaysize>0pt
\global\linelen\dimexpr\predisplaysize-2em
\fi
\global\def\resetspacing{%
\predisplaysize\the\predisplaysize
\prevgraf\the\prevgraf
}%
$$
\resetspacing
\ifdim\linelen>0pt
\vskip-\baselineskip
\fi
}
\newcommand{\nolistspaces}{%
\leftmargin 0pt
\rightmargin 0pt
\itemindent 0pt
\partopsep 0pt
\parsep 0pt
\topsep 0pt
}
\newenvironment{listenva}{%
\selectlanguage{ukenglish}%
\list{}{\nolistspaces}%
\item\relax
}{%
\measureline
\strut\hskip\linelen+++%
\csname @noparlistfalse\endcsname
\endlist
}
\newenvironment{listenvb}{%
\list{}{\nolistspaces}%
\item\relax
}{%
\measureline
\csname @noparlistfalse\endcsname
\endlist
}
\begin{document}
\begin{listenva}
\begin{listenvb}
Test.
\end{listenvb}
\end{listenva}
\selectlanguage{ukenglish}
\begin{listenva}
\begin{listenvb}
Test.
\end{listenvb}
\end{listenva}
\end{document}
Я получаю неправильный вывод
Желаемый результат
решение1
Рассмотрим следующее
\showboxdepth\maxdimen\showboxbreadth\maxdimen
\tracingonline1\tracingoutput1
\everypar{\setbox0=\lastbox}
{%\textdirection=0
$$
$$\par}
\bye
что дает выход
\vbox(667.20255+0.0)x469.75499, direction TLT
.\vbox(0.0+0.0)x469.75499, glue set 14.0fil, direction TLT
..\glue -22.5
..\hbox(8.5+0.0)x469.75499, glue set 469.755fil, direction TLT
...\vbox(8.5+0.0)x0.0, direction TLT
...\glue 0.0 plus 1.0fil
..\glue 0.0 plus 1.0fil minus 1.0fil
.\vbox(643.20255+0.0)x234.8775, glue set 626.20251fill, direction TLT
..\glue(\topskip) 10.0
..\hbox(0.0+0.0)x0.0, shifted 234.8775, direction TLT
..\penalty 0
..\glue(\belowdisplayshortskip) 7.0 plus 3.0 minus 4.0
..\glue 0.0 plus 1.0fill
.\glue(\baselineskip) 17.55556
.\hbox(6.44444+0.0)x469.75499, glue set 232.37749fil, direction TLT
..\glue 0.0 plus 1.0fil minus 1.0fil
..\tenrm 1
..\glue 0.0 plus 1.0fil minus 1.0fil
а если я раскомментирую, то \textdirection=0
вывод будет таким:
\vbox(667.20255+0.0)x469.75499, direction TLT
.\vbox(0.0+0.0)x469.75499, glue set 14.0fil, direction TLT
..\glue -22.5
..\hbox(8.5+0.0)x469.75499, glue set 469.755fil, direction TLT
...\vbox(8.5+0.0)x0.0, direction TLT
...\glue 0.0 plus 1.0fil
..\glue 0.0 plus 1.0fil minus 1.0fil
.\vbox(643.20255+0.0)x469.75499, glue set 614.20251fill, direction TLT
..\glue(\topskip) 10.0
..\hbox(0.0+0.0)x469.75499, glue set 469.755fil, direction TLT
...\localpar
....\localinterlinepenalty=0
....\localbrokenpenalty=0
....\localleftbox=null
....\localrightbox=null
...\begindir TLT
...\penalty 10000
...\enddir TLT
...\glue(\parfillskip) 0.0 plus 1.0fil
...\glue(\rightskip) 0.0
..\penalty 10000
..\glue(\abovedisplayshortskip) 0.0 plus 3.0
..\glue(\baselineskip) 12.0
..\hbox(0.0+0.0)x0.0, shifted 234.8775, direction TLT
..\penalty 0
..\glue(\belowdisplayshortskip) 7.0 plus 3.0 minus 4.0
..\glue 0.0 plus 1.0fill
.\glue(\baselineskip) 17.55556
.\hbox(6.44444+0.0)x469.75499, glue set 232.37749fil, direction TLT
..\glue 0.0 plus 1.0fil minus 1.0fil
..\tenrm 1
..\glue 0.0 plus 1.0fil minus 1.0fil
Похоже, что когда вы явно вставляете узел dir (используя \textdir
) в группу, LuaTeX не отбрасывает пустую строку перед отображением (возможно, он не считает ее пустой из-за узлов dir вокруг штрафа). Не уверен, следует ли это считать ошибкой или нет.
Я не разбираюсь в коде Babel, но предполагаю, что Babel не вставляет узлы dir, когда в этом нет необходимости, и поэтому, когда вы помещаете их \selectlanguage{ukenglish}
на верхний уровень группировки, Babel не внедряет больше узлов dir внутрь группы вашей среды.
Вероятно, вы сможете обойтись без использования трюка с отображением, чтобы получить длину последней строки, если вы готовы использовать немного lua:
\documentclass{article}
\pagestyle{empty}
\usepackage[bidi=basic, layout=lists]{babel}
\babelprovide[import, main]{persian}
\babelprovide[import]{ukenglish}
\newdimen\linelen
\directlua{
local disabled = true
local function lastline_length(head,c)
if disabled then
return head
end
local last_line = node.tail(head)
local parfill_node
for n in node.traverse_id(node.id('glue'),last_line.list) do
if n.subtype == 15 then parfill_node = n end
end
local length, _, _ = node.rangedimensions(last_line,last_line.head,parfill_node)
tex.setdimen('global', 'linelen',length)
return head
end
local getlastlinelength = luatexbase.new_luafunction"getlastlinelength"
lua.get_functions_table()[getlastlinelength] = function() disabled = false end
token.set_lua("getlastlinelength", getlastlinelength, "protected")
local dontgetlastlinelength = luatexbase.new_luafunction"dontgetlastlinelength"
lua.get_functions_table()[dontgetlastlinelength] = function() disabled = true end
token.set_lua("dontgetlastlinelength", dontgetlastlinelength, "protected")
luatexbase.add_to_callback('post_linebreak_filter',lastline_length,'lastline')
}
\newcommand{\nolistspaces}{%
\leftmargin 0pt
\rightmargin 0pt
\itemindent 0pt
\partopsep 0pt
\parsep 0pt
\topsep 0pt
}
\newenvironment{listenva}{%
\selectlanguage{ukenglish}%
\list{}{\nolistspaces}%
\item\relax
}{%
\ifdim\linelen>0pt
\vskip-\baselineskip
\fi
\strut\hskip\linelen+++%
\csname @noparlistfalse\endcsname
\endlist
}
\newenvironment{listenvb}{%
\global\linelen=0pt
\getlastlinelength
\list{}{\nolistspaces}%
\item\relax
}{%
\csname @noparlistfalse\endcsname
\endlist
\dontgetlastlinelength
}
\begin{document}
\begin{listenva}
\begin{listenvb}
Test.
\end{listenvb}
\end{listenva}
\selectlanguage{ukenglish}
\begin{listenva}
\begin{listenvb}
Test.
\end{listenvb}
\end{listenva}
\end{document}