260809.1.6 · 21aae6a8b37203925c8374f74abd7b0cc459a11c
Merge branch 'master' into 'feature/indent-guides'
# Conflicts: # src/cli/cmdlineoptions.cpp # src/core/codegenerator.cpp # src/core/htmlgenerator.cpp
reading declarations
@@ -6,17 +6,6 @@ image: debian:stable-slim before_script: - apt-get update - apt-get install -y make gcc g++ libboost-dev liblua5.3-dev git- # ======================- # EditorConfig Toolchain- # ======================- # Install Node.js:- - apt-get install -y curl- - curl -sL https://deb.nodesource.com/setup_20.x | bash- - apt-get install -y nodejs- - node -v- - npm -v- # Install EClint:- - npm install -g eclint compile: script:@@ -25,9 +14,3 @@ compile: # Verify that our compiled app works properly with a custom "test" script - bash ./src/ci_test.sh -validate:- script:- # Validate committed files against EditorConfig settings via EClint using- # a custom script that in case of error lists only the problematic files:- - bash ./validate.sh-
@@ -9,13 +9,13 @@ == highlight 4.21 -19.05.2026+22.07.2026 + - updated astyle lib to version 3.6.17 - added Svelte language definition (https://gitlab.com/saalen/highlight/-/work_items/189) - fixed vue.js nested section highlighting- - updated astyle lib to version 3.6.17- - updated chinese GUI translation (qm file) - fixed RTF header and footer generation to allow plugin insertions (https://gitlab.com/saalen/highlight/-/work_items/264)+ - updated chinese GUI translation == highlight 4.20
@@ -236,6 +236,8 @@ Output formatting options: -J, --line-length=<num> line length before wrapping (see -V, -W) -j, --line-number-length=<num> line number width incl. left padding (default: 5) --line-range=<start-end> output only lines from number <start> to <end>+ --skip-leading-cols=<num> output the first <num> columns of each line+ unhighlighted (example: hg or svn annotate) -k, --font=<font> set font (specific to output format) -K, --font-size=<num?> set font size (specific to output format) -l, --line-numbers print line numbers in output file@@ -384,9 +386,11 @@ Note: Using a plug-in script is the preferred way to enhance styling. ==== Terminal output: -As there are only a few colours defined for ANSI terminal output, there exists-only one hard coded colour theme with `--out-format=ansi`. You should therefore-use `--out-format=xterm256` to enable output in 256 colours. The 256 colour mode+ANSI terminal output is limited to the 16 colours of the terminal palette, so+themes are ignored with `--out-format=ansi` unless their elements define an+`AnsiIndex` attribute. Elements without one keep the hard coded default sequence,+and theme font attributes are not applied in this format.+Use `--out-format=xterm256` to enable output in 256 colours. The 256 colour mode is supported by recent releases of xterm, rxvt and Putty (amongst others). Recently published terminal emulators also support 16m colors, this mode is enabled with `--out-format=truecolor`.@@ -790,7 +794,7 @@ to use one of the included Base16 themes (located in {themes_base16}). ==== Format attributes ................................................................................-Attributes = {Colour, Bold?, Italic?, Underline?, Custom? }+Attributes = {Colour, Bold?, Italic?, Underline?, AnsiIndex?, Custom? } ................................................................................ [horizontal]@@ -798,6 +802,8 @@ Colour:: String, defines colour in HTML hex notation (`#rrggbb`) Bold:: Boolean, true if font should be bold (optional) Italic:: Boolean, true if font should be italic (optional) Underline:: Boolean, true if font should be underlined (optional)+AnsiIndex:: Number, terminal palette index 0-15, applied with+ `--out-format=ansi` only (optional) Custom:: Array, contains `Format` and `Style` for custom styles ==== Theme elements
@@ -379,9 +379,12 @@ Hinweis: Ein Plug-In Skript ist die bessere Methode das Styling anzupassen. ==== Terminal-Ausgabe: -Da es nur wenige Farben zur ANSI-Ausgabe im Terminal gibt, existiert nur ein-hartkodiertes Farbschema fuer `--out-format=ansi`. Daher sollte nach Moeglichkeit-`--out-format=xterm256` verwendet werden, um eine Ausgabe in 256 Farben zu erhalten.+Die ANSI-Ausgabe im Terminal ist auf die 16 Farben der Terminal-Palette begrenzt.+Themes werden mit `--out-format=ansi` daher ignoriert, sofern deren Elemente kein+`AnsiIndex`-Attribut definieren. Elemente ohne dieses Attribut behalten die+hartkodierte Standardsequenz, Font-Attribute des Themes werden in diesem Format+nicht angewendet.+Fuer eine Ausgabe in 256 Farben sollte `--out-format=xterm256` verwendet werden. Der 256 Farb-Modus wird z.B. von xterm, rxvt und Putty unterstuetzt. Neuere Terminal-Emulatoren unterstuetzen auch 16 Millionen Farben, dies wird mit `--out-format=truecolor` aktiviert.
@@ -377,9 +377,11 @@ Note : Un script plug-in est une meilleure méthode pour personnaliser le style. ==== Sortie Terminal : -Comme il n'y a que peu de couleurs disponibles pour la sortie ANSI dans le terminal,-il n'existe qu'un schéma de couleurs codé en dur pour `--out-format=ansi`. Par conséquent,-il est préférable d'utiliser `--out-format=xterm256` si possible pour obtenir une+La sortie ANSI dans le terminal est limitée aux 16 couleurs de la palette du terminal.+Les thèmes sont donc ignorés avec `--out-format=ansi`, sauf si leurs éléments définissent+un attribut `AnsiIndex`. Les éléments sans cet attribut conservent la séquence par défaut+codée en dur, et les attributs de police du thème ne sont pas appliqués dans ce format.+Il est préférable d'utiliser `--out-format=xterm256` si possible pour obtenir une sortie en 256 couleurs. Le mode 256 couleurs est pris en charge par exemple par xterm, rxvt et Putty. Les émulateurs de terminal plus récents prennent également en charge 16 millions de
gui_files/ext/fileopenfilter.conf
@@ -114,6 +114,7 @@ JSON (*.json) JSP (*.jsp) JSX (*.jsx) Julia (*.jl)+KDL (*.kdl) Kotlin (*.kt) LaTeX (*.tex) LDAP (*.ldif)
@@ -13,7 +13,7 @@ Keywords={ Regex=[[ [0-9A-Z_]{2,} ]], }, { Id=3,- Regex=[[\$\{.+\$\{[^}]+\}.+?\}|\$\{[^}]+\} ]],+ Regex=[[ \$\{[^{}]*\$\{[^}]+\}[^{}]*?\}|\$\{[^}]+\} ]], }, { Id=3, Regex=[[ [A-Z_\>]+\:([\w/]+) ]],
@@ -0,0 +1,51 @@++Description="Svelte template block (nested in svelte.lang)"++Categories = {"markup", "script"}++Digits=[[ (?:0x)[0-9a-fA-F]+|(?:0b)[01]+|(?:0o)[0-8]+|\d*[\.]?\d+(?:[eE][\-\+]\d+)?[lLuU]* ]]++Keywords={+ -- the sigil belongs to the block marker: {#if, {:else, {/each, {@render+ { Id=1,+ Regex=[[[#:\/@]\w+]],+ Group=0,+ },+ -- block keywords plus the javascript ones an expression may contain+ { Id=1,+ List={"if", "else", "each", "as", "await", "then", "catch", "key", "snippet",+ "html", "const", "debug", "render", "attach",+ "break", "class", "continue", "default", "delete", "export", "extends",+ "finally", "instanceof", "import", "in", "new", "of", "from", "return",+ "super", "switch", "this", "throw", "try", "typeof", "var", "let",+ "function", "yield", "static", "true", "false", "null", "do", "for", "while",+ },+ },+ { Id=2,+ List={"boolean", "undefined", "void"},+ },+ { Id=4,+ Regex=[[(\w+)(\s*[:=]\s*function)?\s*\(]],+ Group=1+ },+}++Strings={+ Delimiter=[["|'|`]],+ Interpolation=[[ \$\{[^}]+\} ]],+ Escape = [=[ \\u\{?[[:xdigit:]]{4,6}\}?|\\\d{3}|\\x[[:xdigit:]]{2}|\\[ntvbrfa\\\?'\"] ]=]+}++IgnoreCase=false++Comments={+ { Block=false,+ Delimiter= { [[\/\/]] },+ },+ { Block=true,+ Nested=false,+ Delimiter= { [[\/\*]],[[\*\/]],}+ }+}++Operators=[[\(|\)|\[|\]|\{|\}|\,|\;|\:|\?|\&|<|>|\!|\=|\/|\*|\%|\+|\-|\~|\||\.]]
@@ -0,0 +1,94 @@+Description="KDL"++Categories = {"config"}++-- KDL 2.0.0, plus the KDL 1 spellings of the keywords and of raw strings, as+-- most configuration files in the wild are still written against KDL 1++Identifiers=[[ [a-zA-Z_][\w\-\.]*|[\-\.]+[a-zA-Z_][\w\-\.]* ]]++Digits=[[ [\-\+]?(?:0x[0-9a-fA-F][0-9a-fA-F_]*|0o[0-7][0-7_]*|0b[01][01_]*|\d[\d_]*(?:\.[\d_]+)?(?:[eE][\-\+]?\d[\d_]*)?) ]]++Keywords={+ -- the property key must precede the node name: on a line continued with "\"+ -- both match, and only this one is right+ { Id=2,+ Regex=[[([\w\-\.\x80-\xFF][^\s\(\)\{\}\[\];=\\\/"]*)\s*=]],+ },+ { Id=1,+ Regex=[[^\s*([\w\-\.\x80-\xFF][^\s\(\)\{\}\[\];=\\\/"]*)]],+ },+ { Id=3,+ Regex=[[#(?:true|false|null|inf|-inf|nan)]],+ },+ { Id=3,+ List={"true", "false", "null"}+ },+ { Id=4,+ Regex=[[\(\s*([^\s\(\)]+)\s*\)]],+ },+ -- Raw string delimiters, handed to the string state by OnStateChange, which+ -- pairs their hashes by length. #"""# holds a quote, it is not a multi line+ -- opener; and since "#ff0000" opens a plain string, only close a raw one+ -- where a value ends and cannot begin.+ { Id=5,+ Regex=[[#+"""(?!#)|#+"]]+ },+ { Id=6,+ Regex=[["""#+]]+ },+ { Id=6,+ Regex=[[[^\s=]("#+)(?=[\s;\)\}=]|$)]],+ },+}++Strings={+ Delimiter=[["""|"]],+ AssertEqualLength=true,+ RawPrefix="r",+ -- \" is an escape everywhere except as the tail of a raw string terminator+ Escape=[[ \\u\{[0-9a-fA-F]{1,6}\}|\\[nrtsbf\\\/]|\\"(?!#+(?:[\s;\)\}=]|$)) ]],+}++IgnoreCase=false++Comments={+ -- "/*" and a slashdashed node with a child block share one nesting counter,+ -- so a "}" ends a block comment opened inside a commented out node. The bare+ -- "{" alternative is what feeds the counter the inner blocks.+ { Block=true,+ Nested=true,+ Delimiter= { [[\/\*|\/\-[^\{\}]*\{|\{]], [[\*\/|\}]] }+ },+ -- slashdash without a child block: the node ends with the line+ { Block=false,+ Delimiter= { [[\/\-]] }+ },+ { Block=false,+ Delimiter= { [[\/\/]] }+ },+}++Operators=[[\(|\)|\{|\}|\;|\=|\\]]++function OnStateChange(oldState, newState, token, groupID)++ -- braces delimit a comment only while a slashdashed node is being skipped+ if (token=="{" or token=="}") and oldState~=HL_BLOCK_COMMENT then+ return HL_OPERATOR+ end++ if groupID==5 then+ -- inside a string the hashes are content, and the quote closes it+ if oldState==HL_STRING then+ return HL_REJECT+ end+ OverrideParam("state.string.raw", "true")+ return HL_STRING+ end+ if groupID==6 and oldState==HL_STRING then+ return HL_STRING_END+ end++ return newState+end
@@ -46,7 +46,7 @@ PreProcessor={ } NestedSections = {- { Lang="asm", Delimiter= { [[asm]], [[\}]] } }+ { Lang="nbc", Delimiter= { [[asm]], [[\}]] } } } Operators=[[\(|\)|\[|\]|\{|\}|\,|\;|\.|\:|\&|<|>|\!|\=|\/|\*|\%|\+|\-|\~]]
@@ -57,6 +57,10 @@ Keywords={ -- hereDoc opening delimiter, see OnStateChange to handle end of string Strings={ Delimiter=[[<<[\-]?\s*["']?\s*[A-Za-z_]+["']?|"|`|']],+ -- balanced $( ... ) span (recursive); within strings it is absorbed into the+ -- string unit so quotes inside command substitutions do not break pairing;+ -- outside strings OnStateChange rejects it so inner tokens keep their colors+ Interpolation=[[\$\((?:[^()]|(?R))*\)]], } IgnoreCase=false@@ -74,6 +78,13 @@ cmdSubStack = {} function OnStateChange(oldState, newState, token, kwClass) + -- the interpolation span is only wanted inside quoted strings; reject it at+ -- root level so the substitution's content is tokenized normally, and inside+ -- heredocs, which end at the delimiter word and need no quote pairing+ if newState == HL_INTERPOLATION and (oldState == HL_STANDARD or hereDoc ~= nil) then+ return HL_REJECT+ end+ if oldState == HL_STRING and token == hereDoc then hereDoc = nil return HL_STRING_END@@ -85,7 +96,13 @@ function OnStateChange(oldState, newState, token, kwClass) cmdSubStart = string.find(token, "%$%(") if cmdSubStart and cmdSubStack ~= nil then- table.insert(cmdSubStack, {depth = #cmdSubStack + 1, inString = true})+ -- a balanced $( ... ) arrives as a single token, so no closing ) follows+ -- to pop it again: tracking it would leave the stack filled for good+ cmdSubOpen = select(2, string.gsub(token, "%(", ""))+ cmdSubClose = select(2, string.gsub(token, "%)", ""))+ if cmdSubOpen > cmdSubClose then+ table.insert(cmdSubStack, {depth = #cmdSubStack + 1, inString = true})+ end return HL_STRING end
@@ -11,12 +11,14 @@ Keywords={ { Id=2, Regex=[=[([-\w\.\:\|]+)=["'{]]=], },+ -- full marker: also catches markers after the first on a line, which the+ -- nested section cannot (only one embedded section may open per line) { Id=3, Regex=[[\{[#\/](?:if|each|await|key|snippet)\b|\{:(?:else|then|catch)\b|\{@(?:html|const|debug|render|attach)\b]], Group=0, }, { Id=3,- Regex=[=[[\{\}]]=],+ Regex=[=[\{[#:\/@]?|\}]=], Group=0, }, { Id=4,@@ -38,6 +40,10 @@ Comments={ } NestedSections = {+ -- template blocks and interpolations: the block keyword and the expression are+ -- highlighted by inc_svelteblock instead of a single pattern per marker, so+ -- {:else if} and {#each x as y} keep both of their keywords+ { Lang="inc_svelteblock", Delimiter= { [=[\{[#:\/@]]=], [[\}]] } }, { Lang="css", Delimiter= { [[<style[^>]*>]], [[<\/style>]] } }, { Lang="javascript", Delimiter= { [[<script[^>]*>]], [[<\/script>]] } }, -- must come after the generic entry: the last matching delimiter wins
@@ -55,6 +55,10 @@ list installed scripts filter the scripts by the given categories (example: --list-cat='source;script') .IP "\fB--max-size\fR=<\fIsize\fR>" set maximum input file size (examples: 512M, 1G; default: 256M)+.IP "\fB--skip-leading-cols\fR=<\fInum\fR>"+output the first num columns of each line unhighlighted; the columns are kept+out of the parser, so quotes or comment delimiters within them cannot alter the+highlighting of the remaining code (example: output of hg or svn annotate) .IP "\fB--plug-in\fR=<\fIscript\fR>" execute Lua plug-in script; repeat option to apply multiple plug-ins .IP "\fB--plug-in-param\fR"
@@ -52,7 +52,8 @@ enum Optcode { S_OPT_PLUGIN_READFILE, S_OPT_PLUGIN_PARAMETER, S_OPT_LIST_SCRIPTS, S_OPT_CANVAS, S_OPT_KEEP_INJECTIONS, S_OPT_FORCE_STDOUT, S_OPT_LATEX_BEAMER, S_OPT_NO_VERSION_INFO, S_OPT_REFORMAT_OPT, S_OPT_RANGE_OPT, S_OPT_BASE16, S_OPT_CATEGORIES, S_OPT_PIPED_FNAME,- S_OPT_ISOLATE, S_OPT_MAX_FILE_SIZE, S_OPT_SYNTAX_SUPPORTED, S_OPT_INDENT_GUIDES,+ S_OPT_ISOLATE, S_OPT_MAX_FILE_SIZE, S_OPT_SKIP_LEADING_COLS, S_OPT_SYNTAX_SUPPORTED, + S_OPT_INDENT_GUIDES, S_OPT_LS_PROFILE, S_OPT_LS_WORKSPACE, S_OPT_LS_EXEC, S_OPT_LS_OPTION, S_OPT_LS_HOVER, S_OPT_LS_SEMANTIC, S_OPT_LS_RAINBOW, S_OPT_LS_SYNTAX, S_OPT_LS_SYNTAX_ERROR, S_OPT_LS_DELAY, S_OPT_LS_LEGACY, S_OPT_SERVICE_MODE, S_OPT_DISABLE_ECHO@@ -147,6 +148,7 @@ const Arg_parser::Option options[] = { { S_OPT_PIPED_FNAME, OPT_PIPED_FNAME, Arg_parser::yes }, { S_OPT_ISOLATE, OPT_ISOLATE_TAGS, Arg_parser::no }, { S_OPT_MAX_FILE_SIZE, OPT_MAX_FILE_SIZE, Arg_parser::yes },+ { S_OPT_SKIP_LEADING_COLS, OPT_SKIP_LEADING_COLS, Arg_parser::yes }, { S_OPT_SYNTAX_SUPPORTED, OPT_SYNTAX_SUPPORTED, Arg_parser::no }, { S_OPT_LS_PROFILE, OPT_LS_PROFILE, Arg_parser::yes },@@ -614,6 +616,9 @@ void CmdLineOptions::parseRuntimeOptions( const int argc, const char *argv[], bo } break; }+ case S_OPT_SKIP_LEADING_COLS:+ StringTools::str2num<unsigned int> ( skipLeadingCols, arg, std::dec );+ break; case S_OPT_SYNTAX_SUPPORTED: opt_syntax_supported_check = true; break;@@ -919,6 +924,11 @@ off_t CmdLineOptions::getMaxFileSize() const return maxFileSize; } +unsigned int CmdLineOptions::getSkipLeadingCols() const+{+ return skipLeadingCols;+}+ string CmdLineOptions::getIndentScheme() const { return StringTools::change_case ( indentScheme );
@@ -117,6 +117,7 @@ along with Highlight. If not, see <http://www.gnu.org/licenses/>. #define OPT_PIPED_FNAME "syntax-by-name" #define OPT_ISOLATE_TAGS "isolate" #define OPT_MAX_FILE_SIZE "max-size"+#define OPT_SKIP_LEADING_COLS "skip-leading-cols" #define OPT_SYNTAX_SUPPORTED "syntax-supported" #define OPT_SERVICE_MODE "service-mode" #define OPT_DISABLE_ECHO "disable-echo"@@ -384,6 +385,9 @@ public: /** \return max. input file size (default 256 MB) */ off_t getMaxFileSize() const; + /** \return number of leading columns to output unhighlighted */+ unsigned int getSkipLeadingCols() const;+ /** \return The given base font, empty std::string by default */ const std::string& getBaseFont() const ; @@ -572,6 +576,8 @@ private: off_t maxFileSize{268435456}; + unsigned int skipLeadingCols{0};+ std::string fallbackSyntax, anchorPrefix; std::string helpLang, encodingName;
@@ -185,6 +185,8 @@ void printHelp(const std::string &topic) std::cout<<" -J, --line-length=<num> line length before wrapping (see -V, -W)\n"; std::cout<<" -j, --line-number-length=<num> line number width incl. left padding (default: 5)\n"; std::cout<<" --line-range=<start-end> output only lines from number <start> to <end>\n";+ std::cout<<" --skip-leading-cols=<num> output the first <num> columns of each line\n";+ std::cout<<" unhighlighted (example: hg or svn annotate)\n"; std::cout<<" -k, --font=<font> set font (specific to output format)\n"; std::cout<<" -K, --font-size=<num?> set font size (specific to output format)\n";
@@ -581,6 +581,7 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] ) generator->setBaseFont ( options.getBaseFont() ) ; generator->setBaseFontSize ( options.getBaseFontSize() ) ; generator->setLineNumberWidth ( options.getNumberWidth() );+ generator->setSkipLeadingCols ( options.getSkipLeadingCols() ); generator->disableTrailingNL(options.disableTrailingNL()); generator->setPluginParameter(options.getPluginParameter());
@@ -31,6 +31,7 @@ along with Highlight. If not, see <http://www.gnu.org/licenses/>. using std::string; using std::string_view;+using std::to_string; namespace highlight {@@ -53,6 +54,15 @@ string AnsiGenerator::getOpenTag ( string_view font, } +string AnsiGenerator::getOpenTag ( const ElementStyle &elem,+ string_view font, string_view fgCol )+{+ int idx = elem.getAnsiIndex();+ if ( idx < 0 ) return getOpenTag ( font, fgCol );+ return getOpenTag ( font, to_string ( idx<8 ? 30+idx : 90+idx-8 ) );+}++ AnsiGenerator::AnsiGenerator() : CodeGenerator ( ESC_ANSI ) { newLineTag = "\n";@@ -62,19 +72,19 @@ AnsiGenerator::AnsiGenerator() : CodeGenerator ( ESC_ANSI ) void AnsiGenerator::initOutputTags() { openTags = {- getOpenTag ( "00", "39" ),- getOpenTag ( "00", "31" ), //str- getOpenTag ( "00", "34" ), //number- getOpenTag ( "00", "34" ), //sl comment- getOpenTag ( "00", "34" ), //ml comment- getOpenTag ( "00", "35" ), //escapeChar- getOpenTag ( "00", "35" ), //directive- getOpenTag ( "00", "31" ), //directive string- getOpenTag ( "00", "39" ), //linenum- getOpenTag ( "00", "39" ), //symbol- getOpenTag ( "00", "35" ), //interpolation- getOpenTag ( "01", "31" ), //error- getOpenTag ( "01", "31" ) //warning+ getOpenTag ( docStyle.getDefaultStyle(), "00", "39" ),+ getOpenTag ( docStyle.getStringStyle(), "00", "31" ), //str+ getOpenTag ( docStyle.getNumberStyle(), "00", "34" ), //number+ getOpenTag ( docStyle.getSingleLineCommentStyle(), "00", "34" ), //sl comment+ getOpenTag ( docStyle.getCommentStyle(), "00", "34" ), //ml comment+ getOpenTag ( docStyle.getEscapeCharStyle(), "00", "35" ), //escapeChar+ getOpenTag ( docStyle.getPreProcessorStyle(), "00", "35" ), //directive+ getOpenTag ( docStyle.getPreProcStringStyle(), "00", "31" ), //directive string+ getOpenTag ( docStyle.getLineStyle(), "00", "39" ), //linenum+ getOpenTag ( docStyle.getOperatorStyle(), "00", "39" ), //symbol+ getOpenTag ( docStyle.getInterpolationStyle(), "00", "35" ), //interpolation+ getOpenTag ( docStyle.getErrorStyle(), "01", "31" ), //error+ getOpenTag ( docStyle.getErrorMessageStyle(), "01", "31" ) //warning }; closeTags.assign ( NUMBER_BUILTIN_STATES, "\033[m" );@@ -108,7 +118,8 @@ string AnsiGenerator::maskCharacter ( unsigned char c ) string AnsiGenerator::getKeywordOpenTag ( unsigned int styleID ) {- return ( styleID ) ?getOpenTag ( "00", "32", "" ) :getOpenTag ( "00", "33" );+ return getOpenTag ( docStyle.getKeywordStyle ( currentSyntax->getKeywordClasses() [styleID] ),+ "00", ( styleID ) ?"32" :"33" ); } string AnsiGenerator::getKeywordCloseTag ( unsigned int styleID )
@@ -172,6 +172,8 @@ CodeGenerator::CodeGenerator ( highlight::OutputType type ) startLineCntCurFile( 1 ), extraEOFChar( 255 ), maxLineCnt ( UINT_MAX ),+ skipLeadingCols ( 0 ),+ lineHeadPending ( false ), inputFilesCnt (0), processedFilesCnt (0), kwOffset(0),@@ -489,6 +491,11 @@ void CodeGenerator::setMaxInputLineCnt ( unsigned int cnt ) maxLineCnt = cnt; } +void CodeGenerator::setSkipLeadingCols ( unsigned int cols )+{+ skipLeadingCols = cols;+}+ void CodeGenerator::setFilesCnt ( unsigned int cnt ) { inputFilesCnt = cnt;@@ -733,6 +740,21 @@ bool CodeGenerator::readNewLine ( string &newLine ) newLine.erase(newLine.size() - 1); #endif + // keep the leading columns out of the parser, so that quotes or comment+ // delimiters within them cannot open a state which spans several lines+ if ( skipLeadingCols ) {+ string::size_type headEnd = 0;+ for ( unsigned int col=0; col<skipLeadingCols && headEnd<newLine.size(); ++col ) {+ // do not split a multi byte character+ do {+ ++headEnd;+ } while ( headEnd<newLine.size() && ( newLine[headEnd] & 0xC0 ) == 0x80 );+ }+ lineHead = newLine.substr ( 0, headEnd );+ newLine.erase ( 0, headEnd );+ lineHeadPending = true;+ }+ return eof || ( lineNumber == maxLineCnt ); } @@ -2435,8 +2457,20 @@ void CodeGenerator::insertLineNumber ( bool insertNewLine ) wsBuffer += numberPrefix.str(); } + insertLineHead();+}++void CodeGenerator::insertLineHead()+{ wsBuffer += guidePrefix; guidePrefix.clear();+ // wrapped segments continue a line whose head was already printed+ if ( !lineHeadPending ) return;++ ostringstream headPrefix;+ maskString ( headPrefix, lineHead );+ wsBuffer += headPrefix.str();+ lineHeadPending = false; } unsigned int CodeGenerator::getLineIndex()
@@ -141,4 +141,12 @@ void ElementStyle::setCustomOverride(bool override) { customOverride = override; } +int ElementStyle::getAnsiIndex() const {+ return ansiIndex;+}++void ElementStyle::setAnsiIndex(int idx) {+ ansiIndex = idx;+}+ }
@@ -422,8 +422,7 @@ void HtmlGenerator::insertLineNumber ( bool insertNewLine ) wsBuffer += numberPrefix.str(); } - wsBuffer += guidePrefix;- guidePrefix.clear();+ insertLineHead(); } bool HtmlGenerator::printIndexFile ( const vector<string> &fileList,
@@ -102,6 +102,7 @@ void ThemeReader::initStyle(ElementStyle& style, const Diluculum::LuaVariable& v string styleColor="#000000"; bool styleBold=false, styleItalic=false, styleUnderline=false;+ int styleAnsiIndex=-1; if (var["Colour"].value()!=Diluculum::Nil) { styleColor= var["Colour"].value().asString();@@ -123,10 +124,16 @@ void ThemeReader::initStyle(ElementStyle& style, const Diluculum::LuaVariable& v style.setCustomOverride(false); } + if (var["AnsiIndex"].value()!=Diluculum::Nil) {+ lua_Integer idx = var["AnsiIndex"].value().asInteger();+ if (idx>=0 && idx<=15) styleAnsiIndex=idx;+ }+ style.setColour(Colour(styleColor)); style.setBold(styleBold); style.setItalic(styleItalic); style.setUnderline(styleUnderline);+ style.setAnsiIndex(styleAnsiIndex); } bool ThemeReader::load ( const string &styleDefinitionPath , OutputType type, bool loadSemanticStyles)
@@ -74,6 +74,11 @@ private: std::string getOpenTag ( std::string_view font, std::string_view fgCol, std::string_view bgCol="" ); + /** \return ANSI formatting sequences of the element's terminal colour index,+ or the given default sequence if the element defines no index */+ std::string getOpenTag ( const ElementStyle &elem,+ std::string_view font, std::string_view fgCol );+ /** initialize tags in specific format according to colouring information provided in DocumentStyle */ void initOutputTags() override;
@@ -361,6 +361,12 @@ public: /** \param cnt upper limit of input lines to be processed */ void setMaxInputLineCnt ( unsigned int cnt ); + /** \param cols number of leading columns to output unhighlighted */+ void setSkipLeadingCols ( unsigned int cols );++ /** print the leading columns which bypassed the parser */+ void insertLineHead();+ /** \param cnt number of input files */ void setFilesCnt ( unsigned int cnt ); @@ -641,6 +647,9 @@ protected: /** Current line of input file*/ std::string line; + /** Leading columns of the current line, kept out of the parser */+ std::string lineHead;+ /** Current line number */ unsigned int lineNumber; @@ -815,6 +824,12 @@ private: /**maximum count of input lines to be processed*/ unsigned int maxLineCnt; + /**number of leading columns which bypass the parser*/+ unsigned int skipLeadingCols;++ /**true if the leading columns of the current line still have to be printed*/+ bool lineHeadPending;+ /**number of files to be processed and counter*/ unsigned int inputFilesCnt;
@@ -68,6 +68,7 @@ public: underline = other.isUnderline(); customOverride = other.getCustomOverride(); customAttribute = other.getCustomAttribute();+ ansiIndex = other.getAnsiIndex(); } /** operator overloading */@@ -79,6 +80,7 @@ public: underline = other.isUnderline(); customOverride = other.getCustomOverride(); customAttribute = other.getCustomAttribute();+ ansiIndex = other.getAnsiIndex(); return *this; }@@ -135,10 +137,17 @@ public: void setCustomOverride(bool override); + /** \return terminal colour index (0-15), or -1 if the element defines none */+ int getAnsiIndex() const;++ /** \param idx terminal colour index (0-15), or -1 to use the built-in default */+ void setAnsiIndex(int idx);+ private: Colour colour; bool bold, italic, underline, customOverride; std::string customAttribute;+ int ansiIndex{-1}; }; }
@@ -0,0 +1,43 @@+Description="Terminal palette (ANSI colour indices)"++Categories = {"dark"}++Default = { Colour="#c0c0c0", AnsiIndex=7 }+Canvas = { Colour="#000000" }+Number = { Colour="#00aaaa", AnsiIndex=6 }+Escape = { Colour="#aa00aa", AnsiIndex=5 }+String = { Colour="#00aa00", AnsiIndex=2 }+StringPreProc = { Colour="#55ff55", AnsiIndex=10 }+BlockComment = { Colour="#555555", AnsiIndex=8 }+PreProcessor = { Colour="#aa5500", AnsiIndex=3 }+LineNum = { Colour="#555555", AnsiIndex=8 }+Operator = { Colour="#c0c0c0", AnsiIndex=7 }+LineComment = BlockComment+Interpolation = { Colour="#55ffff", AnsiIndex=14 }++Keywords = {+ { Colour="#ffffff", AnsiIndex=15 },+ { Colour="#5555ff", AnsiIndex=12 },+ { Colour="#ff5555", AnsiIndex=9 },+ { Colour="#ff55ff", AnsiIndex=13 },+ { Colour="#ffff55", AnsiIndex=11 },+ { Colour="#55ffff", AnsiIndex=14 },+}++-- new LSP based elements:++SemanticTokenTypes = {+ { Type = 'type', Style = Keywords[2] },+ { Type = 'class', Style = Keywords[1] },+ { Type = 'struct', Style = Keywords[4] },+ { Type = 'interface', Style = Keywords[1] },+ { Type = 'parameter', Style = Keywords[6] },+ { Type = 'variable', Style = Keywords[5] },+ { Type = 'enumMember', Style = Keywords[5] },+ { Type = 'function', Style = Keywords[4] },+ { Type = 'method', Style = Keywords[4] },+ { Type = 'keyword', Style = Keywords[1] },+ { Type = 'number', Style = Number },+ { Type = 'regexp', Style = String },+ { Type = 'operator', Style = Operator },+}