6

I declared a new command to format list elements in LaTeX as follows:

\newcommand{\sitem}[1]{\item \makefirstuc{#1},}
\newcommand{\eitem}[1]{\item \makefirstuc{#1}.}

This works OK, but now I have to brace every list element as follows:

\begin{itemize}
    \sitem{First item}
    \eitem{second item}
\end{itemize}

How do I get it so that the following is possible?

\begin{itemize}
    \sitem First item
    \eitem second item
\end{itemize}
10
  • It is probably only possible if you leave a blank linie after each item, then you can grap up until the next \par token. But I'd say that \sitem{....} is easier to work with, especially when you later on want something slightly different.
    – daleif
    Apr 19 at 8:10
  • @daleif I itemize a lot in my documents, and the itemize environment is already quite verbose. Adding the new commands in the way I have done would hinder my workflow, so I really would like to find a way to do it without the braces. How is \item itself implemented?
    – user32882
    Apr 19 at 8:13
  • Are you willing and able to work with a LuaLaTeX-based approach?
    – Mico
    Apr 19 at 8:18
  • 1
    @Mico lua is fine, yes.
    – user32882
    Apr 19 at 8:19
  • 1
    @Mico There's a package on CTAN called \mfirstuc which loads it in. It basically capitalizes the first letter of the item.
    – user32882
    Apr 19 at 8:33

3 Answers 3

6

Here's a LuaLaTeX-based solution. It sets up a Lua function, called process_items, which acts as a preprocessor: By the time TeX gets to process the input lines in question, it will not "see" \sitem first item but, instead, \item First item,. (Note the uppercasing of the first letter and the terminal comma.) The Lua function is activated and deactivated, respectively, by the LaTeX utility macros \ItemOn and \ItemOff.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article} % or some other suitable document class
\usepackage{mfirstuc}   % for '\makefirstuc' macro

\usepackage{luacode}    % for 'luacode' environment
\begin{luacode}
function process_items ( s )
  s = string.gsub ( s , '\\sitem%s+(.+)' , '\\item\\makefirstuc{%1},' )
  s = string.gsub ( s , '\\eitem%s+(.+)' , '\\item\\makefirstuc{%1}.' )
  return s
end
\end{luacode}

\newcommand\ItemOn{\directlua{luatexbase.add_to_callback ( 
  "process_input_buffer", process_items , "ProcessItems" )}}
\newcommand\ItemOff{\directlua{luatexbase.remove_from_callback ( 
  "process_input_buffer", "ProcessItems" )}}
  
\begin{document}
\ItemOn %% assign the Lua function to the input processor callback

\begin{itemize}
    \sitem first item
    \sitem  second item
    \eitem   third item 
\end{itemize}
\end{document}
7
  • 1
    It works. I don't fully understand how but the more I use it the more it'll sink in I guess. Why are you not using ItemOff in this example?
    – user32882
    Apr 19 at 13:19
  • 1
    @user32882 - I guess I created \ItemOff mainly as counterpart to the much more important \ItemOn macro. The code works because the Lua function is assigned to LuaTeX's process_input_buffer callback, meaning that it acts as a prepocessor and modifies matching patterns. By the time LaTeX gets to do its job, it never gets to "see" \sitem and \eitem. While \sitem and \eitem look like they might be LaTeX macros, that's not the case. Instead, their role is to serve as "markers" for pattern matching by Lua's powerful built-in string.gsub ("generalized substitution") function.
    – Mico
    Apr 19 at 14:09
  • 1
    I'm afraid this breaks for multiple lines after the \sitem and \eitem. Any good ideas on how I can remedy that?
    – user32882
    Apr 19 at 14:41
  • 2
    @user32882 --- You asked for something that takes the rest of your line as an argument. If you want to allow multiple lines then TeX could only detect the end of the argument at the next instance of \sitem/\eitem or the \end{itemize}. Then you would have all sorts of fun and games with spaces between the argument and the full stop or comma. I suspect this is more trouble than it's worth. Apr 19 at 15:02
  • 1
    @Mico I understand. I made another question: tex.stackexchange.com/questions/641312/…
    – user32882
    Apr 19 at 15:06
4

If you don't plan to use nested lists in this case, you can implement the job in expl3.

Split the input at \item and massage the resulting sequence so that uppercasing of the first letter is performed. Then the whole lot is delivered adding ,\item in between items and a final period.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentEnvironment{adjitemize}{+b}
 {
  \adjitemize_main:n { #1 }
 }
 {}

\seq_new:N \l__adjitemize_in_seq
\seq_new:N \l__adjitemize_out_seq

\cs_new_protected:Nn \adjitemize_main:n
 {
  % split the body at \item
  \seq_set_split:Nnn \l__adjitemize_in_seq { \item } { #1 }
  % discard the first item, which is empty
  \seq_pop_left:NN \l__adjitemize_in_seq \l_tmpa_seq
  % add the capitalization of the first letter
  \seq_set_map_x:NNn \l__adjitemize_out_seq \l__adjitemize_in_seq
   {
    \text_titlecase:n { ##1 }
   }
  % deliver the result
  \begin{itemize}
  \item \seq_use:Nn \l__adjitemize_out_seq { , \item } .
  \end{itemize}
 }

\ExplSyntaxOff

\begin{document}

\begin{adjitemize}
\item first item
      with a second line
\item second item
\item final item
\end{adjitemize}

\end{document}

I believe that using \item is much simpler than \sitem and \eitem, because you can move around the items without worrying about which one is last. The only thing to remember is to use adjitemize instead of itemize, but this is justified by the fact that you want to massage the items.

enter image description here

3
  • This is a valid answer to my other question. If you copy/paste it there I will accept it.
    – user32882
    Apr 20 at 6:42
  • @user32882 you should remove the other question, instead
    – egreg
    Apr 20 at 7:47
  • Sure, I can delete it. But I'm keeping @Mico's answer for this question here. Your answer is also technically valid, and good reference for the future, but I still need to brush up my expl3 skills :)
    – user32882
    Apr 20 at 7:53
3

You can borrow the \eoldef macro from OpTeX. Syntax:

\eoldef\macro #1{body of the macro, #1 can be used}

The \macro is defined with its parameter separated by the end of line.

In your LaTeX document it can look like this:

\documentclass{article}

\def\eoldef #1{\def #1{\begingroup \catcode`\^^M=12 \eoldefA #1}%
   \expandafter\def\csname \string #1:M\endcsname}
{\catcode`\^^M=12 %
\gdef\eoldefA #1#2^^M{\endgroup\csname \string #1:M\endcsname{#2}}%
}

\def\firstupper#1{\uppercase{#1}}

\eoldef\sitem#1{\item \firstupper #1,}
\eoldef\eitem#1{\item \firstupper #1.}

\begin{document}

\begin{itemize}
    \sitem First item
    \eitem second item
\end{itemize}

\end{document}

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.