Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm currently writing a tutorial for some software, and I'd like to refer to the shortcuts used in this program. These shortcuts should be notable, i.e. displayed in a different color or font style.

Basically what I'm trying to do is create a new command, with only one argument -- a string of words, separated by some delimiter (comma). Each word (or segment, since in this case words would be substrings like Ctrl, Shift, Enter or just S, O) should be displayed in the notable style (let's say \textbf{}), and between each two words there should be a + (or some other symbol) using the regular font style. Note that this isn't necessarily the same delimiter used in the argument (the comma)!

In pseudo code:

\newcommand{\shortcut}[1]{
    For every word in the argument #1:
        - Display in notable font style
        - Add + in regular font style (except for last word)
}

So \shortcut{Ctrl,Shift,Z} should result in \textbf{Ctrl}+\textbf{Shift}+\textbf{Z}.

Any recommendations for packages to use, or can this be done using relatively simple LaTeX?

share|improve this question
add comment

6 Answers 6

up vote 12 down vote accepted

"Old style" method

\makeatletter
\newcommand{\shortcut}[1]{%
  \@tempswafalse
  \@for\next:=#1\do
    {\if@tempswa+\else\@tempswatrue\fi\textbf{\next}}%
}
\makeatother

Then \shortcut{Ctrl,Shift,Z} will do what you want.

