0

I would like to automatically define new commands and keyval definitions anytime that a command beginning with the prefix \fn is used within a string.

Part I below is the stub that needs to be changed so that when I input Part II (the input file), PART III is generated with the proper code to route the text of fn-something-text = "the text" to fnSomething as footnote text.

Hopefully that's a clear enough explanation of what I'm after, but the comments in the example doc below are a little more thorough.

\documentclass{article}
\usepackage{keyval}
\begin{document}

% PART I (the part that makes it all happen):
% My main doc should establish a routine to test a string (arg #2) for any
% commands that begin with \fn. This procedure would be in place of `\testmystring` in:

\newcommand{\mycommand}[2]{%
    \testmystring{#2}% look for and generate \fn commands, and generate key defs
    \setkeys{mykeys}{#1}% set the values for those keys
    {#2}% now expand the string
}

% PART II
% This is all that is in my input file, myinput.tex:
\mycommand{%
    fn-foo-text = {This is my foo footnote.}}
}
{This is\fnFoo my new message.}

% PART III (what \testmystring should do)
% When \fn*suffix* is used, the use of `\fn` should trigger/generate the
% following definitions, which will insert *suffix* into the correct spots. 
% In my example, both `Foo` and `Bar` and `BuzBee` are new suffixes.
\makeatletter
\define@key{mykeycollection}{fn-foo-text}{\def\fnfootext{#1}}
\makeatother
\def\fnFoo{\footnote{\fnfootext}}

Hopefully this is possible.

\end{document}

This one is kind of a doozy, so thanks so much for any help! I will follow-up if I come up with any answer(s) as well.


BONUS: I didn't specify this in the doc comments, but the function should also respond to camelcase so that fnBuzBee would send fn-buz-bee-text (and naturally \fnbuzbeetext) to their respective positions in the generated keyval definition. That's not really the main challenge of this question, but it would be nice to implement that in the solution as well.

2
  • Autodefining keys based on a command is possible, but if the command is itself only specified in a key, this is complex on the first glance. And actually, I don't understand what you really want to achieive
    – user31729
    Jun 13, 2016 at 9:53
  • Thanks for the comment - actually, the message is specified in a key as well as its own argument of the command, so the procedure could be applied to the argument of the message (which is just the string). I know it seems redundant to specify the same string twice in one command, but that is because it is being generated by a whole other program which happens to generate both - but that is more or less trivial to this question. I adjusted the example to reflect that. Jun 13, 2016 at 17:55

2 Answers 2

1

Is this what you are looking for?

\documentclass{scrartcl}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand \command { m m }
 {
  \group_begin:
   \keyval_parse:NNn \use_none:n \jshivers_command:nn { #1 }
   #2
  \group_end:
 }

\cs_generate_variant:Nn \seq_set_split:Nnn { NnV }
\cs_new_protected:Npn \jshivers_command:nn #1 #2
 {
  \tl_set:Nn \l_tmpa_tl { #1 }
  \tl_remove_all:Nn \l_tmpa_tl { fn- }
  \tl_remove_all:Nn \l_tmpa_tl { -text }
  \seq_set_split:NnV \l_tmpa_seq { - } \l_tmpa_tl
  \tl_clear:N \l_tmpa_tl
  \seq_map_inline:Nn \l_tmpa_seq
   { \tl_put_right:Nx \l_tmpa_tl { \tl_upper_case:n ##1 } }
  \tl_set:cn { fn \l_tmpa_tl } { #2 }
 }

\ExplSyntaxOff

\begin{document}

\command{
    fn-foo-text = {This is my foo footnote.},
    fn-bar-text = {This is my bar footnote.},
    fn-buz-bee-text = {This is my buzbee footnote.}
}
{This is\fnFoo my\fnBar new\fnBuzBee message.}

\end{document}

With this code, we pass each par fn-foo-bar-text = {This is my foobar footnote.} into a command like \process{fn-foo-bar-text}{This is my foobar footnote.}.

Then from the first argument fn-foo-bar-text we remove fn- leaving only foo-bar-text. Then we remove -text leaving foo-bar.

Then we split what we have left at - leaving two items foo and bar. Then we iterate through them prepending with a command that uppercases what there's in its argument, but, since there are no braces, it uppercases only the first letter: like \MakeUppercase foo will lead to Foo.

So we end with FooBar. and finally we define the macro \fnFooBar to contain the contents of the second argument.

The definition is not global, so you can't use \fnFooBar outside the second argument, i.e., in \command{..=..,..=..}{\fnFooBar}\fnFooBar the second \fnFooBar outside the second argument wouldn't be defined and would raise an error.

4
  • This code is a little over my head (not experienced with explsyntax at all), but it won't actually compile for me anyhow. Would it be easier to generate this stuff from \fn{foo} ? fn-buzbee-text isn't too inelegant either, if that means less complex parsing. Jun 14, 2016 at 1:21
  • Sorry, it had remaining code from another version.
    – Manuel
    Jun 14, 2016 at 9:59
  • Thanks for your work on this answer - it still doesn't really accomplish what I want to do (though that's the fault of my vague/broad question), but it got me to think through the process and almost solve the riddle using some less abstract coding (well, less abstract to me since expl is really beyond my skillset, so I can't extend/alter it at all without screwing it up). If you have a moment to look at my partial solution, I'd definitely appreciate any advice on how to improve it. Jun 15, 2016 at 6:09
  • I don't understand what's wrong with this solution, do you mean that you need, apart from \fnFooBar also \fnfoobartext? That's just a moment.
    – Manuel
    Jun 15, 2016 at 7:11
0

This (almost) answers the whole question. I'm going with FN in this solution as the new trigger instead of \fn. It's less elegant, but works for now.

This document lays out the process that'll take \mymessage, which contains FN..., creates a new command using that name, and replaces the original FN... with that new command; additionally, it generates a new key command with that unique name, which is ultimately put into that new command that is placed into the string (and altogether expanded from the command processedMess).

\documentclass{article}

\usepackage{xstring}
\usepackage{keyval}
\begin{document}

\def\mymessage{My message hasFNsome a new command in it.}% <<< sent from the INPUT file

\StrCut{\mymessage}{FN}\partA\partB% take unique name after "FN"
\StrCut{\partB}{ }\partC\partD% stop at the first space

% GENERATE THE KEY NAME, using the syntax fn-(uniquename)-text
\makeatletter
\define@key{mykeys}{fn-\partC-text}{\expandafter\def\csname fn\partC text\endcsname{#1}}
\makeatother

% THE VALUE OF THE KEY (this is actually from input.tex as well)
\setkeys{mykeys}{fn-some-text={my type here}}% <<< sent from the INPUT file

\expandafter\def\csname FN\partC\endcsname{\expandarg\footnote{\expandafter\csname fn\partC text\endcsname}}

\edef\expandthis{FN\partC}

\expandarg\def\processedMess{
  \StrSubstitute[0]{\mymessage}{\expandthis}
    {\csname FN\partC\endcsname}
}

Result:
\processedMess

\end{document}

So, the above does what I need it to, so far. Anytime I use FN*anything*, it'll put a new footnote there. This process will be prepended in my code with a counter that first searches for how many times FN is used, so that the process can be applied to more than just the first occurrence. The really fun part will be wrapping all of this into a single command. I'll post the full answer that accomplishes that in a different response. Hopefully this partial answer illuminates something for someone else later down the road though, so I'll leave it as is now!

Also, I should say, \csname is a really significant part of this solution. Particularly on the part of expanding a \command into the name of a new command, as I've done here.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .