4

While writing software documentation, the need arose for a command that automatically hyphenates camelCase words at uppercase letters, e.g. camel-Case. Furthermore, these camelCase words are typeset to a certain color. The solution was provided here via a command \zzz{camelCase}.

However, some of the camelCase variables are documented for internal use only. To this end there is a flag defined as

\newboolean{\internal}
\setboolean{internal}{true}

in a config file. For example if a whole paragraph is for internal use only, one can write

\ifthenelse{\boolean{internal}}{%
    Here is a paragraph which will only appear when the \textbackslash internal flag is set to TRUE.%
}{}%

But this is not a practical implementation for all internal camelCase variables. It would be a pain to write and even worse for source code readability. It would be far better to define a command that contains the functionality of \zzz but also reacts to the internal flag. More precisely, the desired behaviour of a new command \zzzconditional{camelCase} would be:

  • iternal flag TRUE: input argument camelCase is hyphenated at capitals and formatted according definition in \zzz{camelCase}
  • internal flag FALSE: input argument camelCase disappears entirely from final document. Bonus points if preceding space is removed so that missing camelCases do not leave blanks in document.

So I tried the following:

\newcommand{\zzzconditional}[1]{%
    \ifthenelse{\boolean{internal}}{%
        \zzz{#1}%
    }{}%
}

I can now switch internal variables on and off in the document by writing them as \zzzconditional{camelCase}. But this breaks the hyphenation functionality of the \zzz command and causes overfull lines - i.e. I'm back to where I started before I had \zzz.

Is there any way of "expanding" my command \zzzconditional so that \zzz on the inside works? I hope "expanding" is the right term in latex slang. Bonus points for a solution that also removes the preceding space along with the camelCase variable in my text.

If a solution would be too painstaking to implement please let me know as I do not wish to impose. I have a Plan B: scanning my latex source with Python for the use of \zzz{} and removing the relevant source code. However, non-Pythonistas will also have to work with this document so native latex solutions are preferable.

I have modified the MWE from the previous solution to provide an example of all mentioned commands:

\documentclass{scrartcl}
\usepackage{xcolor}
\usepackage{ifthen}
\showhyphens{createUnspecifiedNodeErrorMarker}
\def\zzcolor{\color{red}}

% --------------------------------------------
% Definition of \zzz
% --------------------------------------------
\makeatletter
\def\zzz{\leavevmode\begingroup
    \def\zzelt##1{%
        \catcode`##1\active\uccode`\~`##1\uppercase{%
            \def~{\egroup\egroup\-\hbox\bgroup\bgroup\zzcolor\string##1}}}%
    \zz@Alph{}%
    \@zzz}

\def\zz@Alph#1{%
    \zzelt A\zzelt B\zzelt C\zzelt D\zzelt E\zzelt F\zzelt G\zzelt H\zzelt I\zzelt J\zzelt
    K\zzelt L\zzelt M\zzelt N\zzelt O\zzelt P\zzelt Q\zzelt R\zzelt S\zzelt T\zzelt U\zzelt V\zzelt W\zzelt X\zzelt
    Y\zzelt Z}

\def\@zzz#1{\textbf{\hbox\bgroup\bgroup\zzcolor#1\egroup\egroup}\endgroup}
\makeatother

% --------------------------------------------
% Flag to set internal version of document
% --------------------------------------------
\newboolean{internal}
\setboolean{internal}{true}

% --------------------------------------------
% Definition of \zzzconditional which should work like \zzz, but only print to document if interal flag is TRUE
% --------------------------------------------
\newcommand{\zzzconditional}[1]{%
    \ifthenelse{\boolean{internal}}{%
        \zzz{#1}%
    }{}%
}

\begin{document}
    \section{Test}

    Here is an example of how \textbackslash zzz\{\} hyphenates camelCase words. This may also create overfull lines, but I can live with the result because the overflow is minimal and variables in the real document have more capitals than the one in this MWE:

    And another example the show must go on, but we have too less text (\zzz{createUnspecifiedNodeWarningMarker} and
    \zzz{createUnspecifiedNodeErrorMarker}, sdjklashjksa \zzz{createUnspecifiedLinkWarningMarker} and
    \zzz{createUnspecifiedLinkErrorMarker}).

    \ifthenelse{\boolean{internal}}{%
        Here is a paragraph which will only appear when the \textbackslash internal flag is set to TRUE. This is very helpful if I only want it to appear in the internal version of this example document. The next paragraph is visible in source code only because I change internal flag's value to FALSE.%
    }{}%

    \setboolean{internal}{false}
    \ifthenelse{\boolean{internal}}{%
        Now the internal flag has been set to FALSE which makes this paragraph disappear. This is very helpful if I only want it to appear in the internal version of this example document.%
    }{}%

    \setboolean{internal}{true}

    Here is an example of an overfull line because wrapping \textbackslash zzz\{\} inside \textbackslash zzzconditional\{\} does not work properly, as illustrated by this very long variable \zzzconditional{createUnspecifiedNodeWarningMarker}.
\end{document}

enter image description here

1

EDITED Based on the clarification of how the OP wanted \zzzconditional to behave when internal is false. The second and third to last paragraphs of this MWE show the results when internal is true and false, respectively.

EDIT by Jay_At_Play (OP): included bugfix by Steven for \zzzconditional at beginning of paragraph (see comments below for details). Helper function \removetheargument now also calls \leavevmode. The last paragraph of this MWE shows result when internal is FALSE with \zzzconditional at beginning of paragraph.

Here I [re]define

\newcommand{\zzzconditional}{%
    \ifthenelse{\boolean{internal}}{\zzz}{\removetheargument}%
}
\newcommand\removetheargument[1]{\leavevmode\unskip}

such that \zzzconditional is called without an argument and either redirects towards \zzz or towards something that removes the argument (and \unskips), depending on the boolean status of internal.

\documentclass{scrartcl}
\usepackage{xcolor}
\usepackage{ifthen}
\showhyphens{createUnspecifiedNodeErrorMarker}
\def\zzcolor{\color{red}}

% --------------------------------------------
% Definition of \zzz
% --------------------------------------------
\makeatletter
\def\zzz{\leavevmode\begingroup
    \def\zzelt##1{%
        \catcode`##1\active\uccode`\~`##1\uppercase{%
            \def~{\egroup\egroup\-\hbox\bgroup\bgroup\zzcolor\string##1}}}%
    \zz@Alph{}%
    \@zzz}

\def\zz@Alph#1{%
    \zzelt A\zzelt B\zzelt C\zzelt D\zzelt E\zzelt F\zzelt G\zzelt H\zzelt I\zzelt J\zzelt
    K\zzelt L\zzelt M\zzelt N\zzelt O\zzelt P\zzelt Q\zzelt R\zzelt S\zzelt T\zzelt U\zzelt V\zzelt W\zzelt X\zzelt
    Y\zzelt Z}

\def\@zzz#1{\textbf{\hbox\bgroup\bgroup\zzcolor#1\egroup\egroup}\endgroup}
\makeatother

% --------------------------------------------
% Flag to set internal version of document
% --------------------------------------------
\newboolean{internal}
\setboolean{internal}{true}

% --------------------------------------------
% Definition of \zzzconditional which should work like \zzz, but only print to document if interal flag is TRUE
% --------------------------------------------
\newcommand{\zzzconditional}{%
    \ifthenelse{\boolean{internal}}{\zzz}{\removetheargument}%
}
\newcommand\removetheargument[1]{\leavevmode\unskip}

\begin{document}
    \section{Test}

    Here is an example of how \textbackslash zzz\{\} hyphenates camelCase words. This may also create overfull lines, but I can live with the result because the overflow is minimal and variables in the real document have more capitals than the one in this MWE:

    And another example the show must go on, but we have too less text (\zzz{createUnspecifiedNodeWarningMarker} and
    \zzz{createUnspecifiedNodeErrorMarker}, sdjklashjksa \zzz{createUnspecifiedLinkWarningMarker} and
    \zzz{createUnspecifiedLinkErrorMarker}).

    \ifthenelse{\boolean{internal}}{%
        Here is a paragraph which will only appear when the \textbackslash internal flag is set to TRUE. This is very helpful if I only want it to appear in the internal version of this example document. The next paragraph is visible in source code only because I change internal flag's value to FALSE.%
    }{}%

    \setboolean{internal}{false}
    \ifthenelse{\boolean{internal}}{%
        Now the internal flag has been set to FALSE which makes this paragraph disappear. This is very helpful if I only want it to appear in the internal version of this example document.%
    }{}%

    \setboolean{internal}{true}

    Here is an example of an overfull line because wrapping \textbackslash zzz\{\} inside \textbackslash zzzconditional\{\} does not work properly, as illustrated by this very long variable \zzzconditional{createUnspecifiedNodeWarningMarker}.

    \setboolean{internal}{false}

    Here is an example of an overfull line because wrapping \textbackslash zzz\{\} inside \textbackslash zzzconditional\{\} does not work properly, as illustrated by this very long variable \zzzconditional{createUnspecifiedNodeWarningMarker}.
\end{document}

enter image description here

  • thanks a lot for your suggestion and your input regarding my post Steven. Desired behaviour has now been clarified in my post. I tried to experiment with \expandafter but could not get a version of \zzzconditional{camelCase} that removes input argument if internal flag is FALSE. Do you have any ideas? – Jay_At_Play Apr 5 '18 at 7:08
  • @Jay_At_Play No problem. That revision is straightforward. Furthermore, the \expandafter may actually be unnecessary (it is in this particular example and I am not full cognizant of how \ifthenelse handles its two cases). – Steven B. Segletes Apr 5 '18 at 9:51
  • @Jay_At_Play Best I can see, the \expandafter is not needed, so I will remove it from my answer. – Steven B. Segletes Apr 5 '18 at 10:01
  • 1
    @Jay_At_Play ...or you could change it to \leavevmode\unskip. That should work at the beginning of a paragraph. – Steven B. Segletes Apr 5 '18 at 16:36
  • 1
    thanks for the bugfix. I've tested it in my document and the MWE. Works in both cases. Thank you very much! I have edited your post, including the MWE, accordingly. Edit will be visible to everyone once it has passed peer review. – Jay_At_Play Apr 11 '18 at 8:36
1

I'm not sure I understand fully your requirement, but here's how I came up with.

\documentclass{article}
\usepackage{xcolor}
\usepackage{microtype}
\usepackage{xparse,environ}


\ExplSyntaxOn
\NewDocumentCommand{\keyw}{O{.}m}
 {
  \bool_if:NTF \l_jayatplay_internal_bool
   { \unskip }
   { \textcolor{#1}{ \bfseries \jayatplay_keyw:n { #2 } } }
 }

\NewEnviron{internal}
 {
  \bool_if:NF \l_jayatplay_internal_bool { \BODY }
 }

\NewDocumentCommand{\setinternal}{O{true}}
 {
  \use:c { bool_set_#1:N } \l_jayatplay_internal_bool
 }

\bool_new:N \l_jayatplay_internal_bool

\cs_new_protected:Nn \jayatplay_keyw:n
 {
  \tl_map_inline:nn { #1 }
   {
    % if the current char is uppercase, add a discretionary hyphen
    \str_if_eq_x:nnT { ##1 } { \str_upper_case:n { ##1 } } 
     { \- }
    ##1
   }
 }
\ExplSyntaxOff

\begin{document}

\section{Test}

And another example the show must go on, but we have too less 
text (\keyw{createUnspecifiedNodeWarningMarker} sdjkle
\keyw{createUnspecifiedNodeErrorMarker}, sdjklashjksa 
\keyw{createUnspecifiedLinkWarningMarker} and
\keyw[red]{createUnspecifiedLinkErrorMarker}).

\section{Another test}

Here is an example of how \verb|\keyw{}| hyphenates camelCase words. 
This may also create overfull lines, but I can live with the result 
because the overflow is minimal and variables in the real document 
have more capitals than the one in this MWE:

And another example the show must go on, but we have too less text 
(\keyw{createUnspecifiedNodeWarningMarker} and \keyw{createUnspecifiedNodeErrorMarker}, 
sdjklashjksa \keyw{createUnspecifiedLinkWarningMarker} and \keyw{createUnspecifiedLinkErrorMarker}).

% the boolean starts out false, so this will appear
\begin{internal}
Here is a paragraph which will only appear when the \texttt{internal} flag is set to TRUE. 
This is very helpful if I only want it to appear in the internal version of this example 
document. The next paragraph is visible in source code only because I change internal 
flag's value to FALSE.
\end{internal}

% set the boolean to true
\setinternal

% this will not appear
\begin{internal}
Now the internal flag has been set to FALSE which makes this paragraph disappear.
This is very helpful if I only want it to appear in the internal version of this
example document.
\end{internal}

\setinternal[false]

Here is an example of an overfull line because wrapping \verb|keyw{}| inside 
\verb|\keyw{}| does not work properly, as illustrated by this very 
long variable \keyw{createUnspecifiedNodeWarningMarker}.


\setinternal

Here is an example of an overfull line because wrapping \verb|keyw{}| inside 
\verb|\keyw{}| does not work properly, as illustrated by this very 
long variable \keyw{createUnspecifiedNodeWarningMarker}.


\end{document}

enter image description here

  • thanks a lot for your answer, but I'm going with Steven's answer simply because it is only a minor alteration of existing code. – Jay_At_Play Apr 5 '18 at 12:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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