Thanks @PeterJones, I really appreciate your time! I spent a chunk of time yesterday too trying to work out the regex if-then-else functionality before I gave up.
I wouldn’t want to pick up everything that starts with \ because that will pull in a lot of commands that aren’t related to document structure (every command starts with \). For example, here’s my minimum working example with a numbered list in it, and that picks up the \begin{enumerate} and \items:
\documentclass{scrreprt}
\begin{document}
\chapter{Chapter 1 with sections}
\section{1.1}
\subsection{1.1.1}
Lorem
\subsection{1.1.2}
ipsum
\section{1.2}
\begin{enumerate}
\item dolor
\item sit
\item amet
\end{enumerate}
\chapter{Chapter 2 with no sections}
consectetur adipiscing elit.
\chapter{Chapter 3 with unnumbered sections}
\section*{Heading with no number}
Phasellus mollis posuere ante vel tincidunt.
\section*{Second heading with no number}
Donec faucibus tellus sapien, vitae fringilla nulla bibendum eget.
\appendix
\chapter{Appendix A}
\include{document}
\chapter{Appendix B with sections}
\section{B.1}
Nam mauris nisl, cursus at erat in,
\section{B.2}
molestie luctus nulla.
\end{document}
… but picking up the \chapter{} as a function along with the \section{}s is a great workaround!
Here’s what I have now:
<?xml version="1.0" encoding="UTF-8" ?>
<!-- ==========================================================================\
| To learn how to make your own language parser, please check the following
| link: https://npp-user-manual.org/docs/function-list/
\=========================================================================== -->
<NotepadPlus>
<functionList>
<parser
displayName="LaTeX Syntax"
id ="latex_class"
commentExpr="(?x)
(%.*?$) # Comment
"
>
<function
mainExpr="(?x) # free-spacing (see `RegEx - Pattern Modifiers`)
(?im-s) # ignore case, ^ and $ match start/end of line, dot doesn't match newline
\\begin{document} # match start of document
"
>
</function>
<classRange
mainExpr ="(?x) # free-spacing (see `RegEx - Pattern Modifiers`)
(?m) # ^ and $ match at line-breaks
(?'CLASS_START'
^\s* # optional leading white space before \chapter
\\(chapter\*?)
)
(?s:.*?) # whatever,
(?= # ...up till
\s* # ...optional leading white-space of
(?:
(?&CLASS_START) # ...next header
| (\\end{document}) # ...or end of document
)
)
"
>
<className>
<nameExpr expr="(?x) # free-spacing (see `RegEx - Pattern Modifiers`)
(?<={) # brace before name
.*? # name
(?=}) # brace after name
"
/>
</className>
<function
mainExpr="(?xm-s) # free-spacing (see `RegEx - Pattern Modifiers`)
\\(chapter| # match chapter so that even \chapters with no \section appear
section| # match \section
subsection| # match \subsection
)\*?{.*} # match starred and unstarred commands
"
>
<functionName>
<funcNameExpr expr=".*"/>
</functionName>
</function>
</classRange>
</parser>
</functionList>
</NotepadPlus>
And the result on the sample file:
Screenshot 2025-05-14 094212.png
I modified the classRange mainExpr because I wanted to also match indented \chapter{}s (like I have for the appendices in the new sample file). After that change I found that the last \chapter{} wasn’t being matched with \Z so I changed the alternate search to look for \end{document} instead (which will always appear) and that worked.
Thanks for your help!