Редактировать 1

Редактировать 1

Я пытаюсь создать некоторую шаблонную инфраструктуру, которая сильно зависит от стилей pgfkeys, чтобы легко настраивать внешний вид того, как некоторые фрагменты текста набираются в моем документе. Однако я столкнулся с некоторой проблемой при попытке добавить больше пар ключ-значение к стилю, который, как его работа, уже определил больше кодов или стилей.

Следующий пример иллюстрирует проблему, о которой я говорю:

\documentclass{minimal}
\usepackage{pgfkeys}
\begin{document}

\pgfkeys{
  /my package/.cd,
  fancy/.style = {
    format/.code = \textbf{##1},
  },
  fancy,
  format=hello, % typesets `hello' in boldface
  fancy/.append style = { },
  fancy,
  format=hello, % nothing is typeset
%  format/.show code, % uncomment to see the definition of format
}

\end{document}

Раскомментирование последней строки в \pgfkeysкоманде показывает, что после попытки добавления к fancyстилю код в formatключе был заменен на:

\textbf {\pgfkeysnovalue }

и поэтому на втором листе ничего не набрано format=hello.

Я (вроде) понимаю, почему это происходит. По той же причине, по которой мне пришлось писать ##1при определении кода в стиле. Однако есть ли исправление или обходной путь, чтобы сделать стиль достаточно «надёжным», чтобы к нему можно было что-то добавлять, не нарушая его?


Редактировать 1

Благодаря комментарию Джозефа Райта и попытке ответа от percusse я понял, что на более низком уровне проблема, которую нужно решить, заключается в следующем: имея уже определенный макрос, который принимает один аргумент (теперь это коды/стили в pgfkeys, которые определены внутри), исправить заменяющий текст макроса, добавив еще немного текста.

Теперь, изetoolbox , оттудаявляетсямакрос для выполнения именно этого: \apptocmd. Ниже приведен пример того, как, вероятно, должно выглядеть решение с использованием этого макроса:

\documentclass{minimal}
\usepackage{etoolbox}
\tracingpatches
\begin{document}
\ttfamily
\def\fancy#1\pgfeov{\pgfkeysalso{format/.code=\textbf{##1}}}
\meaning\fancy\par
\apptocmd\fancy{\pgfkeysalso{color=red}}{Ok!}{Fail.}\par
\meaning\fancy\par
\apptocmd\fancy{\pgfkeysalso{format/.code=\textit{##1}}}{Ok!}{Fail.}\par
\meaning\fancy\par
\end{document}

Единственная проблема в том, что вторая попытка исправления не срабатывает, и etoolbox показывает следующее в качестве отладочной информации:

[debug] tracing \apptocmd on input line 10
[debug] analyzing '\fancy'
[debug] ++ control sequence is defined
[debug] ++ control sequence is a macro
[debug] ++ control sequence is a macro with parameters
[debug] -- nested patching command and parameters in patch
[debug] -> the patching command seems to be nested in the
[debug]    argument to some other command
[debug] -> the patch text seems to contain # characters
[debug] -> either avoid nesting or use # characters with
[debug]    category code 12 in the patch text
[debug] -> simply doubling the # characters will not work

Возможно ли сделать \apptocmdтак, чтобы он работал даже с #символами в новом заменяющем тексте?

Отказ от ответственности:Теперь у меня есть обходной путь для моего конкретного случая, который работает только потому, что моим fancyстилям на самом деле не нужно принимать никаких аргументов ( formatделает, но fancyне делает). Поэтому вместо того, чтобы хранить код как стиль, я сохраняю его как обычное простое значение и расширяю .codeдо этого значения. Позже можно использовать простое /.appendисправление «поддельного» стиля.

Тем не менее, я бы очень хотел получить решение исходной проблемы, чтобы можно было также добавлять стили, содержащие как аргументы, так и (назовем их) подаргументы. Я не знаю, однако, возможно ли это технически. Итак, вот мое предложение: если кто-то считает, что общее решение осуществимо, и дает мне знать об этом, просто оставив комментарий,Я готов открыть вознаграждение в размере 300 от моей репутации за рабочее решение общего случая.. Однако, если люди считают, что это слишком сложно или технически невозможно (а я так подозреваю, потому что etoolboxне реализовал это), то я просто удовлетворюсь своим более глупым обходным решением и опубликую полный ответ, расширенный по нему.

решение1

Это похоже на ошибку в pgfkeys. Если вы это сделаете

\pgfkeys{
  /my package/.cd,
  fancy/.style = {
    format/.code = \textbf{##1},
  },
  fancy/.show code,
  fancy/.append style = { },
  fancy/.show code
}

Понимаете

\pgfkeysalso { format/.code = \textbf {##1}, }

в первый раз, но

\pgfkeysalso { format/.code = \textbf {#1}}\pgfkeysalso { }

во второй раз: обратите внимание на потерю #.

Код, который лежит в основе .append style, это

\pgfkeys{/handlers/.add code/.code 2 args=%
  % Find out, whether with args or not.
  \pgfkeysifdefined{\pgfkeyscurrentpath/.@args}%
  {% Yes, so add to body and reuse args
    \pgfkeysaddvalue{\pgfkeyscurrentpath/.@body}{#1}{#2}%
    % Redefine code
    {%
      \pgfkeysgetvalue{\pgfkeyscurrentpath/.@args}{\pgfkeys@tempargs}%
      \pgfkeysgetvalue{\pgfkeyscurrentpath/.@body}{\pgfkeys@tempbody}%
      \def\pgfkeys@marshal{\expandafter\gdef\expandafter\pgfkeys@global@temp\pgfkeys@tempargs}%
      \expandafter\pgfkeys@marshal\expandafter{\pgfkeys@tempbody}%
    }%
    \pgfkeysifdefined{\pgfkeyscurrentpath/.@@body}{%
      % support for \pgfkeysndefargs:
      \pgfkeyslet{\pgfkeyscurrentpath/.@@body}{\pgfkeys@global@temp}%
    }{%
      % support for \pgfkeysdefargs:
      \pgfkeyslet{\pgfkeyscurrentpath/.@cmd}{\pgfkeys@global@temp}%
    }%
  }%
  {%
    % No, so single argument (simple \pgfkeysdef). Redefine accordingly.
    {%
      \toks0{#1}%
      \pgfkeysifdefined{\pgfkeyscurrentpath/.@cmd}%
      {\pgfkeys@temptoks\expandafter\expandafter\expandafter{\csname pgfk@\pgfkeyscurrentpath/.@cmd\endcsname##1\pgfeov}}%
      {\pgfkeys@temptoks{}}%
      \toks1{#2}%
      \xdef\pgfkeys@global@temp{\the\toks0 \the\pgfkeys@temptoks \the\toks1 }%
    }%
    \expandafter\def\expandafter\pgfkeys@temp\expandafter##\expandafter1\expandafter\pgfeov\expandafter{\pgfkeys@global@temp}%
    \pgfkeyslet{\pgfkeyscurrentpath/.@cmd}\pgfkeys@temp%
  }%
}

Проблема в линии, которая приближается к концу.

\expandafter\def\expandafter\pgfkeys@temp\expandafter##\expandafter1\expandafter\pgfeov\expandafter{\pgfkeys@global@temp}%

Поскольку это просто расширяется \pgfkeys@global@temp, TeX расдублирует все, #что он содержит. Вместо этого \edefследует использовать плюс toks:

\toks0\expandafter{\pgfkeys@global@temp}%
\edef\pgfkeys@temp##1\pgfeov{\the\toks0}%

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