"New style" method

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\shortcut}{O{,}m}
 {
  \ailurus_make:nn {#1} {#2}
 }

\cs_new_protected:Npn \ailurus_make:nn #1 #2
 {
  \seq_set_split:Nnn \l_ailurus_args_seq { #1 } { #2 }
  \seq_pop_left:NN \l_ailurus_args_seq \l_ailurus_temp_tl
  \textbf { \l_ailurus_temp_tl }
  \seq_map_inline:Nn \l_ailurus_args_seq { + \textbf { ##1 } }
 }

\seq_new:N \l_ailurus_args_seq
\tl_new:N \l_ailurus_temp_tl
\ExplSyntaxOff

\begin{document}
\shortcut{Ctrl,Shift,Z}

\shortcut[/]{Ctrl/,}
\end{document}

It seems more complicated, but it's really very similar. The input is split at the commas and then a cycle is performed. The first element is popped off and treated specially (not very much, actually, in this case).

Bonus With this solution you can easily print a comma, by choosing a different delimiter as optional argument. Of course also

\shortcut{Ctrl,{,}}

would have worked, but this strategy can be used also in more difficult cases.

share|improve this answer
    
Thanks! The first (why is this called the 'old' one by the way) solution is indeed easier to read/understand. I take it the @tempswa flag is just a predefined boolean flag? And @tempswatrue and @tempswafalse set the value to respectively true and false? –  Ailurus Jun 14 '12 at 21:50
    
The 'new style' looks interesting too, never saw this used before (but then again I'm clearly not that experienced writing my own commands). –  Ailurus Jun 14 '12 at 21:51
1  
@Ailurus \if@tempswa is a "scratch conditional" defined by the LaTeX kernel for tasks like this, where its value (true or false) is needed for a short job; one should always set it to true or false before starting the job, as its value can be any. –  egreg Jun 14 '12 at 22:04
    
One other comment: when using the 'old style' method, an additional space is added after the shortcut. This doesn't happen when I rewrite the \newcommand{} without linebreaks. Apparently I have to add a % after the if statement in your code, but why? –  Ailurus Jun 14 '12 at 22:25
    
@Ailurus Yes, sorry, a % was missing. The end of line became part of the definition (and is converted to a space), so it was added at each call of the macro. The "new style" method doesn't suffer of this problem because all spaces and end-of-lines are ignored between \ExplSyntaxOn and \ExplSyntaxOff. –  egreg Jun 14 '12 at 22:30
add comment
\documentclass{article}

\makeatletter

\def\shortcut#1{{\def\scsep{\def\scsep{+}}\@for\w:=#1\do{\scsep\textbf{\w}}}}
\makeatother

\begin{document}

\shortcut{Ctrl,Shift,Z} 

\end{document}
share|improve this answer
    
Very concise, thanks! But how does the \def\scsep{} part work? I don't understand why the + isn't printed the first time. –  Ailurus Jun 14 '12 at 21:43
2  
The first time \scsep doesn't print anything it just defines \scsep to print. It's a trick way of avoiding a + on the first time. If you look in the current associated forum you'll see @egreg scurrilously commenting it's not the first time I've used that idiom on this site:-) –  David Carlisle Jun 14 '12 at 21:53
add comment

Almost any list-processing package would be able to help here, including LaTeX3's list processing constructs. Here's one using etoolbox:

enter image description here

\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\makeatletter
\newcommand{\shortcut}[1]{%
  \begingroup%
  % count the elements
  \@tempcnta=\z@
  \renewcommand*\do[1]{\advance\@tempcnta\@ne}%
  \docsvlist{#1}%
  \chardef\@listsize\@tempcnta%
  \@tempcnta=\@ne%
  \renewcommand*\do[1]{%
    \ifnum\@tempcnta<\@listsize
      \texttt{##1}+\penalty\z@ \advance\@tempcnta\@ne%
    \else
      \unpenalty\texttt{##1}%
    \fi}%
  \docsvlist{#1}%
  \endgroup%
}
\makeatother
\begin{document}
You can use \shortcut{Ctrl,Shift,Z} or \shortcut{2,2,1,2,Alt,X} and on occasion \shortcut{Ctrl,Alt,Del}.
\end{document}​

Taken from Special formatting of a mathmode list. The introduction of a zero \penalty allows for breaking at the text block boundary if your sequence is long.

share|improve this answer
    
Nice touch with the \penalty part. And thanks for suggesting \texttt{} instead of \textbf! –  Ailurus Jun 14 '12 at 21:53
add comment

You can use a \foreach loop from the pgffor package, which is pare of the pgf package:

enter image description here

Notes:

Code:

\documentclass{article}
\usepackage{etoolbox}
\usepackage{pgffor}

\newtoggle{FirstShortcut}
\newcommand*{\shortcut}[1]{%
    \global\toggletrue{FirstShortcut}%
    \foreach \member in {#1} {%
        \iftoggle{FirstShortcut}{}{+}%
        \textbf{\member}%
        \global\togglefalse{FirstShortcut}%
    }%
}%

\begin{document}
    \shortcut{Ctrl,Shift,Z}
\end{document}
share|improve this answer
add comment

... and a really short one, using only one 'special' macro :) (requires xstring):

\documentclass[10pt,a4paper]{article}

\usepackage{xstring}

\newcommand{\specialtext}[1]{%
    \StrSubstitute{#1}{,}{ + }[\myspecialtext]
    \textbf{\myspecialtext}}

\begin{document}
This is a \specialtext{very,special} command.
\end{document}

enter image description here

EDIT: As @PeterGrill pointed out, this will produce a bold face +. To avoid this, as the request of the OP was (in case this is necessary), the code should be modified like this, without sacrificing any comfort:

\newcommand{\specialtext}[1]{%
    \noexpandarg    
    \StrSubstitute{#1}{,}{ \textnormal{+} }[\myspecialtext]
    \textbf{\myspecialtext}}
share|improve this answer
    
But I think the original requirement (which may or many not be significant) was that the \textbf is applied only to the text and not the +. –  Peter Grill Jun 15 '12 at 21:28
1  
@PeterGrill One can cheat and write ${}+{}$ instead of <space>+<space>. –  egreg Jun 15 '12 at 22:02
    
@egreg: I added another 'cheat code', but I like yours too. :) –  Count Zero Jun 15 '12 at 22:07
    
@egreg: Very clever cheat, although I like CountZero's cheat as it is less magical. –  Peter Grill Jun 15 '12 at 22:25
add comment

Another one, using lambda-lists:

\documentclass{article}
\usepackage{lambda} % http://www.ctan.org/pkg/lambda-lists
\makeatletter
\def\Unlistize#1{#1\Unlistize@{}}
\def\Unlistize@#1{#1\Foldr\Plusize{}}
\makeatother
\def\Plusize#1#2{+#1#2}
\def\shortcut#1{\Show\Map\textbf[#1]}

\begin{document}

\shortcut{Ctrl,Alt,Del}
\shortcut{Ctrl,Shift,Z}

\end{document}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.