mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-31 01:34:58 +02:00
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
394 lines
13 KiB
C++
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");
|