У меня есть команда, которая использует синтаксис ключ-значение. Например, она включает изображение с различными опциями, если это необходимо.
Я использую обработку ключ-значение expl3.
Я хотел бы сохранить настройки «ключ-значение» в глобальном списке токенов, чтобы я мог повторно использовать их в качестве значений по умолчанию при следующем выполнении команды. Я не смог найти очевидный способ сделать это, так как я не хочу делать макросы, параметры которых задаются как глобальные, поскольку это усложнит ситуацию различными способами. Все, что я хочу, это сохранить соответствующие значения «ключ-значение» в глобальном списке токенов, чтобы я мог повторно использовать их. (Мне все равно, если это не список токенов — это просто показалось очевидным выбором.)
Я могу сохранять логические значения и списки, разделенные запятыми, как мне кажется, но у меня возникли проблемы со списками токенов, которые сами по себе являются списками параметров «ключ-значение». Например, graphics={<key-value options>}
используется для передачи настроек в \includegraphics
. Однако я не могу заставить это работать.
Вот (сравнительно) минимальный пример, который делает совершенно неочевидным, почему на Венере я пытаюсь это сделать, но это и есть миниатюризация.
\documentclass{article}
\usepackage{xparse,graphicx}
\begin{document}
\ExplSyntaxOn
\tl_new:N \l_pre_graphics_tl
\tl_new:N \g_pre_img_options_tl
\tl_new:N \g_pre_img_tl
\cs_new_protected_nopar:Nn \pre_key_tl_save:Nn
{
\tl_if_empty:cF {l_pre_#2_tl}
{
\tl_gput_right:No #1 { #2 = }
\tl_gput_right:NV #1 \c_left_brace_str
\tl_gput_right:Nv #1 { l_pre_#2_tl }
\tl_gput_right:NV #1 \c_right_brace_str
\tl_gput_right:Nn #1 { , }
}
}
\cs_generate_variant:Nn \tl_gput_right:Nn {Nv}
% includegraphics bit courtesy of egreg (chat 2015-01-08)
\cs_new:Npn \pre_includegraphics:nn #1 #2
{
\includegraphics[#1]{#2}
}
\cs_generate_variant:Nn \pre_includegraphics:nn { VV }
\keys_define:nn { pre / img }
{
graphics .tl_set:N = \l_pre_graphics_tl,
}
\NewDocumentCommand \incimg { o m }
{
\group_begin:
\tl_if_empty:NF \g_pre_img_options_tl
{
\keys_set:nV { pre / img } \g_pre_img_options_tl
}
\IfValueT{#1}{ \keys_set:nn { pre / img } { #1 } }
\pre_key_tl_save:Nn \g_pre_img_options_tl { graphics }
\tl_set:Nn \g_pre_img_tl { #2 }
\pre_includegraphics:VV \l_pre_graphics_tl \g_pre_img_tl
\group_end:
}
\ExplSyntaxOff
\incimg[
graphics={width=\textwidth},
]{example-image-a}
\incimg[
graphics={width=\textwidth},
]{example-image-a}
\end{document}
В сообщении об ошибке предлагалось обратиться за помощью к человеку, и вот я здесь...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "kernel/misplaced-equals-sign"
!
! Misplaced equals sign in key-value input 194
!
! See the LaTeX3 documentation for further information.
!
! For immediate help type H <return>.
!...............................................
l.194 ]{example-image-a}
? h
|'''''''''''''''''''''''''''''''''''''''''''''''
| LaTeX is attempting to parse some key-value input but found two equals signs
| not separated by a comma.
|...............................................
? h
Sorry, I already gave what help I could...
Maybe you should try asking a human?
An error might have occurred before I noticed any problems.
``If all else fails, read the instructions.''
?
Если я покажу список токенов перед попыткой его использовать, я получу
> \g_pre_img_options_tl=graphics={width=\textwidth },.
что наводит на мысль моему простому уму, что мне нужно как-то включить фигурные скобки вокруг списка. Однако мои попытки сделать это пока не увенчались успехом. Либо LaTeX ищет что-то, что не должно быть ключом (например \g_pre_img_options
), либо скобки просто испаряются.
решение1
Я не совсем понимаю, чего вы пытаетесь добиться, и что бы я ни предполагал, не думаю, что я бы сделал то же самое, но, в любом случае, вот изменение, которое позволяет этому документу скомпилироваться.
\cs_new_protected_nopar:Nn \pre_key_tl_save:Nn
{
\tl_if_empty:cF {l_cfr_#2_tl}
{
\tl_gput_right:No #1 { #2 = }
\tl_gput_right:NV #1 \c_left_brace_str
\tl_gput_right:Nv #1 { l_pre_#2_tl }
\tl_gput_right:NV #1 \c_right_brace_str
\tl_gput_right:Nn #1 { , }
}
}
Это кажется неправильным, даже если я не совсем это понимаю, это, во-первых, чрезмерное усложнение проблемы множеством разных частей, а также тот факт, что вы на самом деле не можете этого сделать (добавление \c_left_brace_str
— это не добавление открывающей группы catcode 1 {
, а catcode «другой», похожее на \string{
). Проще с простым x
аргументом, с правильным \exp_not:*
.
\cs_new_protected_nopar:Nn \pre_key_tl_save:Nn
{
\tl_if_empty:cF {l_cfr_#2_tl}
{
\tl_gput_right:Nx #1 { #2 = { \exp_not:v { l_pre_#2_tl } } , }
}
}
С этим изменением он, по крайней мере, компилируется, но я не знаю, решает ли это все проблемы.
Вы хотите добавить строку и значение макроса в другой макрос. Самый простой способ сделать это — сделать все сразу с аргументом x
. Это буквально делает то, что вы хотели сделать, но правильно. \tl_put_right:Nx
расширяет второй аргумент в \edef
, то есть расширяетвсе, поэтому вам нужно остановиться только в тот момент, когда вы хотите. После подстановки аргументов вы заканчиваете на
\tl_gput_right:Nx \g_pre_img_options_tl { graphics = { \exp_not:v { l_pre_grahpics_tl } } , }
Если вы видели, \edef\foo{graphics={foo}}
то понимаете, каким будет содержимое \foo
: ничего не расширяется, ни буквы, ни «другие» («=»), ни фигурные скобки {
и }
. Так что магия внутри \exp_not:v { l_pre_grahpics_tl }
. Благодаря аргументам expl3, это в точности то же самое, что \exp_not:V \l_pre_grahpics_tl
и , в свою очередь, то же самое, что \exp_not:n { width=\textwidth }
и , просто останавливает расширение там ( \exp_not:n
is \unexpanded
).
Таким образом, строка выше после x
расширения в итоге становится точно такой:
\tl_gput_right:Nn \g_pre_img_options_tl { graphics = { width = \textwidth } , }
Если бы не \unexpanded{width=\textwidth}
TeX, он мог бы попытаться расшириться, \textwidth
как и любой другой макрос, который (сейчас не уверен) мог бы быть расширен, \dimen <number>
и, в общем, мы не хотим, чтобы это расширение произошло.
Извините, но любой желающий может редактировать этот ответ, который далек от идеала.