8

Initial Request

I am in search for a macro that would close all curly brackets and all open environments. Ideally, I could write something of the following sort:

\Open\begin{minipage}\begin{quote}\texttt{
      \textbf{Something
\Close % will close all open environments and curly brackets opened
       % since the most recent \Open

If such a beast can be created, I would map \Open to a thick curly brackets of Unicode and \close to a thick curly brackets, i.e., ❴❵ U+2773 and U+2774.

(Yes, I know some people thought this is an abomination, but then so did people think of curly brackets in BCPL, especially when forced to use a digraph or trigraph for these)

With this macro, one can even remove more LaTeX textual "clutter" by writing

\Open\begin{minipage}\begin{quote}\texttt{
      \textbf{Something
\Close % will close all open environments and curly brackets opened
       % since the most recent \Open

or even

❴\minipage{\quote{\texttt{
      \textbf{Something
❵      % will close all open environments and curly brackets opened
       % since the most recent ❵

(and, yes, I realize that this would drive some LaTeX IDE's crazy)

With \Open opening a context, one could even write:

❴\minipage\quote\texttt{
      \textbf{Something
❵

i.e., removing the opening curly brackets of environments. For macros taking an arguments, the code has to be rewritten as

❴\minipage\quote\ttfamily\bfseries
   Something
❵    

which is not only neat. It is also more IDE friendly. Strangely enough, it would also work with ordinary curly brackets.

Here is another use case, should anyone be interested: Instead of typing

\newcommand\kk[1]{\textcolor{RoyalBlue}{\text{\textup{\textbf{\texttt{#1}}}}}}

and carefully counting the closing parenthesis, we shall have code that is much easier to check visually:

\newcommand\kk[1]❴\textcolor{RoyalBlue}{\text{\textup{\textbf{\texttt{#1❵ 

Analysis

Based on the comment below, I understand that this question calls for up to four components of an answer:

  • A macro to close all pending environment which begun by \begin{env}
  • A macro to close all groups opened since the last drop of an anchor. The term group refers here to the use of { and } for delimiting scope, as in {\em something }
  • A macro to close all pending open argument delimiters. Argument delimiters refer to the use of { and } to collect tokens together, making them one for the purpose of macro application, as in \emph{something}
  • A macro to close all open { in the context of \def, in which it used for delimiting the macro body, but not name, as in \def\EM{\em}

I learn that the fourth is impossible without replacing TeX's lexical analyzer, and I presume that the third is equally difficult. IMHO, the original sin is that TeX overloaded '{' for three distinct purposes: argument passing and for defining scope.

Compare with the classical

main() {
  printf("Hello, World!\n");
}

in which C uses () for function calling and {} for grouping or scoping. The round brackets in C are used for two similar purposes:

  1. **Defining functions* as in main(), which in TeX terms is \def\main{}
  2. Calling functions as in printf("Hello, World!\n");which in TeX could be written as emph{Hello, World!}

So, if messing with the {} for macro calling and definition is so difficult, then I would be very happy with answer that would support the original simple use case

\Open\begin{minipage}\begin{quote}\texttt{
      \textbf{Something
\Close % will close all open environments and curly brackets opened
       % since the most recent \Open

wtth the fist two requests only:

  • A macro to close all pending environment which begun by \begin{env}
  • A macro to close all groups opened since the last drop of an anchor. The term group refers here to the use of { and } for delimiting scope, as in {\em something }

Reflection

Without me intending to do so, the question highlighted the fact that {} are used for three different purposes: grouping, macro definition and macro invocation. In my mind, this overloading is a barrier for beginners who come to LaTeX from the programming world.

Motivation and Context

This question was not asked with the purpose of serving as an intellectual challenge. There is a particular need that a solution should serve.

I am engaged in writing many slides with beamer. By now, I believe I have over a thousand of these. The slides are not too complicated, but they do involve using a lot of environments. A slide with 10 lines or so will contain environments such as

  • \begin{frame} ... \end{frame}
  • \begin{quote} ... \end{quote}
  • \begin{block} ... \end{block}
  • \begin{columns} ... \end{columns}
  • \begin{column} ... \end{column}
  • \begin{definition} ... \end{definition}
  • \begin{uncoverenv} ... \end{uncoverenv}
  • \begin{itemize} ... \end{itemize}
  • \begin{lstlisting} ... \end{lstlisting}
  • \begin{centering} ... \end{centering}

The ratio of macros and environments to actual text is very high with input designed to make presentations. In a count I just did, I found that on overage I use four environments per slide, other than the obvious \begin{frame}.

Opening these environments may create some "clutter", but closing them can be a real pain. It is often the case that you open many environments, all of which end at the end of the frame. Being able to close all these at once, is not for saving typing. In making presentations, typing is the least concern. The majority of work is in experimenting with numerous combinations of the visual layout components to create the desired visual effect. In doing that, it is convenient that the actual layout of the text, including indentation, makes it easy to grasp immediately the current slide design, with minimal need to mentally compile and understand commands and other "clutter" which are required to make the input legal for beamer.

I believe that a macro to close all open environments, and more generally, open groups would be useful.

BTW, the idea is not new. Many years ago, I used to program in Lisp. I remember that it was possible to set an anchor by type '[' and then typing ']' to close all parenthesis opened since the anchor. This was a great help then. These days I do not use Lisp anymore, and I cannot find reference to this ancient trick.

Some Statistical Data

Just to get an initial idea of the potential use of this feature, I measured a presentation I just made, which was not overly complex, and without me being aware that such a macro could be made. I only examined the \end{frame} command.

Overall, there were 43 frames. In 6 of these (14%) the frame ended with a single \end{env}. In 26 frames (60%), there were two \end at the end, and in 11 frames (26%), there were three such commands. Seems as if such a feature would be useful in at least 86% of all frames. And, it is highly unlikely that \Close at the end of frames would lead to many strange errors.

\Open/\Close and the Python Metaphor

It occurred to me that these two macros are similar, but not identical to the way the Python programming language manages bracketing. In Python, indenting a line creates indentation/de-indentation tokens as explained by this quote:

Before the first line of the file is read, a single zero is pushed on the stack; this will never be popped off again. The numbers pushed on the stack will always be strictly increasing from bottom to top. At the beginning of each logical line, the line's indentation level is compared to the top of the stack. If it is equal, nothing happens. If it is larger, it is pushed on the stack, and one INDENT token is generated. If it is smaller, it must be one of the numbers occurring on the stack; all numbers on the stack that are larger are popped off, and for each number popped off a DEDENT token is generated. At the end of the file, a DEDENT token is generated for each number remaining on the stack that is larger than zero.

(Source is here: https://docs.python.org/release/2.5.1/ref/indentation.html)

The nice property of Python is that you do not really need to insert an \Open token. All you do is un-indent to the desired level.

  • 5
    The { after \texttt is not a group delimiter, but an argument delimiter: \texttt{ needs an explicit } to delimit its argument. – egreg Aug 12 '14 at 20:45
  • 8
    Such an innocent looking question :) – percusse Aug 12 '14 at 20:47
  • 1
    It is essentially impossible to make the use case that was just added work, short of parsing the TeX file (doable with TeX itself) before feeding it to TeX. If you are ready to parse TeX, then you could get \newcommand\kk[1]\textcolor{RoyalBlue}\text\textup\textbf\texttt{#1} to work, as long as the code you use to parse knows how many arguments each command expects. – Bruno Le Floch Aug 12 '14 at 21:32
  • I do not think that you need to know the number of arguments. Take a look again at this \newcommand\kk[1]❴\textcolor{RoyalBlue}{\text{\textup{\textbf{\texttt{#1❵. The parser would need to keep a count of unclosed {` , and then inject the same number of } – Yossi Gil Aug 13 '14 at 2:14
  • 1
    One from yours examples {\minipage\quote\ttfamily\bfseries Something} looks like plain TeX code. If you are irritated by many nested LaTeX environments {and more braces than is {explicitly {needed}}} then you can migrate from LaTeX to plain TeX. :) – wipet Aug 13 '14 at 10:18
9

I have said that you are inclined to plain TeX code. But your question seemed me to be interesting. So, I tried to do something despite this is LaTeX problem.

You can start with experimenting with my code:

\newcount\openLnum
\newtoks\currtext
\def\Open{\begingroup\let\bgroup=\relax \let\egroup=\relax 
   \expandafter\checkbracesJ\autobracelist\end 
   \let\ifIamInGroup=\iffalse \currtext={}\checkbracesA
}
\def\checkbracesA{\futurelet\tmp\checkbracesB}
\def\checkbracesB{%
   \let\next=\checkbracesN
   \ifx\tmp\spacetoken \let\next=\checkbracesC \let\nexxt=\checkbracesA \addtocurrtext{ }\fi
   \ifx\tmp\bgroupOri  \let\next=\checkbracesC \let\nexxt=\checkbracesD \fi
   \ifx\tmp\egroupOri  \let\next=\checkbracesC \let\nexxt=\checkbracesE \fi
   \ifx\tmp\autobraced \let\next=\checkbracesH \fi
   \ifx\tmp\Close \let\next=\checkbracesC \let\nexxt=\checkbracesF \fi
   \ifx\tmp\Open  \global\advance\openLnum by1 \let\next=\relax \fi
   \next
}
\def\checkbracesC{\afterassignment\nexxt \let\next= }
\long\def\checkbracesN#1{\addtocurrtext#1\checkbracesA}
\def\checkbracesD{\begingroup \let\ifIamInGroup=\iftrue \currtext={}\checkbracesA}
\def\checkbracesE{\ifIamInGroup \addtocurrtextclosebrace
   \else \currtext\expandafter{\expandafter{\the\currtext}}%
   \fi \checkbracesA
}
\def\checkbracesF{%
   \ifIamInGroup \addtocurrtextclosebrace \expandafter\checkbracesF
   \else \expandafter\checkbracesG \fi
}
\def\checkbracesG{%
   \ifnum\openLnum>0 \global\advance\openLnum by-1 
       \def\next{\expandafter\endgroup \expandafter 
          \currtext \expandafter\expandafter\expandafter
             {\expandafter\the\expandafter\currtext \the\currtext}\checkbracesA}%
   \else \def\next{\expandafter\endgroup \the\currtext}%
   \fi \next
}
\def\checkbracesH#1{\addtocurrtext#1\futurelet\tmp\checkbracesI}
\def\checkbracesI{\ifx\tmp\bgroupOri \expandafter\checkbracesB
                  \else \expandafter\checkbracesD \fi
}
\def\checkbracesJ#1{\ifx#1\end \else \let#1=\autobraced \expandafter\checkbracesJ \fi}

\def\addtocurrtextclosebrace{\expandafter\endgroup
   \expandafter\currtext\expandafter\expandafter\expandafter
      {\expandafter\the\expandafter\currtext\expandafter{\the\currtext}}%
}
\long\def\addtocurrtext#1{\currtext\expandafter{\the\currtext#1}}
\let\bgroupOri=\bgroup
\let\egroupOri=\egroup
\def\tmp/{\let\spacetoken= }\tmp/ %
\def\Close{^\Close^}
\def\autobraced{^\autobraced^}
\def\autobracelist{}

Save it to the file (say) openclose.tex and do the following tests:

\documentclass{article}

\input openclose

\long\def\Minipage#1{\begin{minipage}{\textwidth}#1\end{minipage}}
\long\def\Quote#1{\begin{quote}#1\end{quote}}

\begin{document}

\Open
\Minipage{\Quote{\texttt{\textbf{ 
    Something\Close
% This inserts the closing braces automatically. It means that
%  \Minipage{\Quote{\texttt{\textbf{ Something}}}} is processed.

\def\autobracelist{\Minipage \Quote \texttt \textbf}
\Open
\Minipage\Quote\texttt
      \textbf Something else\Close
% This inserts the opening braces after listed commands and 
% inserts the closing braces automatically. 

\def\autobracelist{}
\Open
\newcommand\kk[1]{\textcolor{RoyalBlue}{\text{\textup{\textbf{\texttt{#1\Close

\message{\meaning\kk}

% This defines the \kk macro as is your desire.

\end{document}

Note that my \Open doesn't insert the starting { immediatelly. This is needed because \Open command works at main TeX processor level. It cannot be inserted between [1] and \textcolor in your \newcommand example.

If you need insert the open brace immediatelly then you can define \def\Openbrace{\expandafter\Open\expandafter{\iffalse}\fi}.

Edit The \Open...\Close pair acts as the autobalancing procedure. If the text between \Open...\Close isn't balanced then the balancing braces are added. Else text si unchanged. You can try:

\Open abc\Close       % no change: ->  abc

\Open a{b}c{d}\Close  % no change: -> a{b}c{d}

\Open a{b{c\Close     % added braces: ->  a{b{c}}

\Open a}b}c\Close     % added braces: -> {{a}b}c

\Open a}b}c{d{e\Close % added braces: -> {{a}b}c{d{e}}

2nd Edit: I've added the support of nested \Open...\Close pairs. First, the inner pairs are processed and then the outer pairs (like normal parenthesis):

\Open text \Open inner1\Close text \Open inner2 \Open inner3\Close text \Close \Close
->
\Open text processed-inner1 text \Open inner2 processed-inner3 text \Close \Close
-> 
\Open text processed-inner1 text processed-(inner2 processed-inner3 text)\Close

Edit Aug.30 New version of openclose.tex: more efficient code and new feature: if the open brace already exists after control sequence listed in \autobracelist then new open brace isn't inserted here.

4

There is another part of the original question: how to map \Open and \Close to the Unicode characters ❴❵ U+2774 and U+2775.

If you are using XeTeX or LuaTeX then you can do:

\catcode`^^^^2774=13 \let^^^^2774=\Open  \catcode`^^^^2775=13 \let^^^^2775=\Close

If you are using pdfTeX with encTeX activated (by -enc option when format was generated) then you can do:

 \mubyte \Open  ^^e2^^9d^^b4\endmubyte  % UTF-8 code for U+2774
 \mubyte \Close ^^e2^^9d^^b5\endmubyte  % UTF-8 code for U+2775
 \mubytein=1 \mubyteout=3 \mubytelog=1

Then you can try:

 \input openclose
 ... setting of the Unicode braces as mentioned above

 ❴abc❵     % -> abc
 ❴a}b}c❵   % -> {{a}b}c
 ❴a{b{c❵   % -> a{b{c}}
 ❴a}b}c❴d}e}f❵gh{i❵  % -> {{a}b}c{{d}e}fgh{i}

 \def\autobracelist{\x\y\z}
 ❴a}bc\x\y uu❵  % -> {a}bc\x{\y{uu}}

If you are using pdfTeX without encTeX activated, then the usage of ❴❵ is more complicated and I will not solve it. The test \ifx\tmp\Close in openclose.tex cannot be such simple in this case.

The limitation of openclose: you cannot do catcode changes between ❴ and ❵ (like \verb, verbatim etc.). This is similar as normal parameter scanning.

3

You have been warned!

I know, many readers will regard this as a comment and not an answer, but the message seems too important to bury it in the digital massgrave of comments below the question:

Such a macro \Close obviously may cause very strange effects, while making it impossible to find the cause.

Beginners who have troubles with missing \end{some env} or missing brackets will simply put this \Close command into their *.tex file and complain afterwards of missing text (forgot to close a minipage e.g.) and whatever. Once such a macro circulates in the web, the genie is out of the bottle.

I will never need nor use such a command, but somebody working towards a deadline and frustrated with error messages may use it and get a horrible PDF, without noticing it.

If I'm wrong, please contradict.

Edit

I voted in an earlier version of this answer for the deletion of this question as interesting as it may be. But fortunately the OP found a question without a real solution.

So: Dear User, please be aware that using the code here probably will not solve your issues with errors, but get you deeper in trouble.

  • 3
    Sorry, I am feel this question only as interesting macro problem. There is no danger that it will become to the common practice. – wipet Aug 13 '14 at 16:17
  • 2
    @wipet There is no doubt you wrote sophisticated code. The question itself is interesting. But once \Close exists, somebody will take it and put it into his new package errorsend.sty and put that on CTAN. You won't have any controll where your code ends up. – Keks Dose Aug 13 '14 at 16:35
  • 3
    If somebody found my code as useful he/she can do everything with it. If he/she get into troubles with this then it is his/her problem. We have freedom. – wipet Aug 13 '14 at 16:48
  • 3
    I disagree that the question should be deleted. On the other hand, a “solution” would require changing the definition of tens of commands, probably disrupting their normal functionality: if one changes \texttt to be “delimited” by \Close, it will be very difficult to use it in the usual way. It's good that (La)TeX doesn't require closing any opened tag, but removing closing tag signals is certainly a call for problems. – egreg Aug 13 '14 at 16:58
  • 4
    Not only deleting this is unnecessary but it is also wrong. It is actually very interesting but in my personal opinion impossible to achieve. However, if somebody is picking up this super esoteric code and tries to apply, deserves all kinds of trouble ahead of them. Typical warning applies to all answers on this site, if you are copy/pasting blindly stuff it is certainly your fault. Additionally, SE licensing comes woth such NO WARRANTY status hence it is also not problematic in that sense. – percusse Aug 13 '14 at 19:59

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.