How to check proper nesting of heading levels

How can we check that heading levels in a LaTeX file are coming in sequence, i.e., \section, \subsection, \subsubsection, \paragraph and \subparagraph. How to catch if \section is followed by \subsubsection or \subsection is followed by \paragraph etc.

-

An "abstract" version of zeroth's solution:

\makeatletter
\def\set@schk#1#2{%
\expandafter\let\csname schk@#1\expandafter\endcsname
\csname #1\endcsname
\@namedef{schk@#1@level}{#2}%
\@namedef{#1}{\schk@check{#1}\csname schk@#1\endcsname}%
}
\set@schk{section}{1}
\set@schk{subsection}{2}
\set@schk{subsubsection}{3}
\set@schk{paragraph}{4}
\set@schk{subparagraph}{5}

\def\schk@check#1{%
\ifnum\numexpr\csname schk@#1@level\endcsname-\schk@current\relax>\@ne
\par You can't put \texttt{\expandafter\string\csname #1\endcsname} here\par
\fi
\xdef\schk@current{\csname schk@#1@level\endcsname}%
}
\def\schk@current{0}
\makeatother


We add in front of each sectioning command a check that the level difference is not greater than one followed by setting the current level.

-

You can do it by a hackish way. I do not know of any packages that might do this. And it can probably break by certain packages. Although it should be somewhat robust against other packages.

What I have done is to check for typesetting rules. I have added a lot of unnecessary \if's to exemplify. The same pattern of implementation can be done for \part, \chapter ... whatever command you might wish.

Basically it will keep track of what is allowed to be typeset. There should be one \if to each section, subsection, etc. and then you redefine the section to check against this. If it is allowed to typeset it will proceed and update what is allowed to follow, this can be made arbitrarily and rather straightforward.

\documentclass{article}
\begin{document}
\makeatletter
% Always allow to step back and go one forth
% Create If variables for each sectioning
\newif\iftest@section
\newif\iftest@ssection
\newif\iftest@sssection
% Initialize to correct values
\test@sectiontrue
\test@ssectiontrue
\test@sssectionfalse
% Save old definition of sections, that are going to be incorporated
\let\osection\section
\let\ossection\subsection
\let\osssection\subsubsection
% Redefine section
\def\section{%
\iftest@section % We are allowed to typeset a section, proceed
% Initialize what is allowed to be typeset after a section
\test@sectiontrue
\test@ssectiontrue
\test@sssectionfalse
% Expandafter to circumvent grabbing of \else
\expandafter\osection
\else
% If not applicable for typesetting write out an error message
% You could add a \warning here (but then it wont compile)
ERROR you are not allowed to add a section now!
% Eat the argument of the section, easily expanded to also gobble the
% [] argument
\expandafter\@gobble
\fi
}
% Do same handling for the subsection
\def\subsection{%
\iftest@ssection
\test@sectiontrue
\test@ssectiontrue
\test@sssectiontrue
\expandafter\ossection
\else
ERROR you are not allowed to add a subsection now!
\expandafter\@gobble
\fi
}

\def\subsubsection{%
\iftest@sssection
\test@sectiontrue
\test@ssectiontrue
\test@sssectiontrue
\expandafter\osssection
\else
ERROR you are not allowed to add a subsubsection now!
\expandafter\@gobble
\fi
}
\makeatother

\section{A}

\subsection{A.1}
\subsection{A.2}
\subsubsection{A.2.1}

\section{B}

\subsubsection{B.1.1} % This will return an error

\section{C}

\subsection{C.1}

\subsubsection{C.1.1}

\end{document}


This will output:

-
I am using Winedt editor for editing the file. Is there any option to search error in heading levels in the latex file without compiling. –  Pradeep Singh Mar 28 '12 at 11:20
@PradeepSingh no not just out-of-the box. The easiest thing is just to scour the aux file for write outs of section commands. This will not catch everything as you have to have all sections labelled etc. However, it will give you a hint. Still this will not yield information on paragraph commands so is very limited! I think you are better off with compiling once more... Does it really take that long? –  zeroth Mar 28 '12 at 11:25

Here's a rather idiosyncratic way of doing this that has the advantage of making things easy to fix if you do spot a problem. It requires you to be using emacs+reftex.

First, the theory: If a \section is followed by a \subsubsection, it will be numbered n.0.1 where n is the section number. So all you need to do is list all the numbers of the sections, and search for zeroes!

RefTeX makes this easy to do if you are using emacs. Just do C-c = (that is, Ctrl+c and then =). This opens up the reftex window which lists sections. Pressing l in this window will list all the labels too. Neat, huh? Also, this will list not just the current document's sections, but the other sections in other documents \included in the document listed as TeX-master. Ultra cool.

But anyway. How does this help with the current problem? Well, the reftex buffer – despite all its obvious coolness – is just plain text. We can search plain text. C-s searches forward, C-r searches backward. So C-s .0 should search for .0 in the buffer. Odds are that instances of faulty hierarchy are spotted this way.

What's cool about this method is that it allows you to fix problems easily. Let's say you see this:

(apologies for the dodgy colour scheme. I've not got around to fixing it). There are two ways you might want to fix this. First, you might want to add a new subsection above Broken. Press enter, and reftex will move you to the the part of the file where \subsubsection{Broken!} is. So just move up a couple of lines and do C-c C-s to add a new section-type command.

But this is the cool bit. Say, instead, you just want to change the level of Broken to subsection. From within the reftex buffer, you can use < and > to move a section-type command up and down a level respectively. So pressing < with 2.0.1 Broken! will change it into a subsection 2.1 Broken!. Now, that is cool.