notepad-plus-plus/lexilla/lexers/LexAsciidoc.cxx
Christian Grasser ad79718fc8 Update to scintilla 5.5.2 & Lexilla 5.4.0
Release 5.5.2 ( https://www.scintilla.org/scintilla552.zip )

    Released 21 August 2024.
    Add SCI_SETCOPYSEPARATOR for separator between parts of a multiple selection when copied to the clipboard. Feature #1530.
    Add SCI_GETUNDOSEQUENCE to determine whether an undo sequence is active and its nesting depth.
    Add SCI_STYLESETSTRETCH to support condensed and expanded text styles.
    Add SCI_LINEINDENT and SCI_LINEDEDENT. Feature #1524.
    Fix bug on Cocoa where double-click stopped working when system had been running for a long time.
    On Cocoa implement more values of font weight and stretch.

Release 5.4.0 ( https://www.scintilla.org/lexilla540.zip )

    Released 21 August 2024.
    Inside Lexilla, LexerModule instances are now const. This will require changes to applications that modify Lexilla.cxx, which may be done to add custom lexers.
    Lexer added for TOML "toml".
    Bash: Handle backslash in heredoc delimiter. Issue #257.
    Progress: Fix lexing of nested comments. Pull request #258.
    Force lower-casing of case-insensitive keyword lists so keywords match in some lexers. Issue #259.

Close #15564
2024-08-23 02:59:58 +02:00

394 lines
13 KiB
C++

/******************************************************************
* LexAsciidoc.cxx
*
* A simple Asciidoc lexer for scintilla.
*
* Based on the LexMarkdown.cxx by Jon Strait - jstrait@moonloop.net
*
* The License.txt file describes the conditions under which this
* software may be distributed.
*
*****************************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <string>
#include <string_view>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
using namespace Lexilla;
namespace {
typedef struct {
bool start;
int len1;
int len2;
const char *name;
} MacroItem;
static const MacroItem MacroList[] = {
// Directives
{true, 5, 2, "ifdef::"},
{true, 6, 2, "ifeval::"},
{true, 6, 2, "ifndef::"},
{true, 5, 2, "endif::"},
// Macros
{true, 5, 2, "audio::"},
{true, 7, 2, "include::"},
{true, 5, 2, "image::"},
{true, 5, 2, "video::"},
{false, 8, 1, "asciimath:"},
{false, 3, 1, "btn:"},
{false, 5, 1, "image:"},
{false, 3, 1, "kbd:"},
{false, 9, 1, "latexmath:"},
{false, 4, 1, "link:"},
{false, 6, 1, "mailto:"},
{false, 4, 1, "menu:"},
{false, 4, 1, "pass:"},
{false, 4, 1, "stem:"},
{false, 4, 1, "xref:"},
// Admonitions
{true, 7, 1, "CAUTION:"},
{true, 9, 1, "IMPORTANT:"},
{true, 4, 1, "NOTE:"},
{true, 3, 1, "TIP:"},
{true, 7, 1, "WARNING:"},
{false, 0, 0, NULL}
};
constexpr bool IsNewline(const int ch) {
// sc.GetRelative(i) returns '\0' if out of range
return (ch == '\n' || ch == '\r' || ch == '\0');
}
}
static bool AtTermStart(StyleContext &sc) {
return sc.currentPos == 0 || sc.chPrev == 0 || isspacechar(sc.chPrev);
}
static void ColorizeAsciidocDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
WordList **, Accessor &styler) {
bool freezeCursor = false;
StyleContext sc(startPos, static_cast<Sci_PositionU>(length), initStyle, styler);
while (sc.More()) {
// Skip past escaped characters
if (sc.ch == '\\') {
sc.Forward();
continue;
}
// Skip newline.
if (IsNewline(sc.ch)) {
// Newline doesn't end blocks
if (sc.state != SCE_ASCIIDOC_CODEBK && \
sc.state != SCE_ASCIIDOC_PASSBK && \
sc.state != SCE_ASCIIDOC_COMMENTBK && \
sc.state != SCE_ASCIIDOC_LITERALBK) {
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
sc.Forward();
continue;
}
// Conditional state-based actions
switch (sc.state) {
// Strong
case SCE_ASCIIDOC_STRONG1:
if (sc.ch == '*' && sc.chPrev != ' ') {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_DEFAULT);
freezeCursor = true;
}
break;
case SCE_ASCIIDOC_STRONG2:
if (sc.Match("**") && sc.chPrev != ' ') {
sc.Forward(2);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
freezeCursor = true;
}
break;
// Emphasis
case SCE_ASCIIDOC_EM1:
if (sc.ch == '_' && sc.chPrev != ' ') {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_DEFAULT);
freezeCursor = true;
}
break;
case SCE_ASCIIDOC_EM2:
if (sc.Match("__") && sc.chPrev != ' ') {
sc.Forward(2);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
freezeCursor = true;
}
break;
// Link
case SCE_ASCIIDOC_LINK:
if (sc.ch == ']' && sc.chPrev != '\\') {
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Code block
case SCE_ASCIIDOC_CODEBK:
if (sc.atLineStart && sc.Match("----") && IsNewline(sc.GetRelative(4))) {
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Passthrough block
case SCE_ASCIIDOC_PASSBK:
if (sc.atLineStart && sc.Match("++++") && IsNewline(sc.GetRelative(4))) {
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Comment block
case SCE_ASCIIDOC_COMMENTBK:
if (sc.atLineStart && sc.Match("////") && IsNewline(sc.GetRelative(4))) {
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Literal
case SCE_ASCIIDOC_LITERAL:
if (sc.ch == '+' && sc.chPrev != '\\') {
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Literal block
case SCE_ASCIIDOC_LITERALBK:
if (sc.atLineStart && sc.Match("....") && IsNewline(sc.GetRelative(4))) {
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Attribute
case SCE_ASCIIDOC_ATTRIB:
if (sc.ch == ':' && sc.chPrev != ' ' && sc.chNext == ' ') {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_ATTRIBVAL);
}
break;
// Macro
case SCE_ASCIIDOC_MACRO:
if (sc.ch == ']' && sc.chPrev != '\\') {
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
break;
// Default
case SCE_ASCIIDOC_DEFAULT:
// Headers
if (sc.atLineStart && sc.Match("====== ")) {
sc.SetState(SCE_ASCIIDOC_HEADER6);
sc.Forward(6);
}
else if (sc.atLineStart && sc.Match("===== ")) {
sc.SetState(SCE_ASCIIDOC_HEADER5);
sc.Forward(5);
}
else if (sc.atLineStart && sc.Match("==== ")) {
sc.SetState(SCE_ASCIIDOC_HEADER4);
sc.Forward(4);
}
else if (sc.atLineStart && sc.Match("=== ")) {
sc.SetState(SCE_ASCIIDOC_HEADER3);
sc.Forward(3);
}
else if (sc.atLineStart && sc.Match("== ")) {
sc.SetState(SCE_ASCIIDOC_HEADER2);
sc.Forward(2);
}
else if (sc.atLineStart && sc.Match("= ")) {
sc.SetState(SCE_ASCIIDOC_HEADER1);
sc.Forward(1);
}
// Unordered list item
else if (sc.atLineStart && sc.Match("****** ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(6);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("***** ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(5);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("**** ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("*** ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(3);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("** ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(2);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("* ")) {
sc.SetState(SCE_ASCIIDOC_ULIST_ITEM);
sc.Forward(1);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
// Ordered list item
else if (sc.atLineStart && sc.Match("...... ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(6);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("..... ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(5);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match(".... ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(4);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match("... ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(3);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match(".. ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(2);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
else if (sc.atLineStart && sc.Match(". ")) {
sc.SetState(SCE_ASCIIDOC_OLIST_ITEM);
sc.Forward(1);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
}
// Blockquote
else if (sc.atLineStart && sc.Match("> ")) {
sc.SetState(SCE_ASCIIDOC_BLOCKQUOTE);
sc.Forward();
}
// Link
else if (!sc.atLineStart && sc.ch == '[' && sc.chPrev != '\\' && sc.chNext != ' ') {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_LINK);
freezeCursor = true;
}
// Code block
else if (sc.atLineStart && sc.Match("----") && IsNewline(sc.GetRelative(4))) {
sc.SetState(SCE_ASCIIDOC_CODEBK);
sc.Forward(4);
}
// Passthrough block
else if (sc.atLineStart && sc.Match("++++") && IsNewline(sc.GetRelative(4))) {
sc.SetState(SCE_ASCIIDOC_PASSBK);
sc.Forward(4);
}
// Comment block
else if (sc.atLineStart && sc.Match("////") && IsNewline(sc.GetRelative(4))) {
sc.SetState(SCE_ASCIIDOC_COMMENTBK);
sc.Forward(4);
}
// Comment
else if (sc.atLineStart && sc.Match("//")) {
sc.SetState(SCE_ASCIIDOC_COMMENT);
sc.Forward();
}
// Literal
else if (sc.ch == '+' && sc.chPrev != '\\' && sc.chNext != ' ' && AtTermStart(sc)) {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_LITERAL);
freezeCursor = true;
}
// Literal block
else if (sc.atLineStart && sc.Match("....") && IsNewline(sc.GetRelative(4))) {
sc.SetState(SCE_ASCIIDOC_LITERALBK);
sc.Forward(4);
}
// Attribute
else if (sc.atLineStart && sc.ch == ':' && sc.chNext != ' ') {
sc.SetState(SCE_ASCIIDOC_ATTRIB);
}
// Strong
else if (sc.Match("**") && sc.GetRelative(2) != ' ') {
sc.SetState(SCE_ASCIIDOC_STRONG2);
sc.Forward();
}
else if (sc.ch == '*' && sc.chNext != ' ' && AtTermStart(sc)) {
sc.SetState(SCE_ASCIIDOC_STRONG1);
}
// Emphasis
else if (sc.Match("__") && sc.GetRelative(2) != ' ') {
sc.SetState(SCE_ASCIIDOC_EM2);
sc.Forward();
}
else if (sc.ch == '_' && sc.chNext != ' ' && AtTermStart(sc)) {
sc.SetState(SCE_ASCIIDOC_EM1);
}
// Macro
else if (sc.atLineStart && sc.ch == '[' && sc.chNext != ' ') {
sc.Forward();
sc.SetState(SCE_ASCIIDOC_MACRO);
freezeCursor = true;
}
else {
int i = 0;
bool found = false;
while (!found && MacroList[i].name != NULL) {
if (MacroList[i].start)
found = sc.atLineStart && sc.Match(MacroList[i].name);
else
found = sc.Match(MacroList[i].name);
if (found) {
sc.SetState(SCE_ASCIIDOC_MACRO);
sc.Forward(MacroList[i].len1);
sc.SetState(SCE_ASCIIDOC_DEFAULT);
if (MacroList[i].len2 > 1)
sc.Forward(MacroList[i].len2 - 1);
}
i++;
}
}
break;
}
// Advance if not holding back the cursor for this iteration.
if (!freezeCursor)
sc.Forward();
freezeCursor = false;
}
sc.Complete();
}
extern const LexerModule lmAsciidoc(SCLEX_ASCIIDOC, ColorizeAsciidocDoc, "asciidoc");