Как сохранить параметры «ключ-значение», которые включают параметры «ключ-значение» в expl3?

Как сохранить параметры «ключ-значение», которые включают параметры «ключ-значение» в expl3?

У меня есть команда, которая использует синтаксис ключ-значение. Например, она включает изображение с различными опциями, если это необходимо.

Я использую обработку ключ-значение 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:nis \unexpanded).

Таким образом, строка выше после xрасширения в итоге становится точно такой:

\tl_gput_right:Nn \g_pre_img_options_tl { graphics = { width = \textwidth } , }

Если бы не \unexpanded{width=\textwidth}TeX, он мог бы попытаться расшириться, \textwidthкак и любой другой макрос, который (сейчас не уверен) мог бы быть расширен, \dimen <number>и, в общем, мы не хотим, чтобы это расширение произошло.

Извините, но любой желающий может редактировать этот ответ, который далек от идеала.

Связанный контент