@ 261105.1

261103.1.3 · bebfec1cb9cc7a83ae660a38b3fbce00dcf94155

Merge branch 'master' into 'patch-1'

# Conflicts: # langDefs/csharp_unity.lang

reading declarations

.gitignore

@@ -31,3 +31,4 @@ src/gui-qt/moc_* src/gui-qt/.qmake.stash src/gui-qt/Makefile src/gui-qt/*.qm+src/*.d

.gitlab-ci.yml

@@ -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-

CMakeLists.txt

@@ -2,7 +2,9 @@ cmake_minimum_required(VERSION 3.16)  # Policy settings cmake_policy(SET CMP0074 NEW) # find_package() uses _ROOT variables-cmake_policy(SET CMP0167 NEW) # FindBoost is deprecated, use Boost config+if(POLICY CMP0167)+    cmake_policy(SET CMP0167 NEW) # FindBoost is deprecated, use Boost config+endif()  project(highlight-all VERSION 4.0) @@ -99,7 +101,9 @@ set(CLI_SOURCES # Shared Core Library add_library(highlight-lib STATIC ${CORE_SOURCES}) target_include_directories(highlight-lib PUBLIC ${INCLUDE_DIR})-target_include_directories(highlight-lib PRIVATE ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIRS})+# Public headers (e.g. Diluculum/LuaState.hpp) include lua.hpp and Boost headers,+# so consumers of highlight-lib need these include paths too+target_include_directories(highlight-lib PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIRS}) target_compile_definitions(highlight-lib PRIVATE     HL_CONFIG_DIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}/highlight/"     HL_DATA_DIR="${CMAKE_INSTALL_FULL_DATADIR}/highlight/"@@ -149,6 +153,9 @@ if(BUILD_GUI)         ${GUI_QT_DIR}/io_report.cpp         ${GUI_QT_DIR}/showtextfile.cpp         ${GUI_QT_DIR}/syntax_chooser.cpp+        ${GUI_QT_DIR}/syntaxpalette.cpp+        ${GUI_QT_DIR}/thememodel.cpp+        ${GUI_QT_DIR}/themeswatchdelegate.cpp         ${GUI_QT_DIR}/highlight-gui.qrc     ) 

ChangeLog.adoc

@@ -6,6 +6,59 @@ :toc: left :toclevels: 1 ++== highlight 4.22++02.11.2026++ - updated astyle lib to version 3.6.21+ - added support for UTF-16 and UTF-32 input files with byte order mark (https://gitlab.com/saalen/highlight/-/work_items/266)+ - added m4 language definition+ - added rainbow_brackets.lua plug-in (colours brackets by nesting depth)+ - added color_swatches.lua plug-in (shows colour boxes next to colour literals)+ - added recognition of single-quoted strings in INI definition+ - fixed escaping of OSC sequences in terminal output formats (https://gitlab.com/saalen/highlight/-/work_items/267)+ - fixed Python interpolation matches outside of strings (https://gitlab.com/saalen/highlight/-/work_items/212)+ - fixed shared library build and install+ - GUI: replaced theme combo boxes with a searchable theme gallery+ - GUI: replaced syntax dropdown with a searchable pop-up list+ - GUI: convert and copy to clipboard buttons are always shown+ - GUI: restructured UI elements in groups and fixed UI inconsistencies+ - added russian description to highlight.desktop++== highlight 4.21++09.08.2026++ - updated astyle lib to version 3.6.18+ - added Svelte language definition (https://gitlab.com/saalen/highlight/-/work_items/189)+ - added KDL language definition (https://gitlab.com/saalen/highlight/-/work_items/262)+ - added AnsiIndex theme attribute (https://gitlab.com/saalen/highlight/-/work_items/224)+ - added terminal output sanitation of user input+ - CLI: added `--indent-guides` option (https://gitlab.com/saalen/highlight/-/work_items/240)+ - CLI: added `--skip-leading-cols` option (https://gitlab.com/saalen/highlight/-/work_items/184)+ - fixed vue.js nested section highlighting+ - fixed NXC nested section highlighting+ - fixed RTF header and footer generation to allow plugin insertions (https://gitlab.com/saalen/highlight/-/work_items/264)+ - fixed string highlighting of nested command substitutions in shellscript definition (https://gitlab.com/saalen/highlight/-/work_items/209)+ - fixed regular expressions in CMake and PHP definitions+ - fixed out_of_range crash in nested syntax definitions (https://gitlab.com/saalen/highlight/-/work_items/265)+ - fixed minor performance issues+ - updated chinese GUI translation+++== highlight 4.20++19.05.2026++ - updated astyle lib to version 3.6.16+ - fixed undefined lua upvalue in shellscript language definition+ - added C# Unity language definition+ - updated RPM Language definition+ - refactored cmake build script+ - refactored code to make use of C++17 features++ == highlight 4.19  18.02.2026

README.adoc

@@ -232,9 +232,12 @@ Output formatting options:                                   java, kr, linux, lisp, mozilla, otbs, pico,                                   vtk, ratliff, stroustrup, webkit, whitesmith]  -I, --include-style            include style definition in output file+     --indent-guides            draw guides in leading whitespace (implies -t 4)  -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@@ -383,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`.@@ -486,6 +491,14 @@ Use `--verbose` to display Lua and syntax data. Apply twice to print more inform  Use `--validate-input` to get rid of UTF8 byte order marks. +==== UTF-16 and UTF-32 input++Input files starting with a UTF-16 or UTF-32 byte order mark (little or big endian)+are converted to UTF-8 before parsing, also if read from stdin. The output encoding+is set to utf-8 for these files, unless `--encoding=none` is given.+Files in these encodings without a BOM are not detected; convert them to UTF-8+beforehand (e.g. with `iconv -f UTF-16LE -t UTF-8`).+ ==== Force output to stdout  Use `--stdout` to write output files in batch mode to stdout.@@ -789,7 +802,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]@@ -797,6 +810,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

README_DE.adoc

@@ -222,9 +222,12 @@ Output formatting options:                                   java, kr, linux, lisp, mozilla, otbs, pico,                                   vtk, ratliff, stroustrup, webkit, whitesmith]  -I, --include-style            include style definition in output file+     --indent-guides            draw guides in leading whitespace (implies -t 4)  -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@@ -379,9 +382,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.@@ -494,6 +500,15 @@ um mehr Informationen zu erhalten. Geben Sie `--validate-input` an, um das UTF8 Byte Order Mark (Startsequenz) zu entfernen. +==== UTF-16 und UTF-32 Eingabe++Eingabedateien, die mit einem UTF-16 oder UTF-32 Byte Order Mark beginnen (Little+oder Big Endian), werden vor dem Parsen nach UTF-8 konvertiert, auch bei Eingabe+ueber stdin. Die Ausgabekodierung wird fuer diese Dateien auf utf-8 gesetzt, sofern+nicht `--encoding=none` angegeben ist.+Dateien in diesen Kodierungen ohne BOM werden nicht erkannt; konvertieren Sie diese+vorher nach UTF-8 (z.B. mit `iconv -f UTF-16LE -t UTF-8`).+ ==== Ausgabe in stdout erzwingen  Mit `--stdout` wird die Ausgabe auch im Batch-Modus nach stdout ausgegeben.

README_FR.adoc

@@ -221,9 +221,12 @@ Output formatting options:                                   java, kr, linux, lisp, mozilla, otbs, pico,                                   vtk, ratliff, stroustrup, webkit, whitesmith]  -I, --include-style            include style definition in output file+     --indent-guides            draw guides in leading whitespace (implies -t 4)  -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@@ -377,9 +380,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@@ -487,6 +492,15 @@ fois pour obtenir plus d'informations.  Utilisez `--validate-input` pour supprimer la marque d'ordre des octets UTF8 (séquence de début). +==== Entrée UTF-16 et UTF-32++Les fichiers d'entrée commençant par une marque d'ordre des octets UTF-16 ou UTF-32+(little ou big endian) sont convertis en UTF-8 avant l'analyse, y compris depuis stdin.+L'encodage de sortie de ces fichiers est défini sur utf-8, sauf si `--encoding=none`+est indiqué.+Les fichiers dans ces encodages sans BOM ne sont pas détectés ; convertissez-les+d'abord en UTF-8 (par ex. avec `iconv -f UTF-16LE -t UTF-8`).+ ==== Forcer la sortie vers stdout  Avec `--stdout`, la sortie est dirigée vers stdout même en mode batch.

filetypes.conf

@@ -73,6 +73,7 @@ FileMapping = {  { Lang="lisp", Extensions={"cl", "clisp", "el", "lsp", "sbcl", "scom", "fas", "scm", "mud", "fasl" } },  { Lang="makefile", Extensions={"mak", "mk", "gnumakefile"} },  { Lang="meson", Filenames={ "meson.build", "meson_options.txt" } },+ { Lang="m4", Extensions={"m4"} },  { Lang="snmp", Extensions={"mib", "smi"} },  { Lang="ocaml", Extensions={"ml","mli", "eliom", "eliomi", "ml4", "mll", "mly"} },  { Lang="mod2", Extensions={"mod", "def"} },

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)@@ -219,6 +220,7 @@ Spin-SQL (*.spn) Squirrel (*.nut) Stylus (*.styl) SuperX++ (*.xpp)+Svelte (*.svelte) SVG (*.svg) Swift (*.swift) Sybase (*.sp)

gui_files/l10n/highlight_es_ES.qm

Binary file changed

gui_files/l10n/highlight_fr_FR.qm

Binary file changed

gui_files/l10n/highlight_it_IT.qm

Binary file changed

gui_files/l10n/highlight_zh_CN.qm

Binary file changed

highlight.desktop

@@ -4,6 +4,7 @@ Name=Highlight Type=Application Comment=Converts source code to formatted text (HTML, RTF, TeX, LaTeX, SVG, BBCode, Pango Markup, XML) with syntax highlighting Comment[de]=Konvertiert Sourcecode in formatierten Text (HTML, RTF, TeX, LaTeX, SVG, BBCode, Pango Markup, XML) mit Syntaxhervorhebung+Comment[ru]=Конвертер исходного кода в HTML, XHTML, RTF, LaTeX, TeX, XSL-FO, XML и ANSI-последовательности с подсветкой синтаксиса Exec=highlight-gui TryExec=highlight-gui Icon=highlight

langDefs/cmake.lang

@@ -6,14 +6,15 @@ Categories = {"config", "script"} Keywords={   { Id=1,     List={-    "if", "elseif", "else", "endif", "foreach", "endforeach", "and", "while", "endwhile", "macro", "endmacro", "function", "endfunction", "set", "unset"+    "if", "elseif", "else", "endif", "foreach", "endforeach", "and", "while", "endwhile",+    "macro", "endmacro", "function", "endfunction", "set", "unset"     },   },   { Id=2,     Regex=[[ [0-9A-Z_]{2,}  ]],   },   { Id=3,-    Regex=[[\$\{.+\$\{[^}]+\}.+?\}|\$\{[^}]+\} ]],+    Regex=[[ \$\{[^{}]*\$\{[^}]+\}[^{}]*?\}|\$\{[^}]+\} ]],   },   { Id=3,     Regex=[[ [A-Z_\>]+\:([\w/]+) ]],

langDefs/d.lang

@@ -41,7 +41,7 @@ Strings={   RawPrefix="r",     Interpolation=[[ %\w ]],     DelimiterPairs= {-      { Open=[[ q"[\[\(\<\{] ]], Close=[[ "[\]\)\>\}] ]], Raw=true }+      { Open=[[ q"[\[\(\<\{] ]], Close=[[ [\]\)\>\}]" ]], Raw=true }     } } 

langDefs/inc_svelteblock.lang

new file mode 100644@@ -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=[[\(|\)|\[|\]|\{|\}|\,|\;|\:|\?|\&|<|>|\!|\=|\/|\*|\%|\+|\-|\~|\||\.]]

langDefs/ini.lang

@@ -16,7 +16,10 @@ Keywords={ }  Strings={-  Delimiter=[["]],+  DelimiterPairs={+    { Open=[[(?<![A-Za-z])"]], Close=[["]] },+    { Open=[[(?<![A-Za-z])']], Close=[['']] },+  }, }  Comments={

langDefs/kdl.lang

new file mode 100644@@ -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

langDefs/m4.lang

new file mode 100644@@ -0,0 +1,87 @@+Description="M4 Macro Language"++Categories = {"source", "script"}++Identifiers=[[ [a-zA-Z_][\w\-]* ]]++Digits=[[ (?:0x|0X)[0-9a-fA-F]+|\d+[\.]?\d* ]]++Keywords={+  -- m4 builtins+  { Id=1,+    List={"builtin", "changecom", "changequote", "changeword", "debugfile", "debugmode", "decr",+        "define", "defn", "divert", "divnum", "dumpdef", "errprint", "esyscmd", "eval", "format",+        "ifdef", "ifelse", "include", "incr", "index", "indir", "len", "m4exit", "m4wrap", "mkstemp",+        "patsubst", "popdef", "pushdef", "regexp", "sinclude", "shift", "substr", "syscmd", "sysval",+        "traceoff", "traceon", "translit", "undefine", "undivert"},+  },+  -- autoconf m4sugar aliases+  { Id=1,+    List={"m4_argn", "m4_append", "m4_append_uniq", "m4_bmatch", "m4_bpatsubst", "m4_bpatsubsts",+        "m4_case", "m4_cond", "m4_copy", "m4_curry", "m4_default", "m4_default_nblank",+        "m4_default_nblank_quoted", "m4_default_quoted", "m4_define", "m4_defn", "m4_divert",+        "m4_divert_once", "m4_divert_pop", "m4_divert_push", "m4_divert_text", "m4_do", "m4_dquote",+        "m4_dquote_elt", "m4_dumpdefs", "m4_dumpvars", "m4_echo", "m4_esyscmd", "m4_esyscmd_s",+        "m4_expand", "m4_fatal", "m4_foreach", "m4_foreach_w", "m4_format", "m4_for", "m4_if",+        "m4_ifblank", "m4_ifdef", "m4_ifnblank", "m4_ifndef", "m4_ifset", "m4_ifval", "m4_ifvaln",+        "m4_include", "m4_index", "m4_input", "m4_join", "m4_joinall", "m4_len", "m4_list_cmp",+        "m4_make", "m4_maketemp", "m4_map", "m4_map_args", "m4_map_args_list", "m4_map_args_pair",+        "m4_map_args_sep", "m4_map_sep", "m4_mapall", "m4_max", "m4_min", "m4_newline",+        "m4_pattern_allow", "m4_pattern_forbid", "m4_popdef", "m4_pushdef", "m4_quote",+        "m4_re_escape", "m4_regexp", "m4_rename", "m4_require", "m4_set_add", "m4_set_add_all",+        "m4_set_contains", "m4_set_contents", "m4_set_delete", "m4_set_difference", "m4_set_dump",+        "m4_set_empty", "m4_set_foreach", "m4_set_intersection", "m4_set_list", "m4_set_listc",+        "m4_set_remove", "m4_set_size", "m4_set_union", "m4_shift", "m4_shift2", "m4_shift3",+        "m4_shiftn", "m4_sinclude", "m4_split", "m4_stack_foreach", "m4_stack_foreach_quit",+        "m4_substr", "m4_symbols", "m4_syscmd", "m4_sysval", "m4_text_box", "m4_text_wrap",+        "m4_tolower", "m4_toupper", "m4_translit", "m4_undefine", "m4_undivert", "m4_unquote",+        "m4_version_compare", "m4_warn"},+  },+  -- shell variables and m4 positional parameters+  { Id=2,+    Regex=[[ \$(?:\{[\w]+\}|[@\w]+|\d+|@|#|\*) ]],+  },+  -- shell control keywords inside embedded script+  { Id=3,+    List={"if", "then", "else", "elif", "fi", "case", "esac", "for", "while", "until", "do", "done",+        "in", "function", "select", "time"},+  },+  -- autoconf macros (AC_*)+  { Id=4,+    Regex=[[\bAC_[A-Z][A-Z0-9_]*\b]],+    Group=0,+  },+  -- automake (AM_), m4sh (AS_) and other Autotools macros+  { Id=5,+    Regex=[[\b(AM|AS|AH|AT|AU|AX|LT|PKG|GL|ND|DUTI)_[A-Z][A-Z0-9_]*\b]],+    Group=0,+  },+  -- shell builtin commands inside embedded script+  { Id=6,+    List={"test", "echo", "shift", "set", "unset", "export", "readonly", "return", "exit", "break",+        "continue", "cd", "printf", "read", "pwd", "trap", "true", "false", "eval", "exec",+        "command", "local"},+  },+}++Strings={+  -- shell double-quoted strings inside embedded script+  Delimiter=[=["]=],+  -- m4 quoting: `...'+  DelimiterPairs={+    { Open=[[`]], Close=[[']] },+  },+}++IgnoreCase=false++Comments={+  { Block=false,+    Delimiter= { [[\bdnl\b]] },+  },+  { Block=false,+    Delimiter= { [[\B#]] },+  },+}++Operators=[[\(|\)|\[|\]|\{|\}|\,|\;|\:|\&|<|>|\!|\=|\/|\*|\%|\+|\-|\$]]

langDefs/nxc.lang

@@ -46,7 +46,7 @@ PreProcessor={ }  NestedSections = {-  { Lang="asm", Delimiter= { [[asm]], [[\}]] } }+  { Lang="nbc", Delimiter= { [[asm]], [[\}]] } } }  Operators=[[\(|\)|\[|\]|\{|\}|\,|\;|\.|\:|\&|<|>|\!|\=|\/|\*|\%|\+|\-|\~]]

langDefs/php.lang

@@ -26,7 +26,7 @@ Keywords={     List={"int", "integer", "real", "double", "float", "string", "array", "object", "bool", "mixed", "numeric", "void" },   },   { Id=3,-    Regex=[[\$[\w\-"|']+|\$?\{.+?\}]],+    Regex=[[\$[\w\-]+|\$?\{.+?\}]],   },   { Id=4,     Regex=[[(\w+)\s*\(]],

langDefs/python.lang

@@ -68,5 +68,9 @@ function OnStateChange(oldState, newState, token, groupID)     return HL_OPERATOR   end +  if newState==HL_INTERPOLATION and oldState~=HL_STRING and oldState~=HL_ESC_SEQ and oldState~=HL_INTERPOLATION then+    return HL_REJECT+  end+   return newState end

langDefs/shellscript.lang

@@ -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 

langDefs/spec.lang

@@ -5,8 +5,8 @@ Categories = {"config", "script"}  Keywords={   { Id=1,-    List={  "Summary", "Name", "Version", "Release", "Copyright", "Group", "URL",-            "Packager", "Prefix", "Distribution", "Vendor",  "Icon", "Provides", "Requires",+    List={  "Summary", "Name", "Epoch", "Version", "Release", "Copyright", "Group", "URL",+            "Packager", "Prefix", "Distribution", "Vendor",  "Icon", "Provides", "BuildRequires", "Requires",             "Serial", "Conflicts", "AutoReqProv", "BuildArch", "ExcludeArch",             "ExclusiveArch", "ExclusiveOS",  "BuildRoot", "NoSource", "NoPatch", "License",             "Buildroot", "Source", "Patch", "case", "in", "esac", "for", "do", "done",

langDefs/svelte.lang

new file mode 100644@@ -0,0 +1,51 @@++Description="Svelte"++Categories = {"markup", "script"}++Keywords={+  { Id=1,+    Regex=[[<[!?]?(?!\-\-)\/?[\w\:\-]+>?|[/?]?>]],+    Group=0,+  },+  { 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=[=[\{[#:\/@]?|\}]=],+    Group=0,+  },+  { Id=4,+    Regex=[[\&\#?\w+;]],+  },+}++Strings={+  Delimiter=[["]],+  -- see http://stackoverflow.com/questions/1723182/a-regex-that-will-never-be-matched-by-anything+  Escape=[[\A(?!x)x]]+}++Comments={+  { Block=true,+    Nested=false,+    Delimiter= { [[<!\-\-]],[[\-\->]] }+  }+}++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+  { Lang="typescript", Delimiter= { [[<script[^>]*lang=["']ts["'][^>]*>]], [[<\/script>]] } },+}

langDefs/vue.lang

@@ -14,8 +14,10 @@ Keywords={  NestedSections = { -  { Lang="css", Delimiter= { [[<style>]], [[<\/style>]] } },-  { Lang="js", Delimiter= { [[<script>]], [[<\/script>]] } },-  { Lang="html", Delimiter= { [[ <template>]], [[<\/template>]]  } },+  { Lang="css", Delimiter= { [[<style[^>]*>]], [[<\/style>]] } },+  { Lang="html", Delimiter= { [[<template[^>]*>]], [[<\/template>]] } },+  { Lang="javascript", Delimiter= { [[<script[^>]*>]], [[<\/script>]] } },+  -- must come after the generic entry: the last matching delimiter wins+  { Lang="typescript", Delimiter= { [[<script[^>]*lang=["']ts["'][^>]*>]], [[<\/script>]] } }, } 

makefile

@@ -66,7 +66,7 @@ RMDIR=rm -r -f all cli: 	${MAKE} -C ./src -f ./makefile HL_DATA_DIR=${hl_data_dir} HL_CONFIG_DIR=${hl_conf_dir} -lib lib-static:+lib lib-static libhighlight.a: 	${MAKE} -C ./src -f ./makefile HL_DATA_DIR=${hl_data_dir} HL_CONFIG_DIR=${hl_conf_dir} lib-static  lib-shared:@@ -170,6 +170,7 @@ install-gui: 	${INSTALL_PROGRAM} ./src/highlight-gui ${DESTDIR}${bin_dir}  install-lib-shared:+	${MKDIR} ${DESTDIR}${lib_dir} 	${INSTALL_DATA} ./src/libhighlight.so.4.0 ${DESTDIR}${lib_dir}  uninstall:

man/highlight.1

@@ -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"@@ -105,12 +109,16 @@ print line numbers in output file start line numbering with cnt (assumes -l) .IP "\fB--line-range\fR=<\fIstart\fR-\fIend\fR>" output only lines from number <start> to <end>+.IP "\fB--indent-guides\fR"+draw a guide in the leading whitespace of every indentation level. Blank lines inside a block take the indentation of the next line which contains code.+The guides use the IndentGuide theme element, or a dimmed default if the theme does not define one (plain ansi output always uses the dimmed default); implies \fB-t 4\fR if no tab width was set .IP "\fB-s\fR, \fB--style\fR=<\fIstyle name\fR|\fIpath\fR>" set highlighting style (theme). Add 'base16/' prefix to use a Base16 theme. The theme may also be defined as path of the theme file. .IP "\fB-t\fR  \fB--replace-tabs\fR=<\fInum\fR>" replace tabs by num spaces .IP "\fB-u\fR, \fB--encoding\fR=<\fIenc\fR>"-set output encoding which matches input file encoding; omit encoding information if set to "NONE"+set output encoding which matches input file encoding; omit encoding information if set to "NONE".+Input starting with a UTF-16 or UTF-32 byte order mark is converted to UTF-8, and the output encoding is set to utf-8 for this file (unless "NONE") .IP "\fB-V\fR, \fB--wrap-simple\fR" wrap lines after 80 (default) characters without indenting function parameters and statements. .IP "\fB-W\fR, \fB--wrap\fR"

plugins/color_swatches.lua

new file mode 100644@@ -0,0 +1,277 @@+--[[+Colour swatches: shows a small box filled with the colour next to colour+literals, like VSCode's colour decorators or Vim's hexokinase plug-in.++Recognized literals (in code and strings, but not in comments):+  #rgb, #rgba, #rrggbb, #rrggbbaa+  rgb(r, g, b), rgba(r, g, b, a), rgb(r g b / a)   (numbers or percentages)++Supported output formats: HTML, XHTML, SVG, Pango, BBCode, Truecolor and+xterm256 escape sequences.++Can be combined with other plug-ins which define a Decorate function+(e.g. rainbow_brackets.lua).++Note: highlight copies the Decorate function without its upvalues, so all+state is kept in the global table ColorSwatches instead of local variables.+]]++Description="Adds colour swatches next to hex and rgb() colour literals (HTML, SVG, Pango, BBCode, Truecolor, xterm256)."++Categories = {"format", "html", "svg", "pango", "bbcode", "truecolor", "xterm256", "usability" }++function syntaxUpdate(desc)++  if HL_OUTPUT ~= HL_FORMAT_HTML and HL_OUTPUT ~= HL_FORMAT_XHTML+      and HL_OUTPUT ~= HL_FORMAT_SVG and HL_OUTPUT ~= HL_FORMAT_PANGO+      and HL_OUTPUT ~= HL_FORMAT_BBCODE+      and HL_OUTPUT ~= HL_FORMAT_TRUECOLOR and HL_OUTPUT ~= HL_FORMAT_XTERM256 then+    return+  end++  -- do not chain twice if the chunk is evaluated again in the same state+  if ColorSwatches then+    return+  end++  ColorSwatches = {+    SWATCH_CHAR = "\226\150\160",  -- U+25A0 BLACK SQUARE++    isEscOutput = (HL_OUTPUT == HL_FORMAT_TRUECOLOR or HL_OUTPUT == HL_FORMAT_XTERM256),++    -- hex literal inside strings: split into "#", "00", "ff00", ... tokens+    hexBuf = nil,    -- collected hex digits after a "#", nil if inactive+    hexNextCol = 0,  -- column where the next adjacent hex token has to start++    -- rgb()/rgba(): split into name, parentheses, numbers and separators+    fnState = nil,   -- nil, "name" (rgb/rgba seen), "args" (inside parentheses)+    fnArgs = {},     -- collected arguments as { value, isPercent }++    prevDecorate = Decorate,+    prevDecorateLineEnd = DecorateLineEnd,+  }++  function ColorSwatches.resetFunction()+    ColorSwatches.fnState = nil+    ColorSwatches.fnArgs = {}+  end++  function ColorSwatches.clamp(v, lo, hi)+    if v < lo then return lo end+    if v > hi then return hi end+    return v+  end++  -- returns r, g, b (0-255) and alpha (0-1), or nil+  function ColorSwatches.parseHex(hex)+    local n = #hex+    if string.find(hex, "^%x+$") == nil or (n ~= 3 and n ~= 4 and n ~= 6 and n ~= 8) then+      return nil+    end+    if n <= 4 then+      hex = string.gsub(hex, "(%x)", "%1%1")+    end+    local r = tonumber(string.sub(hex, 1, 2), 16)+    local g = tonumber(string.sub(hex, 3, 4), 16)+    local b = tonumber(string.sub(hex, 5, 6), 16)+    local a = 1+    if #hex == 8 then+      a = tonumber(string.sub(hex, 7, 8), 16) / 255+    end+    return r, g, b, a+  end++  function ColorSwatches.rgbFromArgs(args)+    local clamp = ColorSwatches.clamp+    if #args ~= 3 and #args ~= 4 then+      return nil+    end+    local c = {}+    for i = 1, 3 do+      local v = args[i].value+      if args[i].isPercent then v = v * 2.55 end+      c[i] = math.floor(clamp(v, 0, 255) + 0.5)+    end+    local a = 1+    if args[4] then+      a = args[4].value+      if args[4].isPercent then a = a / 100 end+      a = clamp(a, 0, 1)+    end+    return c[1], c[2], c[3], a+  end++  function ColorSwatches.swatch(r, g, b, a)+    local box = ColorSwatches.SWATCH_CHAR++    if HL_OUTPUT == HL_FORMAT_HTML or HL_OUTPUT == HL_FORMAT_XHTML then+      return string.format('<span style="display:inline-block;width:0.8em;height:0.8em;'+        ..'margin:0 0.25em;vertical-align:middle;border:1px solid #808080;'+        ..'background-color:rgba(%d,%d,%d,%.3g)"></span>', r, g, b, a)+    end++    local hex = string.format("#%02x%02x%02x", r, g, b)+    if HL_OUTPUT == HL_FORMAT_SVG then+      return ' <tspan fill="'..hex..'">'..box..'</tspan> '+    elseif HL_OUTPUT == HL_FORMAT_PANGO then+      return ' <span foreground="'..hex..'">'..box..'</span> '+    elseif HL_OUTPUT == HL_FORMAT_BBCODE then+      return ' [color='..hex..']'..box..'[/color] '+    elseif HL_OUTPUT == HL_FORMAT_TRUECOLOR then+      return string.format(" \x1B[38;2;%d;%d;%dm", r, g, b)..box+    elseif HL_OUTPUT == HL_FORMAT_XTERM256 then+      local idx = 16 + 36 * math.floor(r * 5 / 255 + 0.5)+                     + 6 * math.floor(g * 5 / 255 + 0.5)+                     + math.floor(b * 5 / 255 + 0.5)+      return " \x1B[38;5;"..idx.."m"..box+    end+    return ""+  end++  -- tokens returned by Decorate are not escaped by highlight+  function ColorSwatches.escapeToken(token)+    if HL_OUTPUT == HL_FORMAT_HTML or HL_OUTPUT == HL_FORMAT_XHTML+        or HL_OUTPUT == HL_FORMAT_SVG or HL_OUTPUT == HL_FORMAT_PANGO then+      token = string.gsub(token, "&", "&amp;")+      token = string.gsub(token, "<", "&lt;")+      token = string.gsub(token, ">", "&gt;")+      token = string.gsub(token, '"', "&quot;")+    end+    return token+  end++  -- finishes a pending hex literal; returns its swatch or nil+  function ColorSwatches.flushHex()+    local cs = ColorSwatches+    local buf = cs.hexBuf+    cs.hexBuf = nil+    if buf then+      local r, g, b, a = cs.parseHex(buf)+      if r then+        return cs.swatch(r, g, b, a)+      end+    end+    return nil+  end++  -- handles rgb()/rgba(); returns a swatch if the closing parenthesis completes a colour+  function ColorSwatches.handleFunction(token)+    local cs = ColorSwatches++    if cs.fnState == nil then+      local name = string.lower(token)+      if name == "rgb" or name == "rgba" then+        cs.fnState = "name"+      end+      return nil+    end++    if cs.fnState == "name" then+      if token == "(" then+        cs.fnState = "args"+      else+        cs.resetFunction()+      end+      return nil+    end++    -- fnState == "args"+    local num, pct = string.match(token, "^(%d*%.?%d+)(%%?)$")+    if num then+      cs.fnArgs[#cs.fnArgs+1] = { value = tonumber(num), isPercent = (pct == "%") }+    elseif token == "%" and #cs.fnArgs > 0 then+      cs.fnArgs[#cs.fnArgs].isPercent = true+    elseif token == ")" then+      local r, g, b, a = cs.rgbFromArgs(cs.fnArgs)+      cs.resetFunction()+      if r then+        return cs.swatch(r, g, b, a)+      end+    elseif token ~= "," and token ~= "/" then+      cs.resetFunction()+    end+    return nil+  end++  -- returns prefix and suffix to be placed around the current token+  function ColorSwatches.getSwatches(token, state, column)+    local cs = ColorSwatches++    if state == HL_BLOCK_COMMENT or state == HL_LINE_COMMENT then+      cs.hexBuf = nil+      cs.resetFunction()+      return nil, nil+    end++    -- complete hex literal in a single token, e.g. CSS numbers+    local hex = string.match(token, "^#(%x+)$")+    if hex then+      local pending = cs.flushHex()+      cs.resetFunction()+      local r, g, b, a = cs.parseHex(hex)+      return pending, r and cs.swatch(r, g, b, a) or nil+    end++    -- collect adjacent hex digit tokens after a "#"+    if cs.hexBuf and column == cs.hexNextCol and string.find(token, "^%x+$") then+      cs.hexBuf = cs.hexBuf..token+      cs.hexNextCol = column + #token+      return nil, nil+    end++    -- any other token terminates a pending hex literal+    local pending = cs.flushHex()++    if token == "#" then+      cs.hexBuf = ""+      cs.hexNextCol = column + 1+      cs.resetFunction()+      return pending, nil+    end++    return pending, cs.handleFunction(token)+  end++  function Decorate(token, state, kwGroupID, lineHasStmt, lineno, column)+    local cs = ColorSwatches+    local prevRes+    if cs.prevDecorate then+      prevRes = cs.prevDecorate(token, state, kwGroupID, lineHasStmt, lineno, column)+    end++    -- whitespace is reported as empty tokens and must not break up literals+    if #token > 0 and string.find(token, "^%s*$") == nil then+      local prefix, suffix = cs.getSwatches(token, state, column or -1)++      -- terminal colours cannot be restored after a prefix, so append it instead+      if prefix and cs.isEscOutput then+        suffix = prefix..(suffix or "")+        prefix = nil+      end++      if prefix or suffix then+        return (prefix or "")..(prevRes or cs.escapeToken(token))..(suffix or "")+      end+    end++    if prevRes then+      return prevRes+    end+  end++  -- a hex literal may end the line (e.g. unterminated strings)+  function DecorateLineEnd(lineNumber)+    local cs = ColorSwatches+    local res = cs.flushHex() or ""+    if cs.prevDecorateLineEnd then+      res = res..(cs.prevDecorateLineEnd(lineNumber) or "")+    end+    if #res > 0 then+      return res+    end+  end+end++Plugins={+  { Type="lang", Chunk=syntaxUpdate },+}

plugins/rainbow_brackets.lua

new file mode 100644@@ -0,0 +1,177 @@+--[[+Rainbow brackets: colours (), [] and {} by their nesting depth, like+VSCode's bracket pair colorization or Vim's rainbow plug-ins.++Closing brackets without a matching opening bracket are marked in red.++Optional plug-in parameter: comma separated list of hex colours used for the+nesting levels, e.g. --plug-in-param="#ffd700,#da70d6,#179fff"+Without parameter, a palette is chosen based on the theme's canvas colour.++Supported output formats: HTML, XHTML, SVG, Pango, BBCode, Truecolor and+xterm256 escape sequences.++Can be combined with other plug-ins which define a Decorate function+(e.g. color_swatches.lua).++Note: highlight copies the Decorate function without its upvalues, so all+state is kept in the global table RainbowBrackets instead of local variables.+]]++Description="Colours brackets by their nesting depth (HTML, SVG, Pango, BBCode, Truecolor, xterm256)."++Categories = {"format", "html", "svg", "pango", "bbcode", "truecolor", "xterm256", "usability" }++function syntaxUpdate(desc)++  if HL_OUTPUT ~= HL_FORMAT_HTML and HL_OUTPUT ~= HL_FORMAT_XHTML+      and HL_OUTPUT ~= HL_FORMAT_SVG and HL_OUTPUT ~= HL_FORMAT_PANGO+      and HL_OUTPUT ~= HL_FORMAT_BBCODE+      and HL_OUTPUT ~= HL_FORMAT_TRUECOLOR and HL_OUTPUT ~= HL_FORMAT_XTERM256 then+    return+  end++  -- do not chain twice if the chunk is evaluated again in the same state+  if RainbowBrackets then+    return+  end++  RainbowBrackets = {+    -- VSCode default bracket pair colours+    darkPalette  = { "#ffd700", "#da70d6", "#179fff" },+    lightPalette = { "#0431fa", "#319331", "#7b3814" },+    unmatchedColour = "#ff1212",++    openers = { ["("]=")", ["["]="]", ["{"]="}" },+    closers = { [")"]=true, ["]"]=true, ["}"]=true },+    stack   = {},   -- currently open brackets+    palette = nil,  -- resolved lazily, after the theme chunk stored its value++    prevDecorate = Decorate,+  }++  function RainbowBrackets.parsePalette(param)+    local p = {}+    for c in string.gmatch(param, "#?%x%x%x%x%x%x") do+      if string.sub(c, 1, 1) ~= "#" then c = "#"..c end+      p[#p+1] = string.lower(c)+    end+    return p+  end++  function RainbowBrackets.getPalette()+    local rb = RainbowBrackets+    if rb.palette then return rb.palette end+    if HL_PLUGIN_PARAM and #HL_PLUGIN_PARAM > 0 then+      rb.palette = rb.parsePalette(HL_PLUGIN_PARAM)+    end+    if not rb.palette or #rb.palette == 0 then+      rb.palette = (StoreValue("rbLightCanvas") == "1") and rb.lightPalette or rb.darkPalette+    end+    return rb.palette+  end++  function RainbowBrackets.colourize(token, colour)+    local r = tonumber(string.sub(colour, 2, 3), 16)+    local g = tonumber(string.sub(colour, 4, 5), 16)+    local b = tonumber(string.sub(colour, 6, 7), 16)++    if HL_OUTPUT == HL_FORMAT_HTML or HL_OUTPUT == HL_FORMAT_XHTML then+      return '<span style="color:'..colour..'">'..token..'</span>'+    elseif HL_OUTPUT == HL_FORMAT_SVG then+      return '<tspan fill="'..colour..'">'..token..'</tspan>'+    elseif HL_OUTPUT == HL_FORMAT_PANGO then+      return '<span foreground="'..colour..'">'..token..'</span>'+    elseif HL_OUTPUT == HL_FORMAT_BBCODE then+      return '[color='..colour..']'..token..'[/color]'+    elseif HL_OUTPUT == HL_FORMAT_TRUECOLOR then+      return string.format("\x1B[38;2;%d;%d;%dm", r, g, b)..token+    elseif HL_OUTPUT == HL_FORMAT_XTERM256 then+      local idx = 16 + 36 * math.floor(r * 5 / 255 + 0.5)+                     + 6 * math.floor(g * 5 / 255 + 0.5)+                     + math.floor(b * 5 / 255 + 0.5)+      return "\x1B[38;5;"..idx.."m"..token+    end+    return token+  end++  function RainbowBrackets.colourForDepth(depth)+    local p = RainbowBrackets.getPalette()+    return p[(depth - 1) % #p + 1]+  end++  -- returns the coloured brackets or nil if the token is not a bracket operator+  function RainbowBrackets.colourBrackets(token, state)+    local rb = RainbowBrackets++    if state ~= HL_OPERATOR then+      return nil+    end++    -- only handle tokens which consist of brackets exclusively, so that no+    -- other operator characters need to be escaped or recoloured+    if string.find(token, "^[%(%)%[%]{}]+$") == nil then+      return nil+    end++    local out = {}+    for ch in string.gmatch(token, ".") do+      if rb.openers[ch] then+        rb.stack[#rb.stack+1] = ch+        out[#out+1] = rb.colourize(ch, rb.colourForDepth(#rb.stack))+      else+        local top = rb.stack[#rb.stack]+        if top and rb.openers[top] == ch then+          out[#out+1] = rb.colourize(ch, rb.colourForDepth(#rb.stack))+          rb.stack[#rb.stack] = nil+        else+          out[#out+1] = rb.colourize(ch, rb.unmatchedColour)+        end+      end+    end+    return table.concat(out)+  end++  function Decorate(token, state, kwGroupID, lineHasStmt, lineno, column)+    local rb = RainbowBrackets+    local prevRes+    if rb.prevDecorate then+      prevRes = rb.prevDecorate(token, state, kwGroupID, lineHasStmt, lineno, column)+    end++    local coloured = rb.colourBrackets(token, state)+    if coloured then+      if prevRes == nil then+        return coloured+      end+      -- keep additions of other plug-ins which were appended to the token+      if string.sub(prevRes, 1, #token) == token then+        return coloured..string.sub(prevRes, #token + 1)+      end+    end++    if prevRes then+      return prevRes+    end+  end+end++function themeUpdate(desc)+  local canvas = Canvas and Canvas.Colour or ""+  local light = "0"+  if string.match(canvas, "^#%x%x%x%x%x%x") then+    local r = tonumber(string.sub(canvas, 2, 3), 16)+    local g = tonumber(string.sub(canvas, 4, 5), 16)+    local b = tonumber(string.sub(canvas, 6, 7), 16)+    -- perceived luminance (ITU-R BT.601)+    if (0.299 * r + 0.587 * g + 0.114 * b) > 128 then+      light = "1"+    end+  end+  StoreValue("rbLightCanvas", light)+end++Plugins={+  { Type="lang", Chunk=syntaxUpdate },+  { Type="theme", Chunk=themeUpdate },+}

sh-completion/gen-completions

@@ -80,12 +80,16 @@ parser:option "-F --reformat"    :choices {"allman", "gnu", "google", "horstmann", "java", "kr", "linux", "lisp", "mozilla", "otbs", "pico", "vtk", "ratliff", "stroustrup", "webkit", "whitesmith"} parser:flag "-I --include-style"    :description "include style definition in output file"+parser:flag "--indent-guides"+   :description "draw guides in leading whitespace (implies -t 4)" parser:option "-J --line-length"    :description "line length before wrapping (see -V, -W)" parser:option "-j --line-number-length"    :description "line number width incl. left padding (default: 5)" parser:option "--line-range"    :description "output only lines from number <start> to <end>"+parser:option "--skip-leading-cols"+   :description "output the first <num> columns of each line" parser:option "-k --font"    :description "set font (specific to output format)" parser:option "-K --font-size"

sh-completion/highlight.bash

@@ -4,7 +4,7 @@ _highlight() {     args=("${COMP_WORDS[@]}")     cur="${COMP_WORDS[COMP_CWORD]}"     prev="${COMP_WORDS[COMP_CWORD-1]}"-    opts="-B --batch-recursive -D --data-dir --config-file -d --outdir -h --help -i --input -o --output -P --progress -q --quiet -S --syntax --syntax-by-name --syntax-supported -v --verbose --force --list-scripts --list-cat --max-size --plug-in --plug-in-param --print-config --print-style --skip --stdout --validate-input --version -O --out-format -c --style-outfile -e --style-infile -f --fragment -F --reformat -I --include-style -J --line-length -j --line-number-length --line-range -k --font -K --font-size -l --line-numbers -m --line-number-start -s --style -t --replace-tabs -T --doc-title -u --encoding -V --wrap-simple -W --wrap --wrap-no-numbers -z --zeroes --isolate --keep-injections --kw-case --no-trailing-nl --no-version-info -a --anchors -y --anchor-prefix -N --anchor-filename -C --print-index -n --ordered-list --class-name --inline-css --enclose-pre -b --babel -r --replace-quotes --beamer --pretty-symbols --page-color -x --page-size --char-styles --height --width --canvas --ls-profile --ls-delay --ls-exec --ls-option --ls-hover --ls-semantic --ls-syntax --ls-syntax-error --ls-workspace --ls-legacy --service-mode"+    opts="-B --batch-recursive -D --data-dir --config-file -d --outdir -h --help -i --input -o --output -P --progress -q --quiet -S --syntax --syntax-by-name --syntax-supported -v --verbose --force --list-scripts --list-cat --max-size --plug-in --plug-in-param --print-config --print-style --skip --stdout --validate-input --version -O --out-format -c --style-outfile -e --style-infile -f --fragment -F --reformat -I --include-style --indent-guides -J --line-length -j --line-number-length --line-range --skip-leading-cols -k --font -K --font-size -l --line-numbers -m --line-number-start -s --style -t --replace-tabs -T --doc-title -u --encoding -V --wrap-simple -W --wrap --wrap-no-numbers -z --zeroes --isolate --keep-injections --kw-case --no-trailing-nl --no-version-info -a --anchors -y --anchor-prefix -N --anchor-filename -C --print-index -n --ordered-list --class-name --inline-css --enclose-pre -b --babel -r --replace-quotes --beamer --pretty-symbols --page-color -x --page-size --char-styles --height --width --canvas --ls-profile --ls-delay --ls-exec --ls-option --ls-hover --ls-semantic --ls-syntax --ls-syntax-error --ls-workspace --ls-legacy --service-mode"      case "$prev" in         -B|--batch-recursive)@@ -95,6 +95,10 @@ _highlight() {             COMPREPLY=($(compgen -f -- "$cur"))             return 0             ;;+        --skip-leading-cols)+            COMPREPLY=($(compgen -f -- "$cur"))+            return 0+            ;;         -k|--font)             COMPREPLY=($(compgen -f -- "$cur"))             return 0

sh-completion/highlight.fish

@@ -31,9 +31,11 @@ complete -c highlight -s e -l style-infile -r -d 'to be included in style-outfil complete -c highlight -s f -l fragment -d 'omit document header and footer' complete -c highlight -s F -l reformat -xa 'allman gnu google horstmann java kr linux lisp mozilla otbs pico vtk ratliff stroustrup webkit whitesmith' -d 'reformats and indents output in given style' complete -c highlight -s I -l include-style -d 'include style definition in output file'+complete -c highlight -l indent-guides -d 'draw guides in leading whitespace (implies -t 4)' complete -c highlight -s J -l line-length -r -d 'line length before wrapping (see -V, -W)' complete -c highlight -s j -l line-number-length -r -d 'line number width incl' complete -c highlight -l line-range -r -d 'output only lines from number <start> to <end>'+complete -c highlight -l skip-leading-cols -r -d 'output the first <num> columns of each line' complete -c highlight -s k -l font -r -d 'set font (specific to output format)' complete -c highlight -s K -l font-size -d 'set font size (specific to output format)' complete -c highlight -s l -l line-numbers -d 'print line numbers in output file'

sh-completion/highlight.zsh

@@ -34,9 +34,11 @@ _highlight() {     {-f,--fragment}"[omit document header and footer]"     {-F,--reformat}"[reformats and indents output in given style]: :(allman gnu google horstmann java kr linux lisp mozilla otbs pico vtk ratliff stroustrup webkit whitesmith)"     {-I,--include-style}"[include style definition in output file]"+    "--indent-guides[draw guides in leading whitespace (implies -t 4)]"     {-J,--line-length}"[line length before wrapping (see -V, -W)]: :_files"     {-j,--line-number-length}"[line number width incl]: :_files"     "--line-range[output only lines from number <start> to <end>]: :_files"+    "--skip-leading-cols[output the first <num> columns of each line]: :_files"     {-k,--font}"[set font (specific to output format)]: :_files"     {-K,--font-size}"[set font size (specific to output format)]: :_files"     {-l,--line-numbers}"[print line numbers in output file]"

src/cli/cmdlineoptions.cpp

@@ -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_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@@ -140,12 +141,14 @@ const Arg_parser::Option options[] = {         { S_OPT_ABS_CFG_PATH,     OPT_ABS_CFG_PATH,    Arg_parser::yes},         { S_OPT_LIST_SCRIPTS,     OPT_LIST_SCRIPTS,    Arg_parser::yes},         { S_OPT_CANVAS,           OPT_CANVAS,          Arg_parser::maybe },+        { S_OPT_INDENT_GUIDES,    OPT_INDENT_GUIDES,   Arg_parser::no },         { S_OPT_REFORMAT_OPT,     OPT_REFORMAT_OPT,    Arg_parser::yes },         { S_OPT_RANGE_OPT,        OPT_RANGE_OPT,       Arg_parser::yes },         { S_OPT_CATEGORIES,       OPT_CATEGORIES,      Arg_parser::yes },         { 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 },@@ -582,6 +585,10 @@ void CmdLineOptions::parseRuntimeOptions( const int argc, const char *argv[], bo         case S_OPT_LIST_SCRIPTS:             listScriptType=arg;             break;+        case S_OPT_INDENT_GUIDES:+            indentGuides=true;+            if (!numberSpaces) numberSpaces=4; // guides need tab expansion to know the column+            break;         case S_OPT_CANVAS:             canvasPaddingWidth=80;             numberSpaces=4; // get around problem with maskWs and tab output@@ -609,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;@@ -914,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 );@@ -1126,6 +1141,11 @@ int CmdLineOptions::getCanvasPadding()     return canvasPaddingWidth; } +bool CmdLineOptions::showIndentGuides() const+{+    return indentGuides;+}+ int CmdLineOptions::getLineRangeStart() {     return lineRangeStart;

src/cli/cmdlineoptions.h

@@ -109,6 +109,7 @@ along with Highlight.  If not, see <http://www.gnu.org/licenses/>. #define OPT_FORCE_STDOUT     "stdout" #define OPT_NO_VERSION_INFO  "no-version-info" #define OPT_CANVAS           "canvas"+#define OPT_INDENT_GUIDES    "indent-guides" #define OPT_REFORMAT_OPT     "reformat-option" #define OPT_RANGE_OPT        "line-range" #define OPT_BASE16           "base16"@@ -116,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"@@ -383,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 ; @@ -465,6 +470,9 @@ public:     /** \return ANSI background color padding width */     int getCanvasPadding(); +    /** @return true if indentation guides should be drawn */+    bool showIndentGuides() const;+     /** \return line range start */     int getLineRangeStart(); @@ -488,6 +496,8 @@ private:      unsigned int canvasPaddingWidth{0};    // line number start count +    bool indentGuides{false};+     highlight::WrapMode wrappingStyle{ highlight::WRAP_DISABLED }; // line wrapping mode     highlight::OutputType outputType{ highlight::HTML };     StringTools::KeywordCase keywordCase{ StringTools::CASE_UNCHANGED };@@ -566,6 +576,8 @@ private:      off_t maxFileSize{268435456}; +    unsigned int skipLeadingCols{0};+     std::string fallbackSyntax, anchorPrefix;     std::string helpLang, encodingName; 

src/cli/help.cpp

@@ -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";@@ -192,6 +194,7 @@ void printHelp(const std::string &topic)         std::cout<<" -m, --line-number-start=<cnt>  start line numbering with cnt (assumes -l)\n";         std::cout<<" -s, --style=<style|path>       set colour style (theme) or theme file path\n";         std::cout<<" -t, --replace-tabs=<num>       replace tabs by <num> spaces\n";+        std::cout<<"     --indent-guides            draw guides in leading whitespace (implies -t 4)\n";         std::cout<<" -T, --doc-title=<title>        document title\n";         std::cout<<" -u, --encoding=<enc>           set output encoding which matches input file\n";         std::cout<<"                                  encoding; omit encoding info if set to NONE\n";

src/cli/main.cpp

@@ -38,6 +38,7 @@ along with Highlight.  If not, see <http://www.gnu.org/licenses/>. #include "datadir.h" #include "syntaxreader.h" #include "lspprofile.h"+#include "stringtools.h"  using std::cerr; using std::cin;@@ -97,7 +98,7 @@ int HLCmdLineApp::printInstalledFiles(const std::string& where, const std::strin     bool directoryOK = Platform::getDirectoryEntries ( filePaths, searchDir, true );     if ( !directoryOK ) {         std::cerr << "highlight: Could not access directory "-             <<  searchDir+             <<  StringTools::sanitizeForTerminal(searchDir)              << ", aborted.\n";         return EXIT_FAILURE;     }@@ -108,9 +109,9 @@ int HLCmdLineApp::printInstalledFiles(const std::string& where, const std::strin     std::cout << "\nInstalled " << kind << "s";      if (categoryFilterList.size())-        std::cout << " matching \""<<categoryFilterList<<"\"";+        std::cout << " matching \""<< StringTools::sanitizeForTerminal(categoryFilterList) <<"\""; -    std::cout << " (located in " << where << "):\n\n";+    std::cout << " (located in " << StringTools::sanitizeForTerminal(where) << "):\n\n";     int matchedFileCnt=0;     std::set<string> categoryNames;     std::set<string> categoryFilters;@@ -127,10 +128,11 @@ int HLCmdLineApp::printInstalledFiles(const std::string& where, const std::strin             Diluculum::LuaState ls;             highlight::SyntaxReader::initLuaState(ls, path,"");             ls.doFile(path);-            desc = ls["Description"].value().asString();+            desc = StringTools::sanitizeForTerminal(ls["Description"].value().asString());              suffix = ( path ).substr ( where.length() ) ;             suffix = suffix.substr ( 0, suffix.length()- wildcard.length()+1 );+            suffix = StringTools::sanitizeForTerminal(suffix);              unsigned int filterOKCnt=categoryFilters.size();             if (ls["Categories"].value() !=Diluculum::Nil){@@ -156,7 +158,7 @@ int HLCmdLineApp::printInstalledFiles(const std::string& where, const std::strin                 int extCnt=0;                 for (const auto &[first, second] : dataDir.assocByExtension) {                     if (second==suffix ) {-                        std::cout << ((++extCnt==1)?" ( ":" ") << first;+                        std::cout << ((++extCnt==1)?" ( ":" ") << StringTools::sanitizeForTerminal(first);                     }                 }                 std::cout << ((extCnt)?" )":"");@@ -166,7 +168,7 @@ int HLCmdLineApp::printInstalledFiles(const std::string& where, const std::strin             }             std::cout << endl;         } catch (std::runtime_error &error) {-            std::cout << "Failed to read '" << path << "': " << error.what() << endl;+            std::cout << "Failed to read '" << StringTools::sanitizeForTerminal(path) << "': " << StringTools::sanitizeForTerminal(error.what()) << endl;         }     } @@ -177,7 +179,7 @@ int HLCmdLineApp::printInstalledFiles(const std::string& where, const std::strin         if (!categoryFilters.size()){             std::cout << "\nFound "<<kind<<" categories:\n\n";             for ( const auto &catName : categoryNames)-                std::cout << catName << ' ';+                std::cout << StringTools::sanitizeForTerminal(catName) << ' ';             std::cout << "\n";         } @@ -201,8 +203,8 @@ void HLCmdLineApp::printDebugInfo ( const highlight::SyntaxReader *lang,      map <int, string> HLStateMap; -    cerr << "\nLoading language definition:\n" << langDefPath;-    cerr << "\n\nDescription: " << lang->getDescription();+    cerr << "\nLoading language definition:\n" << StringTools::sanitizeForTerminal(langDefPath);+    cerr << "\n\nDescription: " << StringTools::sanitizeForTerminal(lang->getDescription());     if (level>1) {          if (auto luaState = lang->getLuaState(); luaState) {@@ -211,10 +213,10 @@ void HLCmdLineApp::printDebugInfo ( const highlight::SyntaxReader *lang,              for (const auto &[first, second] : glob) {                 auto elemName = first.asString();-                std::cerr << elemName << ": ";+                std::cerr << StringTools::sanitizeForTerminal(elemName) << ": ";                 switch (second.type()) {                     case  LUA_TSTRING:-                        cerr << "string [ "<<second.asString()<<" ]";+                        cerr << "string [ "<< StringTools::sanitizeForTerminal(second.asString()) <<" ]";                         break;                     case  LUA_TNUMBER:                         cerr << "number [ "<<second.asNumber()<<" ]";@@ -234,13 +236,13 @@ void HLCmdLineApp::printDebugInfo ( const highlight::SyntaxReader *lang,         if (auto regexElements = lang->getRegexElements(); !regexElements.empty()) {             std::cerr << "\nREGEX:\n";             for (const auto *re : regexElements)-                std::cerr << "State " << re->open << " (" << HLStateMap[re->open] << "):\t" << re->pattern << "\n";+                std::cerr << "State " << re->open << " (" << StringTools::sanitizeForTerminal(HLStateMap[re->open]) << "):\t" << StringTools::sanitizeForTerminal(re->pattern) << "\n";         }          if (auto keys = lang->getKeywords(); !keys.empty()) {             std::cerr << "\nKEYWORDS:\n";             for (const auto &[keyword, value] : keys)-                std::cerr << " " << keyword << "(" << value << ")";+                std::cerr << " " << StringTools::sanitizeForTerminal(keyword) << "(" << value << ")";         }     }     cerr <<"\n\n";@@ -294,7 +296,7 @@ void HLCmdLineApp::printCurrentAction ( const string&outfilePath,          << " of "          << total          << ": "-         << outfilePath+         << StringTools::sanitizeForTerminal(outfilePath)          << "\n"; } @@ -311,7 +313,9 @@ void HLCmdLineApp::printIOErrorReport ( unsigned int numberErrorFiles,         cerr<<streamName<<"\n";     }     else {-        copy ( fileList.begin(), fileList.end(), ostream_iterator<string> ( cerr, "\n" ) );+        for (const auto& file : fileList) {+            cerr << StringTools::sanitizeForTerminal(file) << "\n";+        }     }      if ( fileList.size() < numberErrorFiles ) {@@ -344,7 +348,7 @@ bool HLCmdLineApp::serviceModeCheck(CmdLineOptions &options, highlight::CodeGene      cerr << flush;     if (! service_mode_tag.empty())-        std::cout << service_mode_tag << endl;+        std::cout << StringTools::sanitizeForTerminal(service_mode_tag) << endl;      std::cout << flush; @@ -405,10 +409,10 @@ bool HLCmdLineApp::serviceModeCheck(CmdLineOptions &options, highlight::CodeGene             service_mode_tag = modeVal;             modeRes += "Tag: " + service_mode_tag + " ";         } else if (modeKey.length() )-            cerr << "Invalid service mode key change of: " << modeKey << " ignoring." << endl;+            cerr << "Invalid service mode key change of: " << StringTools::sanitizeForTerminal(modeKey) << " ignoring." << endl;     }     if (options.verbosityLevel())-        cerr << "Updated Items: " << modeRes << endl;+        cerr << "Updated Items: " << StringTools::sanitizeForTerminal(modeRes) << endl;      return true; }@@ -484,7 +488,7 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )             if (lsLegacy==false)                 lsLegacy = profile.legacy;         } else {-            cerr << "highlight: Unknown LSP profile '"<< lsProfile << "'.\n";+            cerr << "highlight: Unknown LSP profile '"<< StringTools::sanitizeForTerminal(lsProfile) << "'.\n";             return EXIT_FAILURE;         }     }@@ -500,7 +504,7 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )         else if (  scriptKind.find("lang")==0 ) {             return printInstalledFiles(dataDir.getLangPath(""), "*.lang", "langDef", OPT_SYNTAX, options.getCategories());         } else {-            cerr << "highlight: Unknown script type '"<< scriptKind << "'. Apply one of 'themes', 'langs' or 'plug-ins'.\n";+            cerr << "highlight: Unknown script type '"<< StringTools::sanitizeForTerminal(scriptKind) << "'. Apply one of 'themes', 'langs' or 'plug-ins'.\n";             return EXIT_FAILURE;         }     }@@ -555,6 +559,7 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )     generator->setSVGSize ( options.getSVGWidth(),  options.getSVGHeight() );      generator->setESCCanvasPadding ( options.getCanvasPadding() );+    generator->setIndentGuides ( options.showIndentGuides() );      if (options.useCRDelimiter())         generator->setEOLDelimiter('\r');@@ -580,6 +585,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()); @@ -594,9 +600,9 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )     for (const auto& pluginFile : pluginFileList) {         if ( !generator->initPluginScript(pluginFile) ) {             cerr << "highlight: "-                 << generator->getPluginScriptError()+                 << StringTools::sanitizeForTerminal(generator->getPluginScriptError())                  << " in "-                 << pluginFile+                 << StringTools::sanitizeForTerminal(pluginFile)                  <<"\n";             return EXIT_FAILURE;         }@@ -604,7 +610,7 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )      if ( !generator->initTheme ( themePath, options.isLsSemantic() ) ) {         cerr << "highlight: "-             << generator->getThemeInitError()+             << StringTools::sanitizeForTerminal(generator->getThemeInitError())              << "\n";         return EXIT_FAILURE;     }@@ -618,7 +624,7 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )         string cssOutFile=options.getOutDirectory()  + options.getStyleOutFilename();         bool success=generator->printExternalStyle ( useStdout?"":cssOutFile );         if ( !success ) {-            cerr << "highlight: Could not write " << cssOutFile <<".\n";+            cerr << "highlight: Could not write " << StringTools::sanitizeForTerminal(cssOutFile) <<".\n";             return EXIT_FAILURE;         }         return EXIT_SUCCESS;@@ -628,7 +634,7 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )      if ( !formattingEnabled && !options.getIndentScheme().empty() ) {         cerr << "highlight: Undefined indentation scheme "-             << options.getIndentScheme()+             << StringTools::sanitizeForTerminal(options.getIndentScheme())              << ".\n";         return EXIT_FAILURE;     }@@ -640,7 +646,7 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )     ifstream dirTest ( outDirectory.c_str() );     if ( !outDirectory.empty() && !options.quietMode() && !dirTest ) {         cerr << "highlight: Output directory \""-             << outDirectory+             << StringTools::sanitizeForTerminal(outDirectory)              << "\" does not exist.\n";         return EXIT_FAILURE;     }@@ -685,9 +691,9 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )         if (i==0 && twoPassMode) {              if ( !generator->initPluginScript(twoPassOutFile) ) {                 cerr << "highlight: "-                 << generator->getPluginScriptError()+                 << StringTools::sanitizeForTerminal(generator->getPluginScriptError())                  << " in "-                 << twoPassOutFile+                 << StringTools::sanitizeForTerminal(twoPassOutFile)                  <<"\n";                 initError = true;                 break;@@ -724,21 +730,21 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )              if ( loadRes==highlight::LOAD_FAILED_REGEX ) {                 cerr << "highlight: Regex error ( "-                     << generator->getSyntaxRegexError()-                     << " ) in "<<suffix<<".lang\n";+                     << StringTools::sanitizeForTerminal(generator->getSyntaxRegexError())+                     << " ) in "<< StringTools::sanitizeForTerminal(suffix) <<".lang\n";                 initError = true;                 break;             } else if ( loadRes==highlight::LOAD_FAILED_LUA ) {                 cerr << "highlight: Lua error ( "-                     << generator->getSyntaxLuaError()-                     << " ) in "<<suffix<<".lang\n";+                     << StringTools::sanitizeForTerminal(generator->getSyntaxLuaError())+                     << " ) in "<< StringTools::sanitizeForTerminal(suffix) <<".lang\n";                 initError = true;                 break;             } else if ( loadRes==highlight::LOAD_FAILED ) {                 // do also ignore error msg if --syntax parameter should be skipped                 if ( ! (options.forceOutput() || options.quietMode() || options.isSkippedExt ( suffix )) ) {                     cerr << "highlight: Unknown source file extension \""-                         << suffix+                         << StringTools::sanitizeForTerminal(suffix)                          << "\". Consider the "                          << (options.enableBatchMode() ? "--skip" : "--force or --syntax")                          << " option.\n";@@ -871,7 +877,7 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )             outFilePath = options.getSingleOutFilename();             if ( outFilePath.size() && outFilePath==options.getSingleInFilename() ) {                 cerr << "highlight: Output path equals input path: \""-                     << outFilePath << "\".\n";+                     << StringTools::sanitizeForTerminal(outFilePath) << "\".\n";                 initError = true;                 break;             }@@ -914,12 +920,12 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )              bool success=generator->printPersistentState(twoPassOutFile);             if ( !success ) {-                cerr << "highlight: Could not write "<< twoPassOutFile <<".\n";+                cerr << "highlight: Could not write "<< StringTools::sanitizeForTerminal(twoPassOutFile) <<".\n";                 IOError = true;             } else {                 twoPassMode=true;                 if ( !options.quietMode() &&  !options.forceStdout() ) {-                    std::cout << "Enabling two-pass mode using "<<twoPassOutFile<<"\n";+                    std::cout << "Enabling two-pass mode using "<< StringTools::sanitizeForTerminal(twoPassOutFile) <<"\n";                 }                 //start over, add plug-in to list in next iteration                 usedFileNames.clear();@@ -939,7 +945,7 @@ int HLCmdLineApp::run ( const int argc, const char*argv[] )         string cssOutFile=outDirectory  + options.getStyleOutFilename();         bool success=generator->printExternalStyle ( cssOutFile );         if ( !success ) {-            cerr << "highlight: Could not write " << cssOutFile <<".\n";+            cerr << "highlight: Could not write " << StringTools::sanitizeForTerminal(cssOutFile) <<".\n";             IOError = true;         }     }@@ -987,7 +993,7 @@ int main ( const int argc, const char *argv[] )         HLCmdLineApp app;         return app.run ( argc, argv );     } catch (std::exception &e) {-        std::cerr << "highlight: " << e.what() << std::endl;+        std::cerr << "highlight: " << StringTools::sanitizeForTerminal(e.what()) << std::endl;         return EXIT_FAILURE;     } catch (...) {         std::cerr << "highlight: An unknown error occurred." << std::endl;

src/core/ansigenerator.cpp

@@ -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,23 +72,28 @@ 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" );     closeTags[0] = "";++    // basic ANSI has no theme-driven RGB guide colour, so fall back to a+    // faint/dim variant of the default foreground colour+    guideTagOpen = getOpenTag ( "02", "39" );+    guideTagClose = "\033[m"; }  string AnsiGenerator::getHeader()@@ -98,12 +113,20 @@ string AnsiGenerator::getFooter()  string AnsiGenerator::maskCharacter ( unsigned char c ) {-    return string ( 1, c );+    switch ( c ) {+        case 0x1b :+            return "";+        case 0x07 :+            return "";+        default:+            return string ( 1, 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 )

src/core/astyle/ASBeautifier.cpp

@@ -34,25 +34,10 @@ static int g_preprocessorCppExternCBrace;  */ ASBeautifier::ASBeautifier() {-	waitingBeautifierStack = nullptr;-	activeBeautifierStack = nullptr;-	waitingBeautifierStackLengthStack = nullptr;-	activeBeautifierStackLengthStack = nullptr;--	headerStack = nullptr;-	tempStacks = nullptr;-	parenDepthStack = nullptr;-	blockStatementStack = nullptr;-	parenStatementStack = nullptr;-	braceBlockStateStack = nullptr;-	continuationIndentStack = nullptr;-	continuationIndentStackSizeStack = nullptr;-	parenIndentStack = nullptr;-	preprocIndentStack = nullptr;-	lambdaDepthStack = nullptr; 	sourceIterator = nullptr; 	isModeManuallySet = false; 	shouldForceTabIndentation = false;+	shouldPreserveIndent = false; 	setSpaceIndentation(4); 	setContinuationIndentation(1); 	setMinConditionalIndentOption(MINCOND_TWO);@@ -62,6 +47,7 @@ ASBeautifier::ASBeautifier() 	setClassIndent(false); 	setModifierIndent(false); 	setSwitchIndent(false);+	setNoIndentIfAfterElseMode(false); 	setCaseIndent(false); 	setSqueezeWhitespace(false); 	setPreserveWhitespace(false);@@ -81,14 +67,14 @@ ASBeautifier::ASBeautifier()  	// initialize ASBeautifier member vectors 	beautifierFileType = INVALID_TYPE;		// reset to an invalid type-	headers = new std::vector<const std::string*>;-	nonParenHeaders = new std::vector<const std::string*>;-	assignmentOperators = new std::vector<const std::string*>;-	nonAssignmentOperators = new std::vector<const std::string*>;-	preBlockStatements = new std::vector<const std::string*>;-	preCommandHeaders = new std::vector<const std::string*>;-	indentableHeaders = new std::vector<const std::string*>;-	lambdaEndIndent = lambdaStartIndent = 0;+	headers = std::make_shared<std::vector<const std::string*>>();+	nonParenHeaders = std::make_shared<std::vector<const std::string*>>();+	assignmentOperators = std::make_shared<std::vector<const std::string*>>();+	nonAssignmentOperators = std::make_shared<std::vector<const std::string*>>();+	preBlockStatements = std::make_shared<std::vector<const std::string*>>();+	preCommandHeaders = std::make_shared<std::vector<const std::string*>>();+	indentableHeaders = std::make_shared<std::vector<const std::string*>>();+	lambdaStartIndent = 0; }  /**@@ -103,44 +89,37 @@ ASBeautifier::ASBeautifier() ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) { 	// these don't need to copy the stack-	waitingBeautifierStack = nullptr;-	activeBeautifierStack = nullptr;-	waitingBeautifierStackLengthStack = nullptr;-	activeBeautifierStackLengthStack = nullptr;+	// (default-constructed to nullptr, as before) -	// vector '=' operator performs a DEEP copy of all elements in the vector+	// vector copy construction performs a DEEP copy of all elements in the vector -	headerStack = new std::vector<const std::string*>;-	*headerStack = *other.headerStack;+	headerStack = std::make_unique<std::vector<const std::string*>>(*other.headerStack);  	tempStacks = copyTempStacks(other); -	parenDepthStack = new std::vector<int>;-	*parenDepthStack = *other.parenDepthStack;+	parenDepthStack = std::make_unique<std::vector<int>>(*other.parenDepthStack);+	parenBlockStateStack = std::make_unique<std::vector<ParenBlockState>>(*other.parenBlockStateStack); -	blockStatementStack = new std::vector<bool>;-	*blockStatementStack = *other.blockStatementStack;+	blockStatementStack = std::make_unique<std::vector<bool>>(*other.blockStatementStack);+	blockConditionalStack = std::make_unique<std::vector<bool>>(*other.blockConditionalStack);+	blockQuestionStack = std::make_unique<std::vector<int>>(*other.blockQuestionStack); -	parenStatementStack = new std::vector<bool>;-	*parenStatementStack = *other.parenStatementStack;+	parenStatementStack = std::make_unique<std::vector<bool>>(*other.parenStatementStack); -	braceBlockStateStack = new std::vector<bool>;-	*braceBlockStateStack = *other.braceBlockStateStack;+	braceBlockStateStack = std::make_unique<std::vector<bool>>(*other.braceBlockStateStack);+	lambdaBodyStateStack = std::make_unique<std::vector<bool>>(*other.lambdaBodyStateStack); -	continuationIndentStack = new std::vector<int>;-	*continuationIndentStack = *other.continuationIndentStack;+	continuationIndentStack = std::make_unique<std::vector<int>>(*other.continuationIndentStack); -	continuationIndentStackSizeStack = new std::vector<size_t>;-	*continuationIndentStackSizeStack = *other.continuationIndentStackSizeStack;+	continuationIndentStackSizeStack = std::make_unique<std::vector<size_t>>(*other.continuationIndentStackSizeStack); -	parenIndentStack = new std::vector<int>;-	*parenIndentStack = *other.parenIndentStack;+	parenIndentStack = std::make_unique<std::vector<int>>(*other.parenIndentStack); -	preprocIndentStack = new std::vector<std::pair<int, int> >;-	*preprocIndentStack = *other.preprocIndentStack;+	preprocIndentStack = std::make_unique<std::vector<std::pair<int, int> >>(*other.preprocIndentStack); -	lambdaDepthStack = new std::vector<int>;-	*lambdaDepthStack = *other.lambdaDepthStack;+	lambdaDepthStack = std::make_unique<std::vector<int>>(*other.lambdaDepthStack);+	lambdaParenDepthStack = std::make_unique<std::vector<int>>(*other.lambdaParenDepthStack);+	lambdaBraceDepthStack = std::make_unique<std::vector<size_t>>(*other.lambdaBraceDepthStack);  	// Copy the pointers to std::vectors. 	// This is ok because the original ASBeautifier object@@ -190,7 +169,7 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) 	isInPreprocessorComment = other.isInPreprocessorComment; 	isInRunInComment = other.isInRunInComment; 	isInCase = other.isInCase;-	isInQuestion = other.isInQuestion;+	questionMarkCount = other.questionMarkCount; 	isContinuation = other.isContinuation; 	isInHeader = other.isInHeader; 	isInTemplate = other.isInTemplate;@@ -198,6 +177,7 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) 	isInDefineDefinition = other.isInDefineDefinition; 	classIndent = other.classIndent; 	isIndentModeOff = other.isIndentModeOff;+	shouldPreserveIndent = other.shouldPreserveIndent; 	isInClassHeader = other.isInClassHeader; 	isInClassHeaderTab = other.isInClassHeaderTab; 	isInClassInitializer = other.isInClassInitializer;@@ -212,10 +192,16 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) 	isInEnum = other.isInEnum; 	isInEnumTypeID = other.isInEnumTypeID; 	isInStruct = other.isInStruct;+	isInDesignatedInit = other.isInDesignatedInit; 	isInLet = other.isInLet; 	isInTrailingReturnType = other.isInTrailingReturnType;+	isInConstevalCondition = other.isInConstevalCondition;+	isInLambdaIntroducer = other.isInLambdaIntroducer;+	switchCaseStack = other.switchCaseStack;+	isLastSquareBracketLambda = other.isLastSquareBracketLambda; 	modifierIndent = other.modifierIndent; 	switchIndent = other.switchIndent;+	noIndentIfAfterElse = other.noIndentIfAfterElse; 	caseIndent = other.caseIndent; 	squeezeWhitespace = other.squeezeWhitespace; 	preserveWhitespace = other.preserveWhitespace;@@ -247,6 +233,7 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) 	lineBeginsWithOpenBrace = other.lineBeginsWithOpenBrace; 	lineBeginsWithCloseBrace = other.lineBeginsWithCloseBrace; 	lineBeginsWithComma = other.lineBeginsWithComma;+	prevLineBeginsWithComma = other.prevLineBeginsWithComma; 	lineIsCommentOnly = other.lineIsCommentOnly; 	lineIsLineCommentOnly = other.lineIsLineCommentOnly; 	shouldIndentBracedLine = other.shouldIndentBracedLine;@@ -258,6 +245,11 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) 	shouldIndentPreprocConditional = other.shouldIndentPreprocConditional; 	lambdaIndicator = other.lambdaIndicator; 	lambdaDepth = other.lambdaDepth;+	lambdaCaptureParenDepth = other.lambdaCaptureParenDepth;+	lambdaIntroducerParenDepth = other.lambdaIntroducerParenDepth;+	newKeywordParenDepth = other.newKeywordParenDepth;+	newKeywordSpaceIndent = other.newKeywordSpaceIndent;+	blockSpaceIndent = other.blockSpaceIndent; 	lastLambdaDepth = other.lastLambdaDepth;  @@ -291,31 +283,14 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) 	prevNonLegalCh = other.prevNonLegalCh; 	bracesNestingLevel = other.bracesNestingLevel; 	bracesNestingLevelOfStruct = other.bracesNestingLevelOfStruct;-	lambdaEndIndent = other.lambdaEndIndent; 	lambdaStartIndent = other.lambdaStartIndent; }  /**  * ASBeautifier's destructor+ * All member vectors are smart pointers, so cleanup is automatic.  */-ASBeautifier::~ASBeautifier()-{-	deleteBeautifierContainer(waitingBeautifierStack);-	deleteBeautifierContainer(activeBeautifierStack);-	deleteContainer(waitingBeautifierStackLengthStack);-	deleteContainer(activeBeautifierStackLengthStack);-	deleteContainer(headerStack);-	deleteTempStacksContainer(tempStacks);-	deleteContainer(parenDepthStack);-	deleteContainer(blockStatementStack);-	deleteContainer(parenStatementStack);-	deleteContainer(braceBlockStateStack);-	deleteContainer(continuationIndentStack);-	deleteContainer(continuationIndentStackSizeStack);-	deleteContainer(parenIndentStack);-	deleteContainer(preprocIndentStack);-	deleteContainer(lambdaDepthStack);-}+ASBeautifier::~ASBeautifier() = default;  /**  * initialize the ASBeautifier.@@ -335,29 +310,38 @@ void ASBeautifier::init(ASSourceIterator* iter) 	ASBase::init(getFileType()); 	g_preprocessorCppExternCBrace = 0; -	initContainer(waitingBeautifierStack, new std::vector<ASBeautifier*>);-	initContainer(activeBeautifierStack, new std::vector<ASBeautifier*>);+	// the ASFormatter object is never deleted, so any existing vectors+	// must be replaced (not merely populated) before starting a new file+	waitingBeautifierStack = std::make_unique<std::vector<std::unique_ptr<ASBeautifier>>>();+	activeBeautifierStack = std::make_unique<std::vector<std::unique_ptr<ASBeautifier>>>(); -	initContainer(waitingBeautifierStackLengthStack, new std::vector<size_t>);-	initContainer(activeBeautifierStackLengthStack, new std::vector<size_t>);+	waitingBeautifierStackLengthStack = std::make_unique<std::vector<size_t>>();+	activeBeautifierStackLengthStack = std::make_unique<std::vector<size_t>>(); -	initContainer(headerStack, new std::vector<const std::string*>);+	headerStack = std::make_unique<std::vector<const std::string*>>(); -	initTempStacksContainer(tempStacks, new std::vector<std::vector<const std::string*>*>);-	tempStacks->emplace_back(new std::vector<const std::string*>);+	tempStacks = std::make_unique<std::vector<std::unique_ptr<std::vector<const std::string*>>>>();+	tempStacks->emplace_back(std::make_unique<std::vector<const std::string*>>()); -	initContainer(parenDepthStack, new std::vector<int>);-	initContainer(blockStatementStack, new std::vector<bool>);-	initContainer(parenStatementStack, new std::vector<bool>);-	initContainer(braceBlockStateStack, new std::vector<bool>);+	parenDepthStack = std::make_unique<std::vector<int>>();+	parenBlockStateStack = std::make_unique<std::vector<ParenBlockState>>();+	blockStatementStack = std::make_unique<std::vector<bool>>();+	blockConditionalStack = std::make_unique<std::vector<bool>>();+	blockQuestionStack = std::make_unique<std::vector<int>>();+	parenStatementStack = std::make_unique<std::vector<bool>>();+	braceBlockStateStack = std::make_unique<std::vector<bool>>(); 	// do not use emplace_back on std::vector<bool> until supported by macOS 	braceBlockStateStack->push_back(true);-	initContainer(continuationIndentStack, new std::vector<int>);-	initContainer(continuationIndentStackSizeStack, new std::vector<size_t>);+	lambdaBodyStateStack = std::make_unique<std::vector<bool>>();+	lambdaBodyStateStack->push_back(false);+	continuationIndentStack = std::make_unique<std::vector<int>>();+	continuationIndentStackSizeStack = std::make_unique<std::vector<size_t>>(); 	continuationIndentStackSizeStack->emplace_back(0);-	initContainer(parenIndentStack, new std::vector<int>);-	initContainer(preprocIndentStack, new std::vector<std::pair<int, int> >);-	initContainer(lambdaDepthStack, new std::vector<int>);+	parenIndentStack = std::make_unique<std::vector<int>>();+	preprocIndentStack = std::make_unique<std::vector<std::pair<int, int> >>();+	lambdaDepthStack = std::make_unique<std::vector<int>>();+	lambdaParenDepthStack = std::make_unique<std::vector<int>>();+	lambdaBraceDepthStack = std::make_unique<std::vector<size_t>>();  	previousLastLineHeader = nullptr; 	currentHeader = nullptr;@@ -373,7 +357,7 @@ void ASBeautifier::init(ASSourceIterator* iter) 	isInRunInComment = false; 	isContinuation = false; 	isInCase = false;-	isInQuestion = false;+	questionMarkCount = 0; 	isIndentModeOff = false; 	isInClassHeader = false; 	isInClassHeaderTab = false;@@ -389,13 +373,23 @@ void ASBeautifier::init(ASSourceIterator* iter) 	isInEnum = false; 	isInEnumTypeID = false; 	isInStruct = false;+	isInDesignatedInit = false; 	isInLet = false; 	isInHeader = false; 	isInTemplate = false; 	isInConditional = false; 	isInTrailingReturnType = false;+	isInConstevalCondition = false;+	isInLambdaIntroducer = false;+	switchCaseStack.clear();+	isLastSquareBracketLambda = false; 	lambdaIndicator = false; 	lambdaDepth = 0;+	lambdaCaptureParenDepth = -1;+	lambdaIntroducerParenDepth = 0;+	newKeywordParenDepth = -1;+	newKeywordSpaceIndent = 0;+	blockSpaceIndent = 0; 	lastLambdaDepth = 0;  	indentCount = 0;@@ -436,6 +430,7 @@ void ASBeautifier::init(ASSourceIterator* iter) 	lineBeginsWithOpenBrace = false; 	lineBeginsWithCloseBrace = false; 	lineBeginsWithComma = false;+	prevLineBeginsWithComma = false; 	lineIsCommentOnly = false; 	lineIsLineCommentOnly = false; 	shouldIndentBracedLine = true;@@ -457,7 +452,7 @@ void ASBeautifier::init(ASSourceIterator* iter) 	objCColonAlignSubsequent = 0; 	bracesNestingLevel = 0; 	bracesNestingLevelOfStruct = 0;-	lambdaEndIndent = lambdaStartIndent = 0;+	lambdaStartIndent = 0; }  /*@@ -478,13 +473,13 @@ void ASBeautifier::initVectors() 	preCommandHeaders->clear(); 	indentableHeaders->clear(); -	ASResource::buildHeaders(headers, fileType, true);-	ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);-	ASResource::buildAssignmentOperators(assignmentOperators);-	ASResource::buildNonAssignmentOperators(nonAssignmentOperators, fileType);-	ASResource::buildPreBlockStatements(preBlockStatements, fileType);-	ASResource::buildPreCommandHeaders(preCommandHeaders, fileType);-	ASResource::buildIndentableHeaders(indentableHeaders);+	ASResource::buildHeaders(headers.get(), fileType, true);+	ASResource::buildNonParenHeaders(nonParenHeaders.get(), fileType, true);+	ASResource::buildAssignmentOperators(assignmentOperators.get());+	ASResource::buildNonAssignmentOperators(nonAssignmentOperators.get(), fileType);+	ASResource::buildPreBlockStatements(preBlockStatements.get(), fileType);+	ASResource::buildPreCommandHeaders(preCommandHeaders.get(), fileType);+	ASResource::buildIndentableHeaders(indentableHeaders.get()); }  /**@@ -503,6 +498,18 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 	currentHeader = nullptr; 	lastLineHeader = nullptr; 	blockCommentNoBeautify = blockCommentNoIndent;+	// the lambda offset of a line is the one in effect where the line starts,+	// so lambdas opened or closed within the line do not affect its own indent+	lambdaStartIndent = 0;+	if (!lambdaDepthStack->empty())+	{+		size_t lambdaLevel = lambdaDepthStack->size();+		// a line within the parameter list of a lambda belongs to the enclosing context+		if (lambdaBraceDepthStack->back() == 0 && parenDepth > lambdaParenDepthStack->back())+			lambdaLevel--;+		if (lambdaLevel > 0)+			lambdaStartIndent = (*lambdaDepthStack)[lambdaLevel - 1];+	} 	isInClass = false; 	isInSwitch = false; 	lineBeginsWithOpenBrace = false;@@ -549,8 +556,7 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 		if (trimEnd < line.length()) 			line.erase(trimEnd); 		// does a brace open the line-		size_t firstChar = line.find_first_not_of(" \t");-		if (firstChar != std::string::npos)+		if (size_t firstChar = line.find_first_not_of(" \t"); firstChar != std::string::npos) 		{ 			if (line[firstChar] == '{') 				lineBeginsWithOpenBrace = true;@@ -613,6 +619,10 @@ std::string ASBeautifier::beautify(const std::string& originalLine)  	if (line.empty()) 	{+		if (shouldPreserveIndent)+			return "";++ 		if (backslashEndsPrevLine) 		{ 			backslashEndsPrevLine = false;@@ -623,11 +633,7 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 			{ 				isInDefineDefinition = false; 				if (!activeBeautifierStack->empty())-				{-					ASBeautifier* defineBeautifier = activeBeautifierStack->back(); 					activeBeautifierStack->pop_back();-					delete defineBeautifier;-				} 			} 		} 		if (emptyLineFill && !isInQuoteContinuation)@@ -643,24 +649,12 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 			return line; 	} -	if (isCStyle()-	        && !isInComment-	        && !parenDepth-	        //&& line.find('(', 0) == std::string::npos-	        && line.find('#', 0) == std::string::npos-	        && line.find("//", 0) == std::string::npos-	        && line.find("/*", 0) == std::string::npos-	        && (line[line.length() - 1] == '"' || line[line.length() - 1] == '<' || quoteContinuationIndent))-	{-		quoteContinuationIndent = std::max(quoteContinuationIndent, line.find('"', 0) );-	}- 	// handle preprocessor commands 	if (isInIndentablePreprocBlock 	        && !line.empty() 	        && line[0] != '#') 	{-		if (isIndentModeOff)+		if (isIndentModeOff || shouldPreserveIndent) 			return originalLine;  		if (isInClassHeaderTab || isInClassInitializer)@@ -691,7 +685,7 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 					preprocBlockIndent += 1; 					isInIndentablePreprocBlock = true; 				}-				else if (preproc == "else" || preproc == "elif")+				else if (preproc == "else" || preproc.compare(0, 4, "elif") == 0) // #elif, #elifdef, #elifndef 				{ 					indentedLine = preLineWS(preprocBlockIndent - 1, 0) + line; 				}@@ -705,7 +699,7 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 				else 					indentedLine = preLineWS(preprocBlockIndent, 0) + line; -				if (isIndentModeOff)+				if (isIndentModeOff || shouldPreserveIndent) 					return originalLine; 				else 					return indentedLine;@@ -713,23 +707,22 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 			if (shouldIndentPreprocConditional && !preproc.empty()) 			{ -				if (isIndentModeOff)+				if (isIndentModeOff || shouldPreserveIndent) 					return originalLine;  				std::string indentedLine; 				if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef 				{-					std::pair<int, int> entry;	// indentCount, spaceIndentCount-					if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())-						entry = activeBeautifierStack->back()->computePreprocessorIndent();-					else-						entry = computePreprocessorIndent();+					// indentCount, spaceIndentCount+					std::pair<int, int> entry = (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())+					                            ? activeBeautifierStack->back()->computePreprocessorIndent()+					                            : computePreprocessorIndent(); 					preprocIndentStack->emplace_back(entry); 					indentedLine = preLineWS(preprocIndentStack->back().first, 					                         preprocIndentStack->back().second) + line; 					return indentedLine; 				}-				if (preproc == "else" || preproc == "elif")+				if (preproc == "else" || preproc.compare(0, 4, "elif") == 0) // #elif, #elifdef, #elifndef 				{ 					if (!preprocIndentStack->empty())	// if no entry don't indent 					{@@ -766,13 +759,12 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 		{ 			isInDefineDefinition = false; 			// this could happen with invalid input-			if (activeBeautifierStack->empty() || isIndentModeOff)+			if (activeBeautifierStack->empty() || isIndentModeOff || shouldPreserveIndent) 				return originalLine;-			ASBeautifier* defineBeautifier = activeBeautifierStack->back();+			std::unique_ptr<ASBeautifier> defineBeautifier = std::move(activeBeautifierStack->back()); 			activeBeautifierStack->pop_back();  			std::string indentedLine = defineBeautifier->beautify(line);-			delete defineBeautifier; 			return indentedLine; 		} @@ -815,12 +807,23 @@ std::string ASBeautifier::beautify(const std::string& originalLine)  	size_t iPrelim = headerStack->size(); +	// must be checked before the line is parsed+	bool isDeclarationContinuation = isDeclarationContinuationLine(line);+	bool isSwitchUsing = isUsingBeforeFirstCase(line);+ 	// calculate preliminary indentation based on headerStack and data from past lines 	computePreliminaryIndentation();+	const int prelimSpaceIndentCount = spaceIndentCount;  	// parse characters in the current line. 	parseCurrentLine(line); +	// a comment between comma first initializers is aligned with the commas (bug #330)+	if ((isInClassInitializer || isInClassHeaderTab)+	        && (lineIsLineCommentOnly || lineIsCommentOnly)+	        && prevLineBeginsWithComma)+		spaceIndentCount = 0;+ 	for (auto it = squeezeWSStack.rbegin(); it != squeezeWSStack.rend(); ++it) 	{ 		line.erase(it->first, it->second);@@ -830,6 +833,13 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 	// handle special cases of indentation 	adjustParsedLineIndentation(iPrelim, isInExtraHeaderIndent); +	if (isDeclarationContinuation)+		++indentCount;++	// 'using enum X;' before the first case is unindented like a case label+	if (isSwitchUsing && indentCount > 0)+		--indentCount;+ 	if (isInObjCMethodDefinition) 		adjustObjCMethodDefinitionIndentation(line); @@ -862,25 +872,44 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 		// logIndent(2); 	} -	if (indentCount < 0){-		indentCount = 0;-		// logIndent(3);-	}+	indentCount = std::max(0, indentCount);  	if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation){ 		indentCount = spaceIndentCount = 0; 		// logIndent(4); 	} +	// a string literal ending the line may be continued by a literal on the next line (bug #172):+	// align it with the first literal of a statement's first line or with a continued literal,+	// any other continuation line keeps the regular continuation indent (bug #587)+	quoteContinuationIndent = 0;+	if (isCStyle()+	        && !isInDefine+	        && !isInComment+	        && !isInQuote+	        && !isInMultiLineString+	        && parenDepth == 0+	        && !line.empty()+	        && line.back() == '"')+	{+		if (line[0] == '"')+			quoteContinuationIndent = spaceIndentCount;+		else if (prelimSpaceIndentCount == 0)+			quoteContinuationIndent = spaceIndentCount + static_cast<int>(line.find('"'));+	}+ 	// finally, insert indentations into beginning of line -	std::string indentedLine = isIndentModeOff ? originalLine : preLineWS(indentCount, spaceIndentCount) + line;+	std::string indentedLine = (isIndentModeOff || shouldPreserveIndent) ? originalLine : preLineWS(indentCount, spaceIndentCount) + line; 	prevFinalLineSpaceIndentCount = spaceIndentCount; 	prevFinalLineIndentCount = indentCount;  	if (lastLineHeader != nullptr) 		previousLastLineHeader = lastLineHeader; +	if (!lineIsLineCommentOnly && !lineIsCommentOnly)+		prevLineBeginsWithComma = lineBeginsWithComma;+ 	if ((lineIsLineCommentOnly || lineIsCommentOnly) 	        && line.find("*INDENT-ON*", 0) != std::string::npos) 		isIndentModeOff = false;@@ -989,6 +1018,11 @@ void ASBeautifier::setSpaceIndentation(int length) 	indentLength = length; } +void ASBeautifier::setPreserveIndent(bool state)+{+	shouldPreserveIndent = state;+}+ /** * indent continuation lines using a number of indents. *@@ -1111,6 +1145,18 @@ void ASBeautifier::setSwitchIndent(bool state) 	switchIndent = state; } +/**+ * set the no-indent-if-after-else option. If true, an 'if' statement+ * that follows an 'else' (when break-elseifs is active) will not+ * receive the extra indentation normally applied to a broken else-if.+ *+ * @param   state             state of option.+ */+void ASBeautifier::setNoIndentIfAfterElseMode(bool state)+{+	noIndentIfAfterElse = state;+}+ /**  * set the state of the case indentation option. If true, lines of 'case'  * statements will be indented one additional indent.@@ -1393,8 +1439,56 @@ int ASBeautifier::getTabLength() const 	return tabLength; } +int ASBeautifier::getMinConditionalIndent() const+{+	return minConditionalIndent;+}++int ASBeautifier::getIndentCount() const+{+	return indentCount;+}++int ASBeautifier::getSpaceIndentCount() const+{+	return spaceIndentCount;+}++int ASBeautifier::getPrevFinalLineIndentCount() const+{+	return prevFinalLineIndentCount;+}++int ASBeautifier::getPrevFinalLineSpaceIndentCount() const+{+	return prevFinalLineSpaceIndentCount;+}++/**+ * remove the innermost entry of the lambda capture stacks.+ */+void ASBeautifier::popLambda()+{+	lambdaDepthStack->pop_back();+	lambdaParenDepthStack->pop_back();+	lambdaBraceDepthStack->pop_back();+}++/**+ * check if the current line is within a non in-statement array.+ * isNonInStatementArray remains set within a lambda body like 'f([&]\n{'+ * whose brace was treated as an array brace, but the body contains statements.+ */+bool ASBeautifier::isInNonInStatementArray() const+{+	return isNonInStatementArray && !lambdaBodyStateStack->back();+}+ std::string ASBeautifier::preLineWS(int lineIndentCount, int lineSpaceIndentCount) {+	// within a lambda body indented by --indent-lambda the continuation indent+	// of the line is relative to the lambda column+	lineSpaceIndentCount += lambdaStartIndent;  	if (shouldForceTabIndentation) 	{@@ -1416,17 +1510,6 @@ std::string ASBeautifier::preLineWS(int lineIndentCount, int lineSpaceIndentCoun  	std::string ws; -	if (lambdaDepthStack->size()) {-		if (!lambdaStartIndent)-			lineSpaceIndentCount = lambdaDepthStack->back();-		lambdaStartIndent = 0;-	}-	else if (lambdaEndIndent>0 ) {-		lineSpaceIndentCount = lambdaEndIndent;-		if (!lambdaIndicator)-			lambdaEndIndent = 0;-	}- 	for (int i = 0; i < lineIndentCount; i++) 		ws += indentString; 	while ((lineSpaceIndentCount--) > 0)@@ -1486,6 +1569,11 @@ void ASBeautifier::registerContinuationIndent(std::string_view line, int i, int 			parenIndentStack->back() = 0; 	} +	// align with a comment following the opener, not with the code after it (bug #330)+	size_t firstChar = line.find_first_not_of(" \t", i + 1);+	if (firstChar != std::string_view::npos)+		nextNonWSChar = static_cast<int>(firstChar) - i;+ 	int tabIncrement = tabIncrementIn;  	// check for following tabs@@ -1506,18 +1594,29 @@ void ASBeautifier::registerContinuationIndent(std::string_view line, int i, int  	// this is not done for an in-statement array 	int multiplier = isInAssignment ? 1 : 2; // GL16 - no multiply in assignments++	// when capped by max-continuation-indent, don't let the stack promote+	// the value back up (e.g. to a prior '.' operator's column on the same line)+	bool reducedToMax = false;+ 	if (continuationIndentCount > maxContinuationIndent-	        && !(prevNonLegalCh == '=' && currentNonLegalCh == '{'))+		&& !(prevNonLegalCh == '=' && currentNonLegalCh == '{')){ 		continuationIndentCount = indentLength * multiplier + spaceIndentCount_;+			reducedToMax = true;+	} -	if (!continuationIndentStack->empty()-	        && continuationIndentCount < continuationIndentStack->back())+	if (!reducedToMax && !continuationIndentStack->empty()+		&& continuationIndentCount < continuationIndentStack->back()){ 		continuationIndentCount = continuationIndentStack->back(); +	}+ 	// the block opener is not indented for a NonInStatementArray 	if ((isNonInStatementArray && i >= 0 && line[i] == '{')-	        && !isInEnum && !isInStruct && !braceBlockStateStack->empty() && braceBlockStateStack->back())+		&& !isInEnum && !isInStruct && !braceBlockStateStack->empty() && braceBlockStateStack->back()){ 		continuationIndentCount = 0;+	}+ 	continuationIndentStack->emplace_back(continuationIndentCount); } @@ -1530,11 +1629,9 @@ void ASBeautifier::registerContinuationIndentColon(std::string_view line, int i, 	assert(isInClassInitializer || isInClassHeaderTab);  	// register indent at first word after the colon-	size_t firstChar = line.find_first_not_of(" \t");-	if (firstChar == (size_t) i)		// firstChar is ':'+	if (size_t firstChar = line.find_first_not_of(" \t"); firstChar == (size_t) i)		// firstChar is ':' 	{-		size_t firstWord = line.find_first_not_of(" \t", firstChar + 1);-		if (firstWord != std::string::npos)+		if (size_t firstWord = line.find_first_not_of(" \t", firstChar + 1); firstWord != std::string::npos) 		{ 			int continuationIndentCount = firstWord + spaceIndentCount + tabIncrementIn; 			continuationIndentStack->emplace_back(continuationIndentCount);@@ -1609,17 +1706,17 @@ int ASBeautifier::getNextProgramCharDistance(std::string_view line, int i) const /**  * find the index number of a std::string element in a container of std::strings  *- * @return              the index number of element in the container. -1 if element not found.+ * @return              the index number of element in the container. std::nullopt if element not found.  * @param container     a vector of std::strings.  * @param element       the element to find .  */-int ASBeautifier::indexOf(const std::vector<const std::string*>& container, const std::string* element) const+std::optional<int> ASBeautifier::indexOf(const std::vector<const std::string*>& container, const std::string* element) const { 	std::vector<const std::string*>::const_iterator where;  	where = find(container.begin(), container.end(), element); 	if (where == container.end())-		return -1;+		return std::nullopt; 	return (int) (where - container.begin()); } @@ -1680,124 +1777,17 @@ std::string ASBeautifier::rtrim(std::string_view str) const  * Copy tempStacks for the copy constructor.  * The value of the vectors must also be copied.  */-std::vector<std::vector<const std::string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier& other) const+std::unique_ptr<std::vector<std::unique_ptr<std::vector<const std::string*>>>> ASBeautifier::copyTempStacks(const ASBeautifier& other) const {-	auto* tempStacksNew = new std::vector<std::vector<const std::string*>*>;-	std::vector<std::vector<const std::string*>*>::iterator iter;-	for (iter = other.tempStacks->begin();-	        iter != other.tempStacks->end();-	        ++iter)-	{-		auto* newVec = new std::vector<const std::string*>;-		*newVec = **iter;-		tempStacksNew->emplace_back(newVec);-	}+	auto tempStacksNew = std::make_unique<std::vector<std::unique_ptr<std::vector<const std::string*>>>>();+	for (const auto& stack : *other.tempStacks)+		tempStacksNew->emplace_back(std::make_unique<std::vector<const std::string*>>(*stack)); 	return tempStacksNew; }  /**- * delete a member vectors to eliminate memory leak reporting- */-void ASBeautifier::deleteBeautifierVectors()-{-	beautifierFileType = INVALID_TYPE;		// reset to an invalid type-	delete headers;-	delete nonParenHeaders;-	delete preBlockStatements;-	delete preCommandHeaders;-	delete assignmentOperators;-	delete nonAssignmentOperators;-	delete indentableHeaders;-}--/**- * delete a vector object- * T is the type of vector- * used for all vectors except tempStacks- */-template<typename T>-void ASBeautifier::deleteContainer(T& container)-{-	if (container != nullptr)-	{-		container->clear();-		delete (container);-		container = nullptr;-	}-}--/**- * Delete the ASBeautifier vector object.- * This is a vector of pointers to ASBeautifier objects allocated with the 'new' operator.- * Therefore the ASBeautifier objects have to be deleted in addition to the- * ASBeautifier pointer entries.- */-void ASBeautifier::deleteBeautifierContainer(std::vector<ASBeautifier*>*& container)-{-	if (container != nullptr)-	{-		auto iter = container->begin();-		while (iter < container->end())-		{-			delete *iter;-			++iter;-		}-		container->clear();-		delete (container);-		container = nullptr;-	}-}--/**- * Delete the tempStacks vector object.- * The tempStacks is a vector of pointers to std::strings allocated with the 'new' operator.- * Therefore the std::strings have to be deleted in addition to the tempStacks entries.- */-void ASBeautifier::deleteTempStacksContainer(std::vector<std::vector<const std::string*>*>*& container)-{-	if (container != nullptr)-	{-		auto iter = container->begin();-		while (iter < container->end())-		{-			delete *iter;-			++iter;-		}-		container->clear();-		delete (container);-		container = nullptr;-	}-}--/**- * initialize a vector object- * T is the type of vector used for all vectors- */-template<typename T>-void ASBeautifier::initContainer(T& container, T value)-{-	// since the ASFormatter object is never deleted,-	// the existing vectors must be deleted before creating new ones-	if (container != nullptr)-		deleteContainer(container);-	container = value;-}--/**- * Initialize the tempStacks vector object.- * The tempStacks is a vector of pointers to std::strings allocated with the 'new' operator.- * Any residual entries are deleted before the vector is initialized.- */-void ASBeautifier::initTempStacksContainer(std::vector<std::vector<const std::string*>*>*& container,-                                           std::vector<std::vector<const std::string*>*>* value)-{-	if (container != nullptr)-		deleteTempStacksContainer(container);-	container = value;-}--/**- * Determine if an assignment statement ends with a comma+ * Determine if an assignment statement (index at '=') or a+ *     method call (index at '.') ends with a comma  *     that is not in a function argument. It ends with a  *     comma if a comma is the last char on the line.  *@@ -1805,7 +1795,7 @@ void ASBeautifier::initTempStacksContainer(std::vector<std::vector<const std::st  */ bool ASBeautifier::statementEndsWithComma(std::string_view line, int index) const {-	assert(line[index] == '=');+	assert(line[index] == '=' || line[index] == '.');  	bool isInComment_ = false; 	bool isInQuote_ = false;@@ -1880,6 +1870,32 @@ bool ASBeautifier::statementEndsWithComma(std::string_view line, int index) cons 	return true; } +/**+ * Determine if the assignment at index is a designated initializer+ *     like '.member = value' that begins the line.+ *+ * @return  true if it is a designated initializer, otherwise false.+ */+bool ASBeautifier::isDesignatedInitializer(std::string_view line, size_t index) const+{+	assert(line[index] == '=');++	size_t dotPos = line.find_first_not_of(" \t");+	if (dotPos == std::string::npos || dotPos >= index || line[dotPos] != '.')+		return false;++	size_t nameStart = dotPos + 1;+	if (nameStart >= index || !isLegalNameChar(line[nameStart]) || isDigit(line[nameStart]))+		return false;++	size_t nameEnd = nameStart;+	while (nameEnd < index && isLegalNameChar(line[nameEnd]))+		++nameEnd;++	size_t nextChar = line.find_first_not_of(" \t", nameEnd);+	return nextChar == index;+}+ /**  * check if current comment is a line-end comment  *@@ -1951,6 +1967,18 @@ int ASBeautifier::getContinuationIndentComma(std::string_view line, size_t currP 		if (!isLegalNameChar(line[indent])) 			break; 	}++	// the first word must be followed by a type continuation (declaration),+	// not by an expression like a method call 'a.get(),' or 'values[0],'+	char afterFirstWord = line[indent];+	if (!std::isblank(static_cast<unsigned char>(afterFirstWord))+	        && afterFirstWord != '*'+	        && afterFirstWord != '&'+	        && afterFirstWord != ':'+	        && afterFirstWord != '<'+	        && !(afterFirstWord == '[' && peekNextChar(line, indent) == ']'))+		return 0;+ 	indent++; 	if (indent >= currPos || indent < 4) 		return 0;@@ -2133,8 +2161,7 @@ void ASBeautifier::processPreprocessor(std::string_view preproc, std::string_vie  			// push a new beautifier into the active stack 			// this beautifier will be used for the indentation of this define-			auto* defineBeautifier = new ASBeautifier(*this);-			activeBeautifierStack->emplace_back(defineBeautifier);+			activeBeautifierStack->emplace_back(std::make_unique<ASBeautifier>(*this)); 		} 		else 		{@@ -2150,42 +2177,37 @@ void ASBeautifier::processPreprocessor(std::string_view preproc, std::string_vie 		waitingBeautifierStackLengthStack->emplace_back(waitingBeautifierStack->size()); 		activeBeautifierStackLengthStack->emplace_back(activeBeautifierStack->size()); 		if (activeBeautifierStackLengthStack->back() == 0)-			waitingBeautifierStack->emplace_back(new ASBeautifier(*this));+			waitingBeautifierStack->emplace_back(std::make_unique<ASBeautifier>(*this)); 		else-			waitingBeautifierStack->emplace_back(new ASBeautifier(*activeBeautifierStack->back()));+			waitingBeautifierStack->emplace_back(std::make_unique<ASBeautifier>(*activeBeautifierStack->back())); 	} 	else if (preproc == "else") 	{ 		if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty()) 		{ 			// MOVE current waiting beautifier to active stack.-			activeBeautifierStack->emplace_back(waitingBeautifierStack->back());+			activeBeautifierStack->emplace_back(std::move(waitingBeautifierStack->back())); 			waitingBeautifierStack->pop_back(); 		} 	}-	else if (preproc == "elif")+	else if (preproc.compare(0, 4, "elif") == 0) // #elif, #elifdef, #elifndef 	{ 		if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty()) 		{ 			// append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.-			activeBeautifierStack->emplace_back(new ASBeautifier(*(waitingBeautifierStack->back())));+			activeBeautifierStack->emplace_back(std::make_unique<ASBeautifier>(*waitingBeautifierStack->back())); 		} 	} 	else if (preproc == "endif") 	{ 		int stackLength = 0;-		ASBeautifier* beautifier = nullptr;  		if (waitingBeautifierStackLengthStack != nullptr && !waitingBeautifierStackLengthStack->empty()) 		{ 			stackLength = waitingBeautifierStackLengthStack->back(); 			waitingBeautifierStackLengthStack->pop_back(); 			while ((int) waitingBeautifierStack->size() > stackLength)-			{-				beautifier = waitingBeautifierStack->back(); 				waitingBeautifierStack->pop_back();-				delete beautifier;-			} 		}  		if (!activeBeautifierStackLengthStack->empty())@@ -2193,11 +2215,7 @@ void ASBeautifier::processPreprocessor(std::string_view preproc, std::string_vie 			stackLength = activeBeautifierStackLengthStack->back(); 			activeBeautifierStackLengthStack->pop_back(); 			while ((int) activeBeautifierStack->size() > stackLength)-			{-				beautifier = activeBeautifierStack->back(); 				activeBeautifierStack->pop_back();-				delete beautifier;-			} 		} 	} }@@ -2217,11 +2235,30 @@ void ASBeautifier::computePreliminaryIndentation()  	if (!continuationIndentStack->empty()) 		spaceIndentCount = continuationIndentStack->back();+	else+		spaceIndentCount = blockSpaceIndent; +	size_t braceIndex = 0;	// index of a brace in parenDepthStack and blockConditionalStack 	for (size_t i = 0; i < headerStack->size(); i++) 	{ 		isInClass = false; +		// a brace opened within parens of a header's statement (e.g. 'else call([&] {')+		// is not the header's block; a brace within the header's condition+		// (e.g. 'if (pred([&] {') is indented relative to the header line+		bool isBraceInStatementParen = false;+		bool isBraceInConditionParen = false;+		if ((*headerStack)[i] == &ASResource::AS_OPEN_BRACE)+		{+			bool isInParen = braceIndex < parenDepthStack->size()+			                 && (*parenDepthStack)[braceIndex] > 0;+			bool isInCondition = braceIndex < blockConditionalStack->size()+			                     && (*blockConditionalStack)[braceIndex];+			isBraceInStatementParen = isInParen && !isInCondition;+			isBraceInConditionParen = isInParen && isInCondition;+			++braceIndex;+		}+ 		if (blockIndent) 		{ 			// do NOT indent opening block for these headers@@ -2232,7 +2269,8 @@ void ASBeautifier::computePreliminaryIndentation() 			        || (*headerStack)[i] == &ASResource::AS_UNION 			        || (*headerStack)[i] == &ASResource::AS_INTERFACE 			        || (*headerStack)[i] == &ASResource::AS_THROWS-			        || (*headerStack)[i] == &ASResource::AS_STATIC)){+			        || (*headerStack)[i] == &ASResource::AS_STATIC+			        || isBraceInConditionParen)){ 				++indentCount; 			// logIndent(6); 					}@@ -2242,7 +2280,8 @@ void ASBeautifier::computePreliminaryIndentation() 		{ 			//GL37 			if (!(i > 0 && (*headerStack)[i - 1] != &ASResource::AS_OPEN_BRACE-			        && (*headerStack)[i] == &ASResource::AS_OPEN_BRACE)){+			        && (*headerStack)[i] == &ASResource::AS_OPEN_BRACE+			        && !isBraceInStatementParen)){ 				++indentCount;  					// logIndent(7);@@ -2382,7 +2421,7 @@ void ASBeautifier::computePreliminaryIndentation() 	// logIndent(17);  			}-	if (isInConditional){+	if (isInConditional && parenDepth > 0){ 		--indentCount; 		// logIndent(18); @@ -2423,6 +2462,7 @@ void ASBeautifier::adjustParsedLineIndentation(size_t iPrelim, bool isInExtraHea 	         && lineBeginsWithOpenBrace 	         && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum) 	         && (headerStack->size() > 1 && (*headerStack)[headerStack->size() - 2] != &ASResource::AS_OPEN_BRACE)+	         && !(!parenDepthStack->empty() && parenDepthStack->back() > 0)	// a brace within parens is not the header's block 	         && shouldIndentBracedLine) 	{ 		--indentCount;@@ -2463,12 +2503,7 @@ void ASBeautifier::adjustParsedLineIndentation(size_t iPrelim, bool isInExtraHea 			// logIndent(24); 	} -	if (indentCount < 0)-	{--		indentCount = 0;-		// logIndent(25);-	}+	indentCount = std::max(0, indentCount); 	// take care of extra brace indentation option... 	if (!lineStartsInComment 	        && braceIndent@@ -2520,7 +2555,7 @@ int ASBeautifier::adjustIndentCountForBreakElseIfComments() const { 	assert(isElseHeaderIndent && !tempStacks->empty()); 	int indentCountIncrement = 0;-	std::vector<const std::string*>* lastTempStack = tempStacks->back();+	std::vector<const std::string*>* lastTempStack = tempStacks->back().get(); 	if (lastTempStack != nullptr) 	{ 		for (const std::string* const lastTemp : *lastTempStack)@@ -2560,7 +2595,7 @@ void ASBeautifier::adjustObjCMethodDefinitionIndentation(std::string_view line_) 		if (shouldAlignMethodColon && objCColonAlignSubsequent != -1) 		{ 			std::string convertedLine = getIndentedSpaceEquivalent(line_);-			colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine);+			colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine).value_or(-1); 			int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength; 			if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment) 				colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;@@ -2594,7 +2629,7 @@ void ASBeautifier::adjustObjCMethodCallIndentation(std::string_view line_) 			bracePosObjCMethodAlignment = convertedLine.find('['); 			keywordIndentObjCMethodAlignment = 			    getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);-			colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine);+			colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine).value_or(-1); 			if (colonIndentObjCMethodAlignment >= 0) 			{ 				int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;@@ -2606,7 +2641,7 @@ void ASBeautifier::adjustObjCMethodCallIndentation(std::string_view line_) 		} 		else 		{-			if (findObjCColonAlignment(line_) != -1)+			if (findObjCColonAlignment(line_).has_value()) 			{ 				if (colonIndentObjCMethodAlignment < 0) 					spaceIndentCount += computeObjCColonAlignment(line_, objCColonAlignSubsequent);@@ -2659,7 +2694,7 @@ void ASBeautifier::clearObjCMethodDefinitionAlignment()  * Find the first alignment colon on a line.  * Ternary operators (?) are bypassed.  */-int ASBeautifier::findObjCColonAlignment(std::string_view line) const+std::optional<int> ASBeautifier::findObjCColonAlignment(std::string_view line) const { 	bool haveTernary = false; 	for (size_t i = 0; i < line.length(); i++)@@ -2678,9 +2713,9 @@ int ASBeautifier::findObjCColonAlignment(std::string_view line) const 			haveTernary = false; 			continue; 		}-		return i;+		return static_cast<int>(i); 	}-	return -1;+	return std::nullopt; }  /* chatgpt@@ -2719,10 +2754,10 @@ int ASBeautifier::findObjCColonAlignment(const std::string& line) const  */ int ASBeautifier::computeObjCColonAlignment(std::string_view line, int colonAlignPosition) const {-	int colonPosition = findObjCColonAlignment(line);-	if (colonPosition < 0 || colonPosition > colonAlignPosition)+	std::optional<int> colonPosition = findObjCColonAlignment(line);+	if (!colonPosition.has_value() || *colonPosition > colonAlignPosition) 		return indentLength;-	return (colonAlignPosition - colonPosition);+	return (colonAlignPosition - *colonPosition); }  /*@@ -2789,6 +2824,83 @@ std::string ASBeautifier::getIndentedSpaceEquivalent(std::string_view line_) con 	return convertedLine; } +/**+ * Determine if the text following an 'if' at index is a C++23 consteval condition,+ * like 'if consteval', 'if !consteval' or 'if not consteval'.+ * @return the index after 'consteval', or npos if it is not a consteval condition.+ */+size_t ASBeautifier::findConstevalConditionEnd(std::string_view line, size_t index) const+{+	if (!isCStyle())+		return std::string_view::npos;+	size_t next = line.find_first_not_of(" \t", index);+	if (next == std::string_view::npos)+		return std::string_view::npos;+	if (line[next] == '!')+		next = line.find_first_not_of(" \t", next + 1);+	else if (getCurrentWord(line, next) == "not")+		next = line.find_first_not_of(" \t", next + 3);+	if (next == std::string_view::npos || getCurrentWord(line, next) != "consteval")+		return std::string_view::npos;+	return next + 9;+}++/**+ * Determine if a line continues a function declarator or a template header+ * with a C++20 requires-clause or C++26 contract specifiers, like+ *     template<class T>               int f(int a)+ *         requires C<T>                   pre(a > 0)+ * Such a line is indented by one level.+ * Must be called before the line is parsed.+ */+bool ASBeautifier::isDeclarationContinuationLine(std::string_view line) const+{+	if (!isCStyle() || isInDefine || isInComment || parenDepth > 0+	        || !continuationIndentStack->empty() || !isTopLevel())+		return false;++	// the previous code line must not be terminated+	if (currentNonSpaceCh == ';' || currentNonSpaceCh == '{' || currentNonSpaceCh == '}'+	        || currentNonSpaceCh == ':' || currentNonSpaceCh == ',')+		return false;++	size_t start = line.find_first_not_of(" \t");+	if (start == std::string_view::npos)+		return false;+	std::string_view word = getCurrentWord(line, start);+	if (word == ASResource::AS_REQUIRES)+		return true;+	if (word == "pre" || word == "post")+	{+		size_t next = line.find_first_not_of(" \t", start + word.length());+		return next != std::string_view::npos && line[next] == '(';+	}+	return false;+}++/**+ * Determine if a line is a C++20 'using enum X;' (or other using-declaration)+ * directly in a switch block before the first case label, like+ *     switch (c)+ *     {+ *     using enum Color;+ *     case red:+ * Such a line is unindented like a case label.+ * Must be called before the line is parsed.+ */+bool ASBeautifier::isUsingBeforeFirstCase(std::string_view line) const+{+	if (!isCStyle() || isInDefine || isInComment || parenDepth > 0 || isContinuation+	        || !continuationIndentStack->empty()+	        || switchCaseStack.empty() || switchCaseStack.back().second+	        || switchCaseStack.back().first != headerStack->size())+		return false;++	size_t start = line.find_first_not_of(" \t");+	return start != std::string_view::npos+	       && getCurrentWord(line, start) == ASResource::AS_USING;+}+ /**  * Determine if an item is at a top level.  */@@ -2820,7 +2932,7 @@ bool ASBeautifier::isTopLevel() const  bool ASBeautifier::handleHeaderSection(std::string_view line, size_t* i, bool closingBraceReached, bool *haveCaseIndent) {-	const std::string* newHeader = findHeader(line, *i, headers);+	const std::string* newHeader = findHeader(line, *i, headers.get());  	// java can have a 'default' not in a switch 	if (newHeader == &ASResource::AS_DEFAULT@@ -2852,7 +2964,7 @@ bool ASBeautifier::handleHeaderSection(std::string_view line, size_t* i, bool cl  		std::vector<const std::string*>* lastTempStack = nullptr; 		if (!tempStacks->empty())-			lastTempStack = tempStacks->back();+			lastTempStack = tempStacks->back().get();  		// if a new block is opened, push a new stack into tempStacks to hold the 		// future list of headers in the new block.@@ -2866,17 +2978,28 @@ bool ASBeautifier::handleHeaderSection(std::string_view line, size_t* i, bool cl 				headerStack->pop_back(); 		} +		// suppress extra indentation for 'if' that follows 'else' on the previous line+		// (when break-elseifs has split them onto separate lines)+		if (newHeader == &ASResource::AS_IF+		        && previousLastLineHeader == &ASResource::AS_ELSE+		        && noIndentIfAfterElse)+		{+			if (!headerStack->empty())+				headerStack->pop_back();+			--indentCount;+		}+ 		// take care of 'else' 		else if (newHeader == &ASResource::AS_ELSE && !lambdaDepth) 		{ 			if (lastTempStack != nullptr) 			{-				int indexOfIf = indexOf(*lastTempStack, &ASResource::AS_IF);-				if (indexOfIf != -1)+				std::optional<int> indexOfIf = indexOf(*lastTempStack, &ASResource::AS_IF);+				if (indexOfIf.has_value()) 				{ 					// recreate the header list in headerStack up to the previous 'if' 					// from the temporary snapshot stored in lastTempStack.-					int restackSize = lastTempStack->size() - indexOfIf - 1;+					int restackSize = lastTempStack->size() - *indexOfIf - 1; 					for (int r = 0; r < restackSize; r++) 					{ 						headerStack->emplace_back(lastTempStack->back());@@ -2901,12 +3024,12 @@ bool ASBeautifier::handleHeaderSection(std::string_view line, size_t* i, bool cl 		{ 			if (lastTempStack != nullptr) 			{-				int indexOfDo = indexOf(*lastTempStack, &ASResource::AS_DO);-				if (indexOfDo != -1)+				std::optional<int> indexOfDo = indexOf(*lastTempStack, &ASResource::AS_DO);+				if (indexOfDo.has_value()) 				{ 					// recreate the header list in headerStack up to the previous 'do' 					// from the temporary snapshot stored in lastTempStack.-					int restackSize = lastTempStack->size() - indexOfDo - 1;+					int restackSize = lastTempStack->size() - *indexOfDo - 1; 					for (int r = 0; r < restackSize; r++) 					{ 						headerStack->emplace_back(lastTempStack->back());@@ -2922,14 +3045,14 @@ bool ASBeautifier::handleHeaderSection(std::string_view line, size_t* i, bool cl 		{ 			if (lastTempStack != nullptr) 			{-				int indexOfTry = indexOf(*lastTempStack, &ASResource::AS_TRY);-				if (indexOfTry == -1)+				std::optional<int> indexOfTry = indexOf(*lastTempStack, &ASResource::AS_TRY);+				if (!indexOfTry.has_value()) 					indexOfTry = indexOf(*lastTempStack, &ASResource::AS_CATCH);-				if (indexOfTry != -1)+				if (indexOfTry.has_value()) 				{ 					// recreate the header list in headerStack up to the previous 'try' 					// from the temporary snapshot stored in lastTempStack.-					int restackSize = lastTempStack->size() - indexOfTry - 1;+					int restackSize = lastTempStack->size() - *indexOfTry - 1; 					for (int r = 0; r < restackSize; r++) 					{ 						headerStack->emplace_back(lastTempStack->back());@@ -2947,6 +3070,8 @@ bool ASBeautifier::handleHeaderSection(std::string_view line, size_t* i, bool cl 		else if (newHeader == &ASResource::AS_CASE) 		{ 			isInCase = true;+			if (!switchCaseStack.empty() && switchCaseStack.back().first <= headerStack->size())+				switchCaseStack.back().second = true; 			if (!*haveCaseIndent) 			{ 				*haveCaseIndent = true;@@ -2959,6 +3084,8 @@ bool ASBeautifier::handleHeaderSection(std::string_view line, size_t* i, bool cl 		else if (newHeader == &ASResource::AS_DEFAULT) 		{ 			isInCase = true;+			if (!switchCaseStack.empty() && switchCaseStack.back().first <= headerStack->size())+				switchCaseStack.back().second = true; 			--indentCount; 			// logIndent(33); 		}@@ -2987,7 +3114,14 @@ bool ASBeautifier::handleHeaderSection(std::string_view line, size_t* i, bool cl 		{ 			headerStack->emplace_back(newHeader); 			isContinuation = false;-			if (indexOf(*nonParenHeaders, newHeader) == -1)+			// 'if consteval' has no paren that would end the conditional,+			// the following brace always opens a block+			if (newHeader == &ASResource::AS_IF+			        && findConstevalConditionEnd(line, *i + newHeader->length()) != std::string_view::npos)+			{+				isInConstevalCondition = true;+			}+			else if (!indexOf(*nonParenHeaders, newHeader).has_value()) 			{ 				isInConditional = true; 			}@@ -3001,7 +3135,7 @@ bool ASBeautifier::handleHeaderSection(std::string_view line, size_t* i, bool cl 		return false; 	}  // newHeader != nullptr -	if (findHeader(line, *i, preCommandHeaders) != nullptr)+	if (findHeader(line, *i, preCommandHeaders.get()) != nullptr) 		// must be after function arguments 		if (prevNonSpaceCh == ')') 			foundPreCommandHeader = true;@@ -3117,9 +3251,11 @@ bool ASBeautifier::handleColonSection(std::string_view line, size_t* i, bool tab 		++*i; 		return false; 	}-	else if (isInQuestion)		// NOLINT+	else if (questionMarkCount > 0)		// NOLINT 	{-		// do nothing special+		// the ':' of a ?: sequence, do nothing special+		// #609 consume the '?' so it is not restored after a following block+		--questionMarkCount; 	} 	else if (parenDepth > 0) 	{@@ -3224,23 +3360,22 @@ bool ASBeautifier::handleColonSection(std::string_view line, size_t* i, bool tab  void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, char* ch) {+	int questionMarkCountAfterBlock = 0;	// a block like a lambda body does not end a ?: sequence 	isInAssignment = isInInitializerList = false; 	quoteContinuationIndent = 0; 	if (*ch == '}') 	{ 		// Improved lambda end handling with depth tracking-		if ( !lambdaDepthStack->empty())+		if (!lambdaDepthStack->empty()+		        && lambdaBraceDepthStack->back() == braceBlockStateStack->size()) 		{-			// Check if this brace ends a lambda body-			if (lambdaDepth && braceBlockStateStack->size() > 1 && braceBlockStateStack->back())+			// this brace closes a lambda body+			popLambda();+			lambdaDepth--;+			if (lambdaDepthStack->empty()) 			{-				// This was a lambda body, pop the lambda depth-				lambdaDepthStack->pop_back();-				lambdaDepth--;-				if (lambdaDepth == 0)-				{-					lambdaIndicator = false;-				}+				lambdaDepth = 0;+				lambdaIndicator = false; 			} 		} @@ -3249,6 +3384,7 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha 		{ 			bool braceBlockState = braceBlockStateStack->back(); 			braceBlockStateStack->pop_back();+			lambdaBodyStateStack->pop_back(); 			if (!braceBlockState) 			{ 				if (!continuationIndentStackSizeStack->empty())@@ -3275,15 +3411,43 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha  		++lineClosingBlocksNum; -		if (!continuationIndentStackSizeStack->empty())+		bool isParenBlockSaved = !parenDepthStack->empty()+		                         && !parenBlockStateStack->empty()+		                         && parenBlockStateStack->back().isSaved;+		if (isParenBlockSaved)+		{+			ParenBlockState& saved = parenBlockStateStack->back();+			*continuationIndentStack = std::move(saved.continuationIndents);+			*continuationIndentStackSizeStack = std::move(saved.continuationIndentSizes);+			isInClassInitializer = saved.isInClassInitializer;+			isInClassHeaderTab = saved.isInClassHeaderTab;+		}+		else if (!continuationIndentStackSizeStack->empty()) 			popLastContinuationIndent(); +		// the closing brace of a 'new' initializer within parens aligns with its opening brace+		int closingBraceSpaceIndent = blockSpaceIndent; 		if (!parenDepthStack->empty()) 		{ 			parenDepth = parenDepthStack->back(); 			parenDepthStack->pop_back();+			if (!parenBlockStateStack->empty())+			{+				blockSpaceIndent = parenBlockStateStack->back().prevBlockSpaceIndent;+				parenBlockStateStack->pop_back();+			} 			isContinuation = blockStatementStack->back(); 			blockStatementStack->pop_back();+			if (!blockConditionalStack->empty())+			{+				isInConditional = blockConditionalStack->back();+				blockConditionalStack->pop_back();+			}+			if (!blockQuestionStack->empty())+			{+				questionMarkCountAfterBlock = blockQuestionStack->back();+				blockQuestionStack->pop_back();+			}  			if (isContinuation) 				blockTabCount--;@@ -3291,7 +3455,7 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha  		*closingBraceReached = true; 		if (i == 0)-			spaceIndentCount = 0;+			spaceIndentCount = closingBraceSpaceIndent; 		isInAsmBlock = false; 		isInAsm = isInAsmOneLine = isInQuote = isInTemplate = false;	// close these just in case @@ -3300,8 +3464,8 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha 			isInStruct = false; 		} -		int headerPlace = indexOf(*headerStack, &ASResource::AS_OPEN_BRACE);-		if (headerPlace != -1)+		std::optional<int> headerPlace = indexOf(*headerStack, &ASResource::AS_OPEN_BRACE);+		if (headerPlace.has_value()) 		{ 			const std::string* popped = headerStack->back(); @@ -3311,6 +3475,8 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha 				popped = headerStack->back(); 			} 			headerStack->pop_back();+			while (!switchCaseStack.empty() && switchCaseStack.back().first > headerStack->size())+				switchCaseStack.pop_back();  			if (headerStack->empty()) 				g_preprocessorCppExternCBrace = 0;@@ -3323,11 +3489,7 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha 				shouldIndentBracedLine = false;  			if (!tempStacks->empty())-			{-				std::vector<const std::string*>* temp = tempStacks->back(); 				tempStacks->pop_back();-				delete temp;-			} 		}  		*ch = ' '; // needed due to cases such as '}else{', so that headers ('else' in this case) will be identified...@@ -3342,13 +3504,17 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha 		* (such as a previous 'if' for an 'else' header) within the tempStacks, 		* and recreates the temporary snapshot by manipulating the tempStacks. 		*/-	if (!tempStacks->back()->empty())-		while (!tempStacks->back()->empty())-			tempStacks->back()->pop_back();-	while (!headerStack->empty() && headerStack->back() != &ASResource::AS_OPEN_BRACE)+	// a block closed within parens (e.g. a lambda in 'if (...)') does not end the header's statement+	if (!(*closingBraceReached && parenDepth > 0)) 	{-		tempStacks->back()->emplace_back(headerStack->back());-		headerStack->pop_back();+		if (!tempStacks->back()->empty())+			while (!tempStacks->back()->empty())+				tempStacks->back()->pop_back();+		while (!headerStack->empty() && headerStack->back() != &ASResource::AS_OPEN_BRACE)+		{+			tempStacks->back()->emplace_back(headerStack->back());+			headerStack->pop_back();+		} 	}  	if (parenDepth == 0 && *ch == ';')@@ -3356,6 +3522,9 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha 		isContinuation = false; 		isInClassInitializer = false; +		while (!lambdaBraceDepthStack->empty() && lambdaBraceDepthStack->back() == 0)+			popLambda();+ 		if (lambdaDepth <= 1 || (lastLambdaDepth == lambdaDepth && lambdaDepthStack->size() == 0)){ 			lambdaIndicator = false; 			lambdaDepth = 0;@@ -3375,7 +3544,7 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha 	isInEnum = false; 	isInEnumTypeID = false; -	isInQuestion = false;+	questionMarkCount = questionMarkCountAfterBlock; 	isInTemplate = false; 	isInObjCInterface = false; 	foundPreCommandHeader = false;@@ -3400,12 +3569,8 @@ void ASBeautifier::handleParens(std::string_view line, size_t i, bool tabIncreme  			if (line.find("struct ", 0) > i)        // if not on this line #526, GH #12 				indentCount -= classInitializerIndents;-			if (indentCount < 0){-				indentCount = 0;-				// logIndent(40);--			}-						}+			indentCount = std::max(0, indentCount);+		}  		if (parenDepth == 0) 		{@@ -3417,6 +3582,20 @@ void ASBeautifier::handleParens(std::string_view line, size_t i, bool tabIncreme 		if (ch == '[') 		{ 			++squareBracketCount;+			// #606 a '[' not following a name, ']' or ')' starts a lambda capture, not a subscript+			isLastSquareBracketLambda = isCStyle()+			                            && !isLegalNameChar(prevNonSpaceCh)+			                            && prevNonSpaceCh != ']'+			                            && prevNonSpaceCh != ')';+			// the matching ']' ends the capture, a following '{' opens the lambda body;+			// '[[' starts an attribute, not a capture+			size_t prevCodePos = i > 0 ? line.find_last_not_of(" \t", i - 1) : std::string_view::npos;+			bool isAfterReturn = prevCodePos != std::string_view::npos && prevCodePos >= 5+			                     && line.compare(prevCodePos - 5, 6, "return") == 0+			                     && (prevCodePos == 5 || !isLegalNameChar(line[prevCodePos - 6]));+			if ((isLastSquareBracketLambda || (isCStyle() && isAfterReturn)) && !isObjCStyle()+			        && prevNonSpaceCh != '[' && peekNextChar(line, i) != '[')+				lambdaCaptureParenDepth = parenDepth; 			// #525 Maybe check for opening brace in the line 			if (squareBracketCount == 1 && isObjCStyle() && line.find('{', i + 1 ) == std::string::npos) 			{@@ -3447,13 +3626,20 @@ void ASBeautifier::handleParens(std::string_view line, size_t i, bool tabIncreme 					isLambdaCapture = true; 				} +				// '[[' starts an attribute, not a capture list+				if (prevNonSpaceCh == '[' || peekNextChar(line, i) == '[')+					isLambdaCapture = false;+ 				if (isLambdaCapture) 				{ 					lambdaIndicator = true; 					lambdaDepth++; -					lambdaDepthStack->push_back(i);-					lambdaEndIndent = lambdaStartIndent = i;+					// the column is relative to the line, so add the offset of enclosing lambdas+					// and the continuation indent of the line (e.g. '| transform([](...)' in a pipeline)+					lambdaDepthStack->push_back(static_cast<int>(i) + lambdaStartIndent + spaceIndentCount);+					lambdaParenDepthStack->push_back(parenDepth - 1);	// depth outside the '['+					lambdaBraceDepthStack->push_back(0);	// body brace not yet seen 				} 			} 		}@@ -3478,7 +3664,21 @@ void ASBeautifier::handleParens(std::string_view line, size_t i, bool tabIncreme 				isImmediatelyPostObjCMethodCall = true; 		} 		foundPreCommandHeader = false;+		if (ch == ']' && parenDepth == lambdaCaptureParenDepth)+		{+			isInLambdaIntroducer = true;+			lambdaIntroducerParenDepth = parenDepth - 1;+			lambdaCaptureParenDepth = -1;+		} 		parenDepth--;+		if (isInLambdaIntroducer && parenDepth < lambdaIntroducerParenDepth)+			isInLambdaIntroducer = false;+		if (parenDepth < newKeywordParenDepth)+			newKeywordParenDepth = -1;++		while (!lambdaBraceDepthStack->empty() && lambdaBraceDepthStack->back() == 0+		        && lambdaParenDepthStack->back() > parenDepth)+			popLambda();  		if (parenDepth == 0) 		{@@ -3511,17 +3711,44 @@ void ASBeautifier::handleClosingParen(std::string_view line, size_t i, bool tabI { 	// first, check if '{' is a block-opener or a static-array opener -	bool isBlockOpener = ((prevNonSpaceCh == '{' && braceBlockStateStack->back())+	// #606 isNonInStatementArray may still be set by an enclosing brace (e.g. a lambda body+	// like 'f([&]\n{'), so it must not turn an inline brace-init like 'Type{1, 2}' into a block+	size_t nextCodePos = line.find_first_not_of(" \t", i + 1);+	bool isInlineBraceInit = isCStyle()+	                         && (isLegalNameChar(prevNonSpaceCh) || prevNonSpaceCh == '>')+	                         && i > line.find_first_not_of(" \t")+	                         && nextCodePos != std::string::npos+	                         && line.compare(nextCodePos, 2, "//") != 0+	                         && line.compare(nextCodePos, 2, "/*") != 0;++	// the body of a lambda like '[](int n) -> int {', '[]() mutable {' or 'return [x] {';+	// a '[] {' within parens is left to the existing checks+	bool isLambdaBodyBrace = isInLambdaIntroducer+	                         && parenDepth == lambdaIntroducerParenDepth+	                         && (prevNonSpaceCh != ']' || parenDepth == 0);+	isInLambdaIntroducer = false;++	// the brace follows a 'new' expression at the current paren level, e.g. 'f(new Bar()\n{'+	bool isNewInitializerBrace = (isJavaStyle() || isSharpStyle())+	                             && parenDepth > 0+	                             && parenDepth == newKeywordParenDepth;++	// #308 a nested array within an argument list like 'f(a, { {' is not a block+	bool isNestedArrayArgument = parenDepth > 0 && i > line.find_first_not_of(" \t");++	bool isBlockOpener =((prevNonSpaceCh == '{' && braceBlockStateStack->back()) 	                      || prevNonSpaceCh == '}' 	                      || prevNonSpaceCh == ')' 	                      || prevNonSpaceCh == ';'-	                      || peekNextChar(line, i) == '{'+	                      || (peekNextChar(line, i) == '{' && !isNestedArrayArgument) 	                      || isInTrailingReturnType+	                      || isInConstevalCondition+	                      || isLambdaBodyBrace 	                      || foundPreCommandHeader 	                      || foundPreCommandMacro 	                      || isInClassHeader 	                      || (isInClassInitializer && !isLegalNameChar(prevNonSpaceCh))-	                      || (isNonInStatementArray && !isInClassInitializer)+	                      || (isNonInStatementArray && !isInClassInitializer && !isInlineBraceInit) 	                      || isInObjCMethodDefinition 	                      || isInObjCInterface 	                      || isSharpAccessor@@ -3549,8 +3776,34 @@ void ASBeautifier::handleClosingParen(std::string_view line, size_t i, bool tabI 	}  	// GL28 fix initializer lists like x({a.x=0;})--	isInInitializerList = isCStyle() && isBlockOpener && (prevNonSpaceCh == '(' || prevNonSpaceCh == '=');+	// https://gitlab.com/saalen/astyle/-/work_items/108+	// direct-list-init like 'A var_a { ... }': prev char ends an identifier+	// or template/array close, and we are not inside a class/enum header, a+	// control-flow header (do/try/else/...), or a class initializer.+	// Also exclude block-scope openers like 'namespace xxx {' or 'extern "C" {'+	// where the brace opens a scope rather than initializing a variable.+	// For extern "C", prevNonSpaceCh is not reliable here: it is not updated+	// while scanning the quoted "C" token, so it still holds a stale legal+	// identifier character left over from 'extern', which would otherwise+	// make isDirectBraceInit true below.+	bool isPrevHeaderBlockScope = (!headerStack->empty()+	                               && (headerStack->back() == &ASResource::AS_NAMESPACE+	                                   || headerStack->back() == &ASResource::AS_MODULE))+	                              || isInExternC;++	bool isDirectBraceInit = isCStyle() && isBlockOpener+	                         && (isLegalNameChar(prevNonSpaceCh)+	                             || prevNonSpaceCh == '>'+	                             || (prevNonSpaceCh == ']' && !isLastSquareBracketLambda))+	                         && !isInClassHeader+	                         && !isInClassInitializer+	                         && !isInEnum+	                         && !isPrevHeaderBlockScope+	                         && !foundPreCommandHeader   // added #112+	                         && !isLambdaBodyBrace+	                         && currentHeader == nullptr;++	isInInitializerList = isCStyle() && isBlockOpener && (prevNonSpaceCh == '(' || prevNonSpaceCh == '=' || isDirectBraceInit);  	if (!isBlockOpener && currentHeader != nullptr) 	{@@ -3564,6 +3817,15 @@ void ASBeautifier::handleClosingParen(std::string_view line, size_t i, bool tabI  	// do not use emplace_back on vector<bool> until supported by macOS 	braceBlockStateStack->push_back(isBlockOpener);+	// a lambda body like '[&] {' or '[](int n) mutable -> int {' contains statements,+	// even if the formatter treats its brace as an array brace+	lambdaBodyStateStack->push_back(isCStyle() && isBlockOpener+	                               && (isLambdaBodyBrace || (prevNonSpaceCh == ']' && isLastSquareBracketLambda)));++	// the first brace after a lambda capture opens the lambda body+	if (!lambdaBraceDepthStack->empty() && lambdaBraceDepthStack->back() == 0+	        && lambdaParenDepthStack->back() == parenDepth)+		lambdaBraceDepthStack->back() = braceBlockStateStack->size();  	if (!isBlockOpener) 	{@@ -3633,8 +3895,24 @@ void ASBeautifier::handleClosingParen(std::string_view line, size_t i, bool tabI  	// is a brace inside a paren? 	parenDepthStack->emplace_back(parenDepth);+	// a block within parens (e.g. a lambda argument) must not lose the state+	// of the enclosing statement, it is restored at the closing brace+	ParenBlockState parenBlockState;+	if (parenDepth > 0)+	{+		parenBlockState.isSaved = true;+		parenBlockState.continuationIndents = *continuationIndentStack;+		parenBlockState.continuationIndentSizes = *continuationIndentStackSizeStack;+		parenBlockState.isInClassInitializer = isInClassInitializer;+		parenBlockState.isInClassHeaderTab = isInClassHeaderTab;+	}+	parenBlockState.prevBlockSpaceIndent = blockSpaceIndent;+	parenBlockStateStack->emplace_back(std::move(parenBlockState)); 	// do not use emplace_back on vector<bool> until supported by macOS 	blockStatementStack->push_back(isContinuation);+	blockConditionalStack->push_back(isInConditional);+	blockQuestionStack->push_back(questionMarkCount);+	isInConditional = false;  	if (!continuationIndentStack->empty()) 	{@@ -3644,30 +3922,44 @@ void ASBeautifier::handleClosingParen(std::string_view line, size_t i, bool tabI 		if (isInClassInitializer || isInClassHeaderTab) 		{ 			if (lineBeginsWithOpenBrace || lineBeginsWithComma)-				spaceIndentCount = 0;+				spaceIndentCount = blockSpaceIndent; 		}-		else-			spaceIndentCount = 0;+		else if (lineBeginsWithOpenBrace)+			spaceIndentCount = blockSpaceIndent; 	} +	// #478 a C#/Java object initializer or anonymous class like 'f(a,\n new Bar()\n{'+	// keeps the indent of the 'new' argument instead of falling back to the statement+	if (isNewInitializerBrace)+	{+		blockSpaceIndent = newKeywordSpaceIndent;+		if (lineBeginsWithOpenBrace)+			spaceIndentCount = blockSpaceIndent;+	}+	newKeywordParenDepth = -1;+ 	blockTabCount += (isContinuation ? 1 : 0); 	if (g_preprocessorCppExternCBrace == 3) 		++g_preprocessorCppExternCBrace; 	parenDepth = 0; 	isInTrailingReturnType = false;+	isInConstevalCondition = false; 	isInClassHeader = false; 	isInClassHeaderTab = false; 	isInClassInitializer = false; 	isInEnumTypeID = false; 	isContinuation = false;-	isInQuestion = false;+	questionMarkCount = 0; 	isInLet = false; 	foundPreCommandHeader = false; 	foundPreCommandMacro = false; 	isInExternC = false; -	tempStacks->emplace_back(new std::vector<const std::string*>);+	tempStacks->emplace_back(std::make_unique<std::vector<const std::string*>>());+	bool isSwitchBlock = !headerStack->empty() && headerStack->back() == &ASResource::AS_SWITCH; 	headerStack->emplace_back(&ASResource::AS_OPEN_BRACE);+	if (isSwitchBlock)+		switchCaseStack.emplace_back(headerStack->size(), false); 	lastLineHeader = &ASResource::AS_OPEN_BRACE; } @@ -3677,7 +3969,7 @@ void ASBeautifier::handlePotentialHeaderSection(std::string_view line, size_t* i 	// (otherwise 'struct XXX' statements would be wrongly interpreted...) 	if (!isInTemplate && !(isCStyle() && parenDepth > 0)) 	{-		const std::string* newHeader = findHeader(line, *i, preBlockStatements);+		const std::string* newHeader = findHeader(line, *i, preBlockStatements.get()); 		// CORBA IDL module 		if (newHeader == &ASResource::AS_MODULE) 		{@@ -3725,13 +4017,13 @@ void ASBeautifier::handlePotentialHeaderSection(std::string_view line, size_t* i 			return; 		} 	}-	const std::string* foundIndentableHeader = findHeader(line, *i, indentableHeaders);+	const std::string* foundIndentableHeader = findHeader(line, *i, indentableHeaders.get());  	if (foundIndentableHeader != nullptr) 	{ 		// must bypass the header before registering the in statement 		*i += foundIndentableHeader->length() - 1;-		if (!*isInOperator && !isInTemplate && !isNonInStatementArray)+		if (!*isInOperator && !isInTemplate && !isInNonInStatementArray()) 		{ 			registerContinuationIndent(line, *i, spaceIndentCount, tabIncrementIn, 0, false); 			isContinuation = true;@@ -3753,6 +4045,11 @@ void ASBeautifier::handlePotentialHeaderSection(std::string_view line, size_t* i 	{ 		if (isContinuation && !continuationIndentStack->empty() && prevNonSpaceCh == '=') 			continuationIndentStack->back() = 0;+		if ((isJavaStyle() || isSharpStyle()) && parenDepth > 0)+		{+			newKeywordParenDepth = parenDepth;+			newKeywordSpaceIndent = spaceIndentCount;+		} 	}  	if (isCStyle() && findKeyword(line, *i, ASResource::AS_AUTO) && isTopLevel())@@ -3788,11 +4085,11 @@ void ASBeautifier::handlePotentialHeaderSection(std::string_view line, size_t* i }  -void ASBeautifier::handlePotentialOperatorSection(std::string_view line, size_t* i, bool tabIncrementIn, bool haveAssignmentThisLine, bool isInOperator)+void ASBeautifier::handlePotentialOperatorSection(std::string_view line, size_t* i, bool tabIncrementIn, bool* haveAssignmentThisLine, bool isInOperator) { 	// Check if an operator has been reached.-	const std::string* foundAssignmentOp = findOperator(line, *i, assignmentOperators);-	const std::string* foundNonAssignmentOp = findOperator(line, *i, nonAssignmentOperators);+	const std::string* foundAssignmentOp = findOperator(line, *i, assignmentOperators.get());+	const std::string* foundNonAssignmentOp = findOperator(line, *i, nonAssignmentOperators.get());  	if (foundNonAssignmentOp != nullptr) 	{@@ -3852,7 +4149,9 @@ void ASBeautifier::handlePotentialOperatorSection(std::string_view line, size_t* 		        && !lineStartsWithDot 		        && ( (foundNonAssignmentOp == &ASResource::AS_GR_GR && countLS < 2 ) 		             ||  foundNonAssignmentOp == &ASResource::AS_LS_LS-		             || (foundNonAssignmentOp == &ASResource::AS_DOT && openParenPos == methodNameEndPos && closeParenPos != std::string::npos )))+		             || (foundNonAssignmentOp == &ASResource::AS_DOT && openParenPos == methodNameEndPos && closeParenPos != std::string::npos+		                 // SF #593: a method call ending with a comma (e.g. an initializer list element) is not continued+		                 && !statementEndsWithComma(line, *i) ))) 		{ 			// this will be true if the line begins with the operator 			if (*i < foundNonAssignmentOp->length() && spaceIndentCount == 0)@@ -3873,7 +4172,12 @@ void ASBeautifier::handlePotentialOperatorSection(std::string_view line, size_t* 		if (foundAssignmentOp->length() > 1) 			*i += foundAssignmentOp->length() - 1; -		if (!isInOperator && !isInTemplate && (!isNonInStatementArray || isInEnum || isInStruct))+		// SF #593: a designated initializer '.member = value' within a brace array+		bool isDesignatedInit = foundAssignmentOp == &ASResource::AS_ASSIGN+		                        && isInNonInStatementArray()+		                        && isDesignatedInitializer(line, *i);++		if (!isInOperator && !isInTemplate && (!isInNonInStatementArray() || isInEnum || isInStruct || isDesignatedInit)) 		{ 			// if multiple assignments, align on the previous word 			if (foundAssignmentOp == &ASResource::AS_ASSIGN@@ -3881,10 +4185,11 @@ void ASBeautifier::handlePotentialOperatorSection(std::string_view line, size_t* 			        && statementEndsWithComma(line, *i)) 			{ 				// only one assignment indent per line + GH #10-				if (!haveAssignmentThisLine && line.find(ASResource::AS_SCOPE_RESOLUTION) == std::string::npos)+				// a designated initializer ending with a comma needs no indent+				if (!*haveAssignmentThisLine && !isDesignatedInit && line.find(ASResource::AS_SCOPE_RESOLUTION) == std::string::npos) 				{ 					// register indent at previous word-					haveAssignmentThisLine = true;+					*haveAssignmentThisLine = true; 					int prevWordIndex = getContinuationIndentAssign(line, *i); 					int continuationIndentCount = prevWordIndex + spaceIndentCount + tabIncrementIn; 					continuationIndentStack->emplace_back(continuationIndentCount);@@ -3907,6 +4212,8 @@ void ASBeautifier::handlePotentialOperatorSection(std::string_view line, size_t*  				registerContinuationIndent(line, *i, spaceIndentCount, tabIncrementIn, 0, false); 				isContinuation = true;+				if (isDesignatedInit)+					isInDesignatedInit = true; 			} 		} 	}@@ -3986,11 +4293,7 @@ void ASBeautifier::parseCurrentLine(std::string_view line) 				                      || line.compare(wsSpanEnd, ASResource::AS_GSC_OPEN_COMMENT.length(), ASResource::AS_GSC_OPEN_COMMENT) == 0); 			} 			if (squeezeWhitespace && !isInComment && !isInQuote && !nextTokenIsComment && std::isblank(line[i + 1]) && !std::isblank(line[i - 1]))-			{--				std::pair<size_t, size_t> wsSpan(i, wsSpanEnd - i - 1);-				squeezeWSStack.emplace_back(wsSpan);-			}+				squeezeWSStack.emplace_back(i, wsSpanEnd - i - 1);  			if (ch == '\t') 				tabIncrementIn += convertTabToSpaces(i, tabIncrementIn);@@ -4026,11 +4329,15 @@ void ASBeautifier::parseCurrentLine(std::string_view line) 					if (parenPos != -1) 					{ 						isInVerbatimQuote = true;+						isInMultiLineString = false; 						verbatimDelimiter = line.substr(i + 1, parenPos - i - 1); 					} 				} 				else if (isSharpStyle() && prevCh == '@')+				{ 					isInVerbatimQuote = true;+					isInMultiLineString = false;+				} 				// check for "C" following "extern" 				else if (g_preprocessorCppExternCBrace == 2 && line.compare(i, 3, "\"C\"") == 0) 					++g_preprocessorCppExternCBrace;@@ -4271,7 +4578,7 @@ void ASBeautifier::parseCurrentLine(std::string_view line) 		}  		// handle parentheses-		if ((ch == '(' && !isInInitializerList) || ch == '[' || ch == ')' || ch == ']')+		if (ch == '(' || ch == '[' || ch == ')' || ch == ']') 		{ 			handleParens(line, i, tabIncrementIn, &isInOperator, ch); 			continue;@@ -4296,7 +4603,7 @@ void ASBeautifier::parseCurrentLine(std::string_view line) 		}   // isPotentialHeader  		if (ch == '?')-			isInQuestion = true;+			++questionMarkCount;  		// special handling of colons XXX 533 		if (ch == ':')@@ -4313,10 +4620,18 @@ void ASBeautifier::parseCurrentLine(std::string_view line) 		} 		else if (ch == ',' && (isInEnum || isInStruct) && isNonInStatementArray && !continuationIndentStack->empty()) 			continuationIndentStack->pop_back();+		// SF #593: end of a continued designated initializer+		else if (ch == ',' && isInDesignatedInit && parenDepth == 0)+		{+			if (!continuationIndentStack->empty())+				continuationIndentStack->pop_back();+			isInDesignatedInit = false;+		}  		// handle commas 		// previous "isInStatement" will be from an assignment operator or class initializer-		if (ch == ',' && parenDepth == 0 && !isContinuation && !isNonInStatementArray)+		// https://gitlab.com/saalen/astyle/-/work_items/108+		if (ch == ',' && parenDepth == 0 && !isContinuation && !isNonInStatementArray && !isInInitializerList) 		{ 			// is comma at end of line 			size_t nextChar = line.find_first_not_of(" \t", i + 1);@@ -4350,6 +4665,11 @@ void ASBeautifier::parseCurrentLine(std::string_view line) 		        && (isInClassInitializer || isInClassHeaderTab)) 			spaceIndentCount = 0; +		if ((ch == ';' || ch == ',') && parenDepth <= lambdaIntroducerParenDepth)+			isInLambdaIntroducer = false;+		if ((ch == ';' || ch == ',') && parenDepth <= newKeywordParenDepth)+			newKeywordParenDepth = -1;+ 		// handle ends of statements 		if ((ch == ';' && parenDepth == 0) || ch == '}') 		{@@ -4434,7 +4754,7 @@ void ASBeautifier::parseCurrentLine(std::string_view line)  		if (isPotentialOperator) 		{-			handlePotentialOperatorSection(line, &i, tabIncrementIn, haveAssignmentThisLine, isInOperator);+			handlePotentialOperatorSection(line, &i, tabIncrementIn, &haveAssignmentThisLine, isInOperator); 		} 	}	// end of for loop * end of for loop * end of for loop * end of for loop * end of for loop * }

src/core/astyle/ASEnhancer.cpp

@@ -1,5 +1,5 @@ // ASEnhancer.cpp-// Copyright (c) 2025 The Artistic Style Authors.+// Copyright (c) 2026 The Artistic Style Authors. // This code is licensed under the MIT License. // License.md describes the conditions under which this software may be distributed. @@ -34,7 +34,8 @@ void ASEnhancer::init(int  _fileType,                       bool _preprocBlockIndent,                       bool _preprocDefineIndent,                       bool _emptyLineFill,-                      std::vector<const std::pair<const std::string, const std::string>* >* _indentableMacros)+                      std::vector<const std::pair<const std::string, const std::string>* >* _indentableMacros,+                      bool _preserveIndent) { 	// formatting variables from ASFormatter and ASBeautifier 	ASBase::init(_fileType);@@ -48,6 +49,7 @@ void ASEnhancer::init(int  _fileType, 	preprocDefineIndent = _preprocDefineIndent; 	emptyLineFill = _emptyLineFill; 	indentableMacros = _indentableMacros;+	preserveIndent = _preserveIndent; 	quoteChar = '\'';  	// unindent variables@@ -90,6 +92,9 @@ void ASEnhancer::enhance(std::string& line, bool isInNamespace, bool isInPreproc 	shouldUnindentComment = false; 	lineNumber++; +	if (preserveIndent)+		return;+ 	// check for beginning of event table 	if (nextLineIsEventIndent) 	{

src/core/astyle/ASFormatter.cpp

@@ -19,7 +19,8 @@ // astyle namespace //----------------------------------------------------------------------------- -namespace astyle {+namespace astyle+{  // //-----------------------------------------------------------------------------@@ -31,118 +32,99 @@ namespace astyle {  */ ASFormatter::ASFormatter() {-	sourceIterator = nullptr;-	enhancer = new ASEnhancer;-	preBraceHeaderStack = nullptr;-	braceTypeStack = nullptr;-	parenStack = nullptr;-	structStack = nullptr;-	questionMarkStack = nullptr;-	lineCommentNoIndent = false;-	formattingStyle = STYLE_NONE;-	braceFormatMode = NONE_MODE;-	pointerAlignment = PTR_ALIGN_NONE;-	referenceAlignment = REF_SAME_AS_PTR;-	objCColonPadMode = COLON_PAD_NO_CHANGE;-	lineEnd = LINEEND_DEFAULT;-	squeezeEmptyLineNum = std::string::npos;-	maxCodeLength = std::string::npos;-	isInStruct = false;-	shouldPadCommas = false;-	shouldPadOperators = false;-	negationPadMode = NEGATION_PAD_NO_CHANGE;-	includeDirectivePaddingMode = INCLUDE_PAD_NO_CHANGE;-	shouldPadParensOutside = false;-	shouldPadFirstParen = false;-	shouldPadEmptyParens = false;-	shouldPadParensInside = false;-	shouldPadHeader = false;-	shouldStripCommentPrefix = false;-	shouldUnPadParens = false;-	attachClosingBraceMode = false;-	shouldBreakOneLineBlocks = true;-	shouldBreakOneLineHeaders = false;-	shouldBreakOneLineStatements = true;-	shouldConvertTabs = false;-	shouldIndentCol1Comments = false;-	shouldIndentPreprocBlock = false;-	shouldCloseTemplates = false;-	shouldAttachExternC = false;-	shouldAttachNamespace = false;-	shouldAttachClass = false;-	shouldAttachClosingWhile = false;-	shouldAttachInline = false;-	shouldBreakBlocks = false;-	shouldBreakClosingHeaderBlocks = false;-	shouldBreakClosingHeaderBraces = false;-	shouldDeleteEmptyLines = false;-	shouldBreakReturnType = false;-	shouldBreakReturnTypeDecl = false;-	shouldAttachReturnType = false;-	shouldAttachReturnTypeDecl = false;-	shouldBreakElseIfs = false;-	shouldBreakLineAfterLogical = false;-	shouldAddBraces = false;-	shouldAddOneLineBraces = false;-	shouldRemoveBraces = false;-	shouldPadMethodColon = false;-	shouldPadMethodPrefix = false;-	shouldUnPadMethodPrefix = false;-	shouldPadReturnType = false;-	shouldUnPadReturnType = false;-	shouldPadParamType = false;-	shouldUnPadParamType = false;-	shouldPadBracketsOutside = false;-	shouldPadBracketsInside = false;-	shouldUnPadBrackets = false;-	isInMultlineStatement = false;-	isInExplicitBlock = 0;--	// initialize ASFormatter member std::vectors-	formatterFileType = INVALID_TYPE;		// reset to an invalid type-	headers = new std::vector<const std::string*>;-	nonParenHeaders = new std::vector<const std::string*>;-	preDefinitionHeaders = new std::vector<const std::string*>;-	preCommandHeaders = new std::vector<const std::string*>;-	operators = new std::vector<const std::string*>;-	assignmentOperators = new std::vector<const std::string*>;-	castOperators = new std::vector<const std::string*>;--	// initialize ASEnhancer member std::vectors-	indentableMacros = new std::vector<const std::pair<const std::string, const std::string>* >;+    sourceIterator = nullptr;+    enhancer = std::make_unique<ASEnhancer>();+    lineCommentNoIndent = false;+    formattingStyle = STYLE_NONE;+    braceFormatMode = NONE_MODE;+    pointerAlignment = PTR_ALIGN_NONE;+    referenceAlignment = REF_SAME_AS_PTR;+    objCColonPadMode = COLON_PAD_NO_CHANGE;+    lineEnd = LINEEND_DEFAULT;+    squeezeEmptyLineNum = std::string::npos;+    maxCodeLength = std::string::npos;+    maxCodeLengthMode = MAXCODELENGTH_CODE,+    shouldIgnoreSideCommentLengths = false;+    isInStruct = false;+    structNestingLevel = 0;+    shouldPreserveBraceFormat = false;+    shouldPadCommas = false;+    shouldPadOperators = false;+    negationPadMode = NEGATION_PAD_NO_CHANGE;+    includeDirectivePaddingMode = INCLUDE_PAD_NO_CHANGE;+    shouldPadParensOutside = false;+    shouldPadFirstParen = false;+    shouldPadEmptyParens = false;+    shouldPadParensInside = false;+    shouldPadHeader = false;+    shouldStripCommentPrefix = false;+    shouldUnPadParens = false;+    attachClosingBraceMode = false;+    shouldBreakOneLineBlocks = true;+    shouldBreakOneLineHeaders = false;+    shouldBreakOneLineStatements = true;+    shouldConvertTabs = false;+    shouldIndentCol1Comments = false;+    shouldEndWithSingleNewline = false;+    shouldIndentPreprocBlock = false;+    shouldCloseTemplates = false;+    shouldAttachExternC = false;+    shouldAttachNamespace = false;+    shouldAttachClass = false;+    shouldAttachClosingWhile = false;+    shouldAttachInline = false;+    shouldBreakBlocks = false;+    shouldBreakClosingHeaderBlocks = false;+    shouldLineBetweenMembers = false;+    shouldLineBetweenAllMembers = false;+    needBlankBeforeNextMember = false;+    lineBetweenMembersDoBlank = false;+    lineBetweenMembersPassedClassClose = false;+    shouldBreakClosingHeaderBraces = false;+    shouldDeleteEmptyLines = false;+    shouldBreakReturnType = false;+    shouldBreakReturnTypeDecl = false;+    shouldAttachReturnType = false;+    shouldAttachReturnTypeDecl = false;+    shouldBreakElseIfs = false;+    shouldBreakLineAfterLogical = false;+    shouldAddBraces = false;+    shouldAddOneLineBraces = false;+    shouldRemoveBraces = false;+    shouldRemoveOneLineBraces = false;+    shouldPadMethodColon = false;+    shouldPadMethodPrefix = false;+    shouldUnPadMethodPrefix = false;+    shouldPadReturnType = false;+    shouldUnPadReturnType = false;+    shouldPadParamType = false;+    shouldUnPadParamType = false;+    shouldPadBracketsOutside = false;+    shouldPadBracketsInside = false;+    shouldUnPadBrackets = false;+    shouldUnPadSemicolon = false;+    isInMultlineStatement = false;+    isInExplicitBlock = 0;++    // initialize ASFormatter member std::vectors+    formatterFileType = INVALID_TYPE;		// reset to an invalid type+    headers = std::make_unique<std::vector<const std::string*>>();+    nonParenHeaders = std::make_unique<std::vector<const std::string*>>();+    preDefinitionHeaders = std::make_unique<std::vector<const std::string*>>();+    preCommandHeaders = std::make_unique<std::vector<const std::string*>>();+    operators = std::make_unique<std::vector<const std::string*>>();+    assignmentOperators = std::make_unique<std::vector<const std::string*>>();+    castOperators = std::make_unique<std::vector<const std::string*>>();++    // initialize ASEnhancer member std::vectors+    indentableMacros = std::make_unique<std::vector<const std::pair<const std::string, const std::string>* >>(); }  /**  * Destructor of ASFormatter+ * All member vectors and the enhancer are smart pointers, so cleanup is automatic.  */-ASFormatter::~ASFormatter()-{-	// delete ASFormatter stack std::vectors-	deleteContainer(preBraceHeaderStack);-	deleteContainer(braceTypeStack);-	deleteContainer(parenStack);-	deleteContainer(structStack);-	deleteContainer(questionMarkStack);--	// delete ASFormatter member std::vectors-	formatterFileType = INVALID_TYPE;		// reset to an invalid type-	delete headers;-	delete nonParenHeaders;-	delete preDefinitionHeaders;-	delete preCommandHeaders;-	delete operators;-	delete assignmentOperators;-	delete castOperators;--	// delete ASEnhancer member std::vectors-	delete indentableMacros;--	// must be done when the ASFormatter object is deleted (not ASBeautifier)-	// delete ASBeautifier member std::vectors-	ASBeautifier::deleteBeautifierVectors();--	delete enhancer;-}+ASFormatter::~ASFormatter() = default;  /**  * initialize the ASFormatter.@@ -156,179 +138,193 @@ ASFormatter::~ASFormatter()  */ void ASFormatter::init(ASSourceIterator* si) {-	buildLanguageVectors();-	fixOptionVariableConflicts();-	ASBeautifier::init(si);-	sourceIterator = si;--	enhancer->init(getFileType(),-	               getIndentLength(),-	               getTabLength(),-	               getIndentString() == "\t",-	               getForceTabIndentation(),-	               getNamespaceIndent(),-	               getCaseIndent(),-	               shouldIndentPreprocBlock,-	               getPreprocDefineIndent(),-	               getEmptyLineFill(),-	               indentableMacros);--	initContainer(preBraceHeaderStack, new std::vector<const std::string*>);-	initContainer(parenStack, new std::vector<int>);-	initContainer(structStack, new std::vector<bool>);-	initContainer(questionMarkStack, new std::vector<bool>);-	parenStack->emplace_back(0);               // parenStack must contain this default entry-	initContainer(braceTypeStack, new std::vector<BraceType>);-	braceTypeStack->emplace_back(NULL_TYPE);   // braceTypeStack must contain this default entry-	clearFormattedLineSplitPoints();--	currentHeader = nullptr;-	previousHeader = nullptr;-	currentLine = "";-	readyFormattedLine = "";-	formattedLine = "";-	verbatimDelimiter = "";-	currentChar = ' ';-	previousChar = ' ';-	previousCommandChar = ' ';-	previousNonWSChar = ',';	// not a potential name or operator-	quoteChar = '"';-	preprocBlockEnd = 0;-	charNum = 0;-	checksumIn = 0;-	checksumOut = 0;-	currentLineFirstBraceNum = std::string::npos;-	formattedLineCommentNum = 0;-	leadingSpaces = 0;-	previousReadyFormattedLineLength = std::string::npos;-	preprocBraceTypeStackSize = 0;-	spacePadNum = 0;-	methodAttachCharNum = std::string::npos;-	methodAttachLineNum = 0;-	methodBreakCharNum = std::string::npos;-	methodBreakLineNum = 0;-	nextLineSpacePadNum = 0;-	objCColonAlign = 0;-	templateDepth = 0;-	squareBracketCount = 0;-	parenthesesCount = 0;-	bracesNestingLevel = 0;-	bracesNestingLevelOfStruct = 0;-	squeezeEmptyLineCount = 0;--	runInIndentChars = 0;-	tabIncrementIn = 0;-	previousBraceType = NULL_TYPE;--	isVirgin = true;-	isInVirginLine = true;-	isInLineComment = false;-	isInComment = false;-	isInCommentStartLine = false;-	noTrimCommentContinuation = false;-	isInPreprocessor = false;-	isInPreprocessorDefineDef = false;-	isInPreprocessorBeautify = false;-	doesLineStartComment = false;-	lineEndsInCommentOnly = false;-	lineIsCommentOnly = false;-	lineIsLineCommentOnly = false;-	lineIsEmpty = false;-	isImmediatelyPostCommentOnly = false;-	isImmediatelyPostEmptyLine = false;-	isInClassInitializer = false;-	isInQuote = false;-	isInVerbatimQuote = false;-	checkInterpolation = false;-	haveLineContinuationChar = false;-	isInQuoteContinuation = false;-	isHeaderInMultiStatementLine = false;-	isSpecialChar = false;-	isNonParenHeader = false;-	foundNamespaceHeader = false;-	foundClassHeader = false;-	foundStructHeader = false;-	foundInterfaceHeader = false;-	foundPreDefinitionHeader = false;-	foundPreCommandHeader = false;-	foundPreCommandMacro = false;-	foundTrailingReturnType = false;-	foundCastOperator = false;-	foundQuestionMark = false;-	isInLineBreak = false;-	endOfAsmReached = false;-	endOfCodeReached = false;-	isFormattingModeOff = false;-	isInEnum = false;-	isInContinuedPreProc = false;-	isInStruct = false;-	isInExecSQL = false;-	isInAsm = false;-	isInAsmOneLine = false;-	isInAsmBlock = false;-	isLineReady = false;-	elseHeaderFollowsComments = false;-	caseHeaderFollowsComments = false;-	isPreviousBraceBlockRelated = false;-	isInPotentialCalculation = false;-	needHeaderOpeningBrace = false;-	shouldBreakLineAtNextChar = false;-	shouldKeepLineUnbroken = false;-	shouldReparseCurrentChar = false;-	passedSemicolon = false;-	passedColon = false;-	isImmediatelyPostNonInStmt = false;-	isCharImmediatelyPostNonInStmt = false;-	isInTemplate = false;-	isImmediatelyPostComment = false;-	isImmediatelyPostLineComment = false;-	isImmediatelyPostEmptyBlock = false;-	isImmediatelyPostObjCMethodPrefix = false;-	isImmediatelyPostPreprocessor = false;-	isImmediatelyPostReturn = false;-	isImmediatelyPostThrow = false;-	isImmediatelyPostNewDelete = false;-	isImmediatelyPostOperator = false;-	isImmediatelyPostTemplate = false;-	isImmediatelyPostPointerOrReference = false;-	isCharImmediatelyPostReturn = false;-	isCharImmediatelyPostThrow = false;-	isCharImmediatelyPostNewDelete = false;-	isCharImmediatelyPostOperator = false;-	isCharImmediatelyPostComment = false;-	isPreviousCharPostComment = false;-	isCharImmediatelyPostLineComment = false;-	isCharImmediatelyPostOpenBlock = false;-	isCharImmediatelyPostCloseBlock = false;-	isCharImmediatelyPostTemplate = false;-	isCharImmediatelyPostPointerOrReference = false;-	isInObjCInterface = false;-	isInObjCMethodDefinition = false;-	isInObjCReturnType = false;-	isInObjCParam = false;-	isInObjCSelector = false;-	breakCurrentOneLineBlock = false;-	shouldRemoveNextClosingBrace = false;-	isInBraceRunIn = false;-	returnTypeChecked = false;-	currentLineBeginsWithBrace = false;-	isPrependPostBlockEmptyLineRequested = false;-	isAppendPostBlockEmptyLineRequested = false;-	isIndentablePreprocessor = false;-	isIndentablePreprocessorBlck = false;-	prependEmptyLine = false;-	appendOpeningBrace = false;-	foundClosingHeader = false;-	isImmediatelyPostHeader = false;-	isInHeader = false;-	isInCase = false;-	isInAllocator = false;-	isInMultlineStatement = false;-	isInExplicitBlock = 0;--	isFirstPreprocConditional = false;-	processedFirstConditional = false;-	isJavaStaticConstructor = false;+    buildLanguageVectors();+    fixOptionVariableConflicts();+    ASBeautifier::init(si);+    sourceIterator = si;++    enhancer->init(getFileType(),+                   getIndentLength(),+                   getTabLength(),+                   getIndentString() == "\t",+                   getForceTabIndentation(),+                   getNamespaceIndent(),+                   getCaseIndent(),+                   shouldIndentPreprocBlock,+                   getPreprocDefineIndent(),+                   getEmptyLineFill(),+                   indentableMacros.get(),+                   shouldPreserveIndent);++    // the ASFormatter object is never deleted, so any existing vectors+    // must be replaced (not merely populated) before starting a new file+    preBraceHeaderStack = std::make_unique<std::vector<const std::string*>>();+    parenStack = std::make_unique<std::vector<int>>();+    structStack = std::make_unique<std::vector<bool>>();+    questionMarkStack = std::make_unique<std::vector<bool>>();+    parenStack->emplace_back(0);               // parenStack must contain this default entry+    braceTypeStack = std::make_unique<std::vector<BraceType>>();+    braceTypeStack->emplace_back(BraceType::NULL_TYPE);   // braceTypeStack must contain this default entry+    requiresBodyStack = std::make_unique<std::vector<size_t>>();+    braceQuestionMarkStack = std::make_unique<std::vector<bool>>();+    clearFormattedLineSplitPoints();++    currentHeader = nullptr;+    previousHeader = nullptr;+    currentLine = "";+    readyFormattedLine = "";+    formattedLine = "";+    verbatimDelimiter = "";+    currentChar = ' ';+    previousChar = ' ';+    previousCommandChar = ' ';+    previousNonWSChar = ',';	// not a potential name or operator+    quoteChar = '"';+    preprocBlockEnd = 0;+    charNum = 0;+    checksumIn = 0;+    checksumOut = 0;+    currentLineFirstBraceNum = std::nullopt;+    formattedLineCommentNum = 0;+    leadingSpaces = 0;+    previousReadyFormattedLineLength = std::nullopt;+    preprocBraceTypeStackSize = 0;+    spacePadNum = 0;+    methodAttachCharNum = std::nullopt;+    methodAttachLineNum = 0;+    methodBreakCharNum = std::nullopt;+    methodBreakLineNum = 0;+    nextLineSpacePadNum = 0;+    objCColonAlign = 0;+    templateDepth = 0;+    squareBracketCount = 0;+    parenthesesCount = 0;+    addedBraceStatementParenDepth = 0;+    bracesNestingLevel = 0;+    bracesNestingLevelOfStruct = 0;+    squeezeEmptyLineCount = 0;++    runInIndentChars = 0;+    tabIncrementIn = 0;+    previousBraceType = BraceType::NULL_TYPE;++    isVirgin = true;+    isInVirginLine = true;+    isInLineComment = false;+    isInComment = false;+    isInCommentStartLine = false;+    noTrimCommentContinuation = false;+    isInPreprocessor = false;+    isInPreprocessorDefineDef = false;+    isInPreprocessorBeautify = false;+    doesLineStartComment = false;+    lineEndsInCommentOnly = false;+    lineIsCommentOnly = false;+    lineIsLineCommentOnly = false;+    lineIsEmpty = false;+    isImmediatelyPostCommentOnly = false;+    isImmediatelyPostEmptyLine = false;+    isInClassInitializer = false;+    isInQuote = false;+    isInVerbatimQuote = false;+    checkInterpolation = false;+    haveLineContinuationChar = false;+    isInQuoteContinuation = false;+    isHeaderInMultiStatementLine = false;+    isSpecialChar = false;+    isNonParenHeader = false;+    foundNamespaceHeader = false;+    foundClassHeader = false;+    foundStructHeader = false;+    foundDefinitionAttribute = false;+    foundInterfaceHeader = false;+    foundPreDefinitionHeader = false;+    foundPreCommandHeader = false;+    foundPreCommandMacro = false;+    foundTrailingReturnType = false;+    foundConstevalCondition = false;+    foundRequiresExpression = false;+    foundCastOperator = false;+    foundQuestionMark = false;+    isInLineBreak = false;+    isLineContinuation = false;+    endOfAsmReached = false;+    endOfCodeReached = false;+    isFormattingModeOff = false;+    isInEnum = false;+    isInContinuedPreProc = false;+    isInStruct = false;+    structNestingLevel = 0;+    isInExecSQL = false;+    isInAsm = false;+    isInAsmOneLine = false;+    isInAsmBlock = false;+    isLineReady = false;+    elseHeaderFollowsComments = false;+    caseHeaderFollowsComments = false;+    isPreviousBraceBlockRelated = false;+    isInPotentialCalculation = false;+    needHeaderOpeningBrace = false;+    shouldBreakLineAtNextChar = false;+    shouldKeepLineUnbroken = false;+    shouldReparseCurrentChar = false;+    passedSemicolon = false;+    passedColon = false;+    isImmediatelyPostNonInStmt = false;+    isCharImmediatelyPostNonInStmt = false;+    isInTemplate = false;+    isImmediatelyPostComment = false;+    isImmediatelyPostLineComment = false;+    isImmediatelyPostEmptyBlock = false;+    isImmediatelyPostObjCMethodPrefix = false;+    isImmediatelyPostPreprocessor = false;+    isImmediatelyPostReturn = false;+    isImmediatelyPostThrow = false;+    isImmediatelyPostNewDelete = false;+    isImmediatelyPostOperator = false;+    isImmediatelyPostTemplate = false;+    isImmediatelyPostPointerOrReference = false;+    isCharImmediatelyPostReturn = false;+    isCharImmediatelyPostThrow = false;+    isCharImmediatelyPostNewDelete = false;+    isCharImmediatelyPostOperator = false;+    isCharImmediatelyPostComment = false;+    isPreviousCharPostComment = false;+    isCharImmediatelyPostLineComment = false;+    isCharImmediatelyPostOpenBlock = false;+    isCharImmediatelyPostCloseBlock = false;+    isCharImmediatelyPostTemplate = false;+    isCharImmediatelyPostPointerOrReference = false;+    isInObjCInterface = false;+    isInObjCMethodDefinition = false;+    isInObjCReturnType = false;+    isInObjCParam = false;+    isInObjCSelector = false;+    breakCurrentOneLineBlock = false;+    shouldRemoveNextClosingBrace = false;+    shouldAddClosingBraceAtStatementEnd = false;+    isInBraceRunIn = false;+    returnTypeChecked = false;+    currentLineBeginsWithBrace = false;+    isPrependPostBlockEmptyLineRequested = false;+    isAppendPostBlockEmptyLineRequested = false;+    isIndentablePreprocessor = false;+    isIndentablePreprocessorBlck = false;+    prependEmptyLine = false;+    isPreviousReadyLinePreprocCondStart = false;+    appendOpeningBrace = false;+    appendClosingBrace = false;+    foundClosingHeader = false;+    isImmediatelyPostHeader = false;+    isInHeader = false;+    isInCase = false;+    isInAllocator = false;+    isInMultlineStatement = false;+    isInExplicitBlock = 0;++    isFirstPreprocConditional = false;+    processedFirstConditional = false;+    isJavaStaticConstructor = false; }  /**@@ -337,28 +333,28 @@ void ASFormatter::init(ASSourceIterator* si)  */ void ASFormatter::buildLanguageVectors() {-	if (getFileType() == formatterFileType)  // don't build unless necessary-		return;+    if (getFileType() == formatterFileType)  // don't build unless necessary+        return; -	formatterFileType = getFileType();+    formatterFileType = getFileType(); -	headers->clear();-	nonParenHeaders->clear();-	preDefinitionHeaders->clear();-	preCommandHeaders->clear();-	operators->clear();-	assignmentOperators->clear();-	castOperators->clear();-	indentableMacros->clear();	// ASEnhancer+    headers->clear();+    nonParenHeaders->clear();+    preDefinitionHeaders->clear();+    preCommandHeaders->clear();+    operators->clear();+    assignmentOperators->clear();+    castOperators->clear();+    indentableMacros->clear();	// ASEnhancer -	ASResource::buildHeaders(headers, formatterFileType);-	ASResource::buildNonParenHeaders(nonParenHeaders, formatterFileType);-	ASResource::buildPreDefinitionHeaders(preDefinitionHeaders, formatterFileType);-	ASResource::buildPreCommandHeaders(preCommandHeaders, formatterFileType);-	ASResource::buildOperators(operators, formatterFileType);-	ASResource::buildAssignmentOperators(assignmentOperators);-	ASResource::buildCastOperators(castOperators);-	ASResource::buildIndentableMacros(indentableMacros);	//ASEnhancer+    ASResource::buildHeaders(headers.get(), formatterFileType);+    ASResource::buildNonParenHeaders(nonParenHeaders.get(), formatterFileType);+    ASResource::buildPreDefinitionHeaders(preDefinitionHeaders.get(), formatterFileType);+    ASResource::buildPreCommandHeaders(preCommandHeaders.get(), formatterFileType);+    ASResource::buildOperators(operators.get(), formatterFileType);+    ASResource::buildAssignmentOperators(assignmentOperators.get());+    ASResource::buildCastOperators(castOperators.get());+    ASResource::buildIndentableMacros(indentableMacros.get());	//ASEnhancer }  /**@@ -367,1901 +363,2102 @@ void ASFormatter::buildLanguageVectors()  */ void ASFormatter::fixOptionVariableConflicts() {-	if (formattingStyle == STYLE_ALLMAN)-	{-		setBraceFormatMode(BREAK_MODE);-	}-	else if (formattingStyle == STYLE_JAVA)-	{-		setBraceFormatMode(ATTACH_MODE);-	}-	else if (formattingStyle == STYLE_KR)-	{-		setBraceFormatMode(LINUX_MODE);-	}-	else if (formattingStyle == STYLE_STROUSTRUP)-	{-		setBraceFormatMode(LINUX_MODE);-		setBreakClosingHeaderBracesMode(true);-	}-	else if (formattingStyle == STYLE_WHITESMITH)-	{-		setBraceFormatMode(BREAK_MODE);-		setBraceIndent(true);-		setClassIndent(true);			// avoid hanging indent with access modifiers-		setSwitchIndent(true);			// avoid hanging indent with case statements-	}-	else if (formattingStyle == STYLE_VTK)-	{-		// the unindented class brace does NOT cause a hanging indent like Whitesmith-		setBraceFormatMode(BREAK_MODE);-		setBraceIndentVtk(true);		// sets both braceIndent and braceIndentVtk-		setSwitchIndent(true);			// avoid hanging indent with case statements-	}-	else if (formattingStyle == STYLE_RATLIFF)-	{-		// attached braces can have hanging indents with the closing brace-		setBraceFormatMode(ATTACH_MODE);-		setBraceIndent(true);-		setClassIndent(true);			// avoid hanging indent with access modifiers-		setSwitchIndent(true);			// avoid hanging indent with case statements-	}-	else if (formattingStyle == STYLE_GNU)-	{-		setBraceFormatMode(BREAK_MODE);-		setBlockIndent(true);-	}-	else if (formattingStyle == STYLE_LINUX)-	{-		setBraceFormatMode(LINUX_MODE);-		// always for Linux style-		setMinConditionalIndentOption(MINCOND_ONEHALF);-	}-	else if (formattingStyle == STYLE_HORSTMANN)-	{-		setBraceFormatMode(RUN_IN_MODE);-		setSwitchIndent(true);-	}-	else if (formattingStyle == STYLE_1TBS)-	{-		setBraceFormatMode(LINUX_MODE);-		setAddBracesMode(1);-		setRemoveBracesMode(false);-	}-	else if (formattingStyle == STYLE_GOOGLE)-	{-		setBraceFormatMode(ATTACH_MODE);-		setModifierIndent(true);-		setClassIndent(false);-	}-	else if (formattingStyle == STYLE_MOZILLA)-	{-		setBraceFormatMode(LINUX_MODE);-	}-	else if (formattingStyle == STYLE_WEBKIT)-	{-		setBraceFormatMode(LINUX_MODE);-	}-	else if (formattingStyle == STYLE_PICO)-	{-		setBraceFormatMode(RUN_IN_MODE);-		setAttachClosingBraceMode(true);-		setSwitchIndent(true);-		setBreakOneLineBlocksMode(false);-		setBreakOneLineStatementsMode(false);-		// add-braces won't work for pico, but it could be fixed if necessary-		// both options should be set to true-		if (shouldAddBraces)-			shouldAddOneLineBraces = true;-	}-	else if (formattingStyle == STYLE_LISP)-	{-		setBraceFormatMode(ATTACH_MODE);-		setAttachClosingBraceMode(true);-		setBreakOneLineStatementsMode(false);-		// add-one-line-braces won't work for lisp-		// only shouldAddBraces should be set to true-		if (shouldAddOneLineBraces)-		{-			shouldAddBraces = true;-			shouldAddOneLineBraces = false;-		}-	}-	setMinConditionalIndentLength();-	// if not set by indent=force-tab-x set equal to indentLength-	if (getTabLength() == 0)-		setDefaultTabLength();-	// add-one-line-braces implies keep-one-line-blocks-	if (shouldAddOneLineBraces)-		setBreakOneLineBlocksMode(false);-	// don't allow add-braces and remove-braces-	if (shouldAddBraces || shouldAddOneLineBraces)-		setRemoveBracesMode(false);-	// don't allow break-return-type and attach-return-type-	if (shouldBreakReturnType)-		shouldAttachReturnType = false;-	if (shouldBreakReturnTypeDecl)-		shouldAttachReturnTypeDecl = false;-	// don't allow indent-classes and indent-modifiers-	if (getClassIndent())-		setModifierIndent(false);+    if (shouldPreserveBraceFormat)+    {+        setBraceFormatMode(NONE_MODE);+    }+    else if (formattingStyle == STYLE_ALLMAN)+    {+        setBraceFormatMode(BREAK_MODE);+    }+    else if (formattingStyle == STYLE_JAVA)+    {+        setBraceFormatMode(ATTACH_MODE);+    }+    else if (formattingStyle == STYLE_KR)+    {+        setBraceFormatMode(LINUX_MODE);+    }+    else if (formattingStyle == STYLE_STROUSTRUP)+    {+        setBraceFormatMode(LINUX_MODE);+        setBreakClosingHeaderBracesMode(true);+    }+    else if (formattingStyle == STYLE_WHITESMITH)+    {+        setBraceFormatMode(BREAK_MODE);+        setBraceIndent(true);+        setClassIndent(true);			// avoid hanging indent with access modifiers+        setSwitchIndent(true);			// avoid hanging indent with case statements+    }+    else if (formattingStyle == STYLE_VTK)+    {+        // the unindented class brace does NOT cause a hanging indent like Whitesmith+        setBraceFormatMode(BREAK_MODE);+        setBraceIndentVtk(true);		// sets both braceIndent and braceIndentVtk+        setSwitchIndent(true);			// avoid hanging indent with case statements+    }+    else if (formattingStyle == STYLE_RATLIFF)+    {+        // attached braces can have hanging indents with the closing brace+        setBraceFormatMode(ATTACH_MODE);+        setBraceIndent(true);+        setClassIndent(true);			// avoid hanging indent with access modifiers+        setSwitchIndent(true);			// avoid hanging indent with case statements+    }+    else if (formattingStyle == STYLE_GNU)+    {+        setBraceFormatMode(BREAK_MODE);+        setBlockIndent(true);+    }+    else if (formattingStyle == STYLE_LINUX)+    {+        setBraceFormatMode(LINUX_MODE);+        // always for Linux style+        setMinConditionalIndentOption(MINCOND_ONEHALF);+    }+    else if (formattingStyle == STYLE_HORSTMANN)+    {+        setBraceFormatMode(RUN_IN_MODE);+        setSwitchIndent(true);+    }+    else if (formattingStyle == STYLE_1TBS)+    {+        setBraceFormatMode(LINUX_MODE);+        setAddBracesMode(1);+        setRemoveBracesMode(false);+    }+    else if (formattingStyle == STYLE_GOOGLE)+    {+        setBraceFormatMode(ATTACH_MODE);+        setModifierIndent(true);+        setClassIndent(false);+    }+    else if (formattingStyle == STYLE_MOZILLA)+    {+        setBraceFormatMode(LINUX_MODE);+    }+    else if (formattingStyle == STYLE_WEBKIT)+    {+        setBraceFormatMode(LINUX_MODE);+    }+    else if (formattingStyle == STYLE_PICO)+    {+        setBraceFormatMode(RUN_IN_MODE);+        setAttachClosingBraceMode(true);+        setSwitchIndent(true);+        setBreakOneLineBlocksMode(false);+        setBreakOneLineStatementsMode(false);+        // add-braces won't work for pico, but it could be fixed if necessary+        // both options should be set to true+        if (shouldAddBraces)+            shouldAddOneLineBraces = true;+    }+    else if (formattingStyle == STYLE_LISP)+    {+        setBraceFormatMode(ATTACH_MODE);+        setAttachClosingBraceMode(true);+        setBreakOneLineStatementsMode(false);+        // add-one-line-braces won't work for lisp+        // only shouldAddBraces should be set to true+        if (shouldAddOneLineBraces)+        {+            shouldAddBraces = true;+            shouldAddOneLineBraces = false;+        }+    }+    setMinConditionalIndentLength();+    // if not set by indent=force-tab-x set equal to indentLength+    if (getTabLength() == 0)+        setDefaultTabLength();+    // add-one-line-braces implies keep-one-line-blocks+    if (shouldAddOneLineBraces)+        setBreakOneLineBlocksMode(false);+    // don't allow add-braces and remove-braces+    if (shouldAddBraces || shouldAddOneLineBraces)+    {+        setRemoveBracesMode(false);+        setRemoveOneLineBracesMode(false);+    }+    // don't allow break-return-type and attach-return-type+    if (shouldBreakReturnType)+        shouldAttachReturnType = false;+    if (shouldBreakReturnTypeDecl)+        shouldAttachReturnTypeDecl = false;+    // don't allow indent-classes and indent-modifiers+    if (getClassIndent())+        setModifierIndent(false); }  bool ASFormatter::handleImmediatelyPostHeaderSection() {-	// should braces be added-	if (currentChar != '{'-	        && shouldAddBraces-	        && currentChar != '#'	// don't add to preprocessor-	        && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine)-	        && isOkToBreakBlock(braceTypeStack->back()))-	{-		bool bracesAdded = addBracesToStatement();-		if (bracesAdded && !shouldAddOneLineBraces)-		{-			size_t firstText = currentLine.find_first_not_of(" \t");-			assert(firstText != std::string::npos);-			if ((int) firstText == charNum || shouldBreakOneLineHeaders)-				breakCurrentOneLineBlock = true;-		}-	}-	// should braces be removed-	else if (currentChar == '{' && shouldRemoveBraces)-	{-		bool bracesRemoved = removeBracesFromStatement();-		if (bracesRemoved)-		{-			shouldRemoveNextClosingBrace = true;-			if (isBeforeAnyLineEndComment(charNum))-				spacePadNum--;-			else if (shouldBreakOneLineBlocks-			         || (currentLineBeginsWithBrace-			             && currentLine.find_first_not_of(" \t") != std::string::npos))-				shouldBreakLineAtNextChar = true;-			return false;-		}-	}--	// break 'else-if' if shouldBreakElseIfs is requested-	if (shouldBreakElseIfs-	        && currentHeader == &ASResource::AS_ELSE-	        && isOkToBreakBlock(braceTypeStack->back())-	        && !isBeforeAnyComment()-	        && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine))-	{-		std::string nextText = peekNextText(currentLine.substr(charNum));-		if (!nextText.empty()-		        && isCharPotentialHeader(nextText, 0)-		        && ASBase::findHeader(nextText, 0, headers) == &ASResource::AS_IF)-		{-			isInLineBreak = true;-		}-	}--	// break a header (e.g. if, while, else) from the following statement-	if (shouldBreakOneLineHeaders-	        && peekNextChar() != ' '-	        && (shouldBreakOneLineStatements-	            || (!isHeaderInMultiStatementLine-	                && !isMultiStatementLine()))-	        && isOkToBreakBlock(braceTypeStack->back())-	        && !isBeforeAnyComment())-	{-		if (currentChar == '{')-		{-			if (!currentLineBeginsWithBrace)-			{-				if (isOneLineBlockReached(currentLine, charNum) == 3)-					isInLineBreak = false;-				else-					breakCurrentOneLineBlock = true;-			}-		}-		else if (currentHeader == &ASResource::AS_ELSE)-		{-			std::string nextText = peekNextText(currentLine.substr(charNum), true);-			if (!nextText.empty()-			        && ((isCharPotentialHeader(nextText, 0)-			             && ASBase::findHeader(nextText, 0, headers) != &ASResource::AS_IF)-			            || nextText[0] == '{'))-				isInLineBreak = true;-		}-		else-		{-			// GH16 only break if header is present-			if (currentHeader)-				isInLineBreak = true;-		}-	}--	isImmediatelyPostHeader = false;-	return true;+    // should braces be added+    if (currentChar != '{'+            && shouldAddBraces+            && currentChar != '#'	// don't add to preprocessor+            && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine)+            && isOkToBreakBlock(braceTypeStack->back()))+    {+        bool bracesAdded = addBracesToStatement();+        if (bracesAdded && !shouldAddOneLineBraces)+        {+            size_t firstText = currentLine.find_first_not_of(" \t");+            assert(firstText != std::string::npos);+            if ((int) firstText == charNum || shouldBreakOneLineHeaders)+                breakCurrentOneLineBlock = true;+        }+    }+    // should braces be removed+    // 'if consteval' requires braces+    else if (currentChar == '{' && shouldRemoveBraces && !foundConstevalCondition)+    {+        bool bracesRemoved = removeBracesFromStatement();+        if (bracesRemoved)+        {+            shouldRemoveNextClosingBrace = true;+            if (isBeforeAnyLineEndComment(charNum))+                spacePadNum--;+            else if (shouldBreakOneLineBlocks+                     || (currentLineBeginsWithBrace+                         && currentLine.find_first_not_of(" \t") != std::string::npos))+                shouldBreakLineAtNextChar = true;+            return false;+        }+    }+    // should one-line braces be removed (keep the statement on one line)+    else if (currentChar == '{' && shouldRemoveOneLineBraces && !foundConstevalCondition)+    {+        if (isOneLineBlockReached(currentLine, charNum) == 1)+        {+            bool bracesRemoved = removeBracesFromStatement();+            if (bracesRemoved)+            {+                shouldRemoveNextClosingBrace = true;+                return false;+            }+        }+    }++    // break 'else-if' if shouldBreakElseIfs is requested+    if (shouldBreakElseIfs+            && currentHeader == &ASResource::AS_ELSE+            && isOkToBreakBlock(braceTypeStack->back())+            && !isBeforeAnyComment()+            && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine))+    {+        std::string nextText = peekNextText(currentLine.substr(charNum));+        if (!nextText.empty()+                && isCharPotentialHeader(nextText, 0)+                && ASBase::findHeader(nextText, 0, headers.get()) == &ASResource::AS_IF)+        {+            isInLineBreak = true;+        }+    }++    // break a header (e.g. if, while, else) from the following statement+    if (shouldBreakOneLineHeaders+            && peekNextChar() != ' '+            && (shouldBreakOneLineStatements+                || (!isHeaderInMultiStatementLine+                    && !isMultiStatementLine()))+            && isOkToBreakBlock(braceTypeStack->back())+            && !isBeforeAnyComment())+    {+        if (currentChar == '{')+        {+            if (!currentLineBeginsWithBrace)+            {+                if (isOneLineBlockReached(currentLine, charNum) == 3)+                    isInLineBreak = false;+                else+                    breakCurrentOneLineBlock = true;+            }+        }+        else if (currentHeader == &ASResource::AS_ELSE)+        {+            std::string nextText = peekNextText(currentLine.substr(charNum), true);+            if (!nextText.empty()+                    && ((isCharPotentialHeader(nextText, 0)+                         && ASBase::findHeader(nextText, 0, headers.get()) != &ASResource::AS_IF)+                        || nextText[0] == '{'))+                isInLineBreak = true;+        }+        else+        {+            // GH16 only break if header is present+            if (currentHeader)+                isInLineBreak = true;+        }+    }++    isImmediatelyPostHeader = false;+    return true; }  bool ASFormatter::handlePassedSemicolonSection() {-	isInAllocator = false; // GH16-	isInMultlineStatement = false;-	passedSemicolon = false;--	if (parenStack->back() == 0 && !isCharImmediatelyPostComment && currentChar != ';') // allow ;;-	{-		// does a one-line block have ending comments?-		if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))-		{-			size_t blockEnd = currentLine.rfind(ASResource::AS_CLOSE_BRACE);-			assert(blockEnd != std::string::npos);-			// move ending comments to this formattedLine-			if (isBeforeAnyLineEndComment(blockEnd))-			{-				size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1);-				assert(commentStart != std::string::npos);-				assert((currentLine.compare(commentStart, 2, "//") == 0)-				       || (currentLine.compare(commentStart, 2, "/*") == 0));-				formattedLine.append(getIndentLength() - 1, ' ');-				// append comment-				int charNumSave = charNum;-				charNum = commentStart;-				while (charNum < (int) currentLine.length())-				{-					currentChar = currentLine[charNum];-					if (currentChar == '\t' && shouldConvertTabs)-						convertTabToSpaces();-					formattedLine.append(1, currentChar);-					++charNum;-				}-				size_t commentLength = currentLine.length() - commentStart;-				currentLine.erase(commentStart, commentLength);-				charNum = charNumSave;-				currentChar = currentLine[charNum];-				testForTimeToSplitFormattedLine();-			}-		}-		isInExecSQL = false;-		shouldReparseCurrentChar = true;-		if (formattedLine.find_first_not_of(" \t") != std::string::npos)-			isInLineBreak = true;-		if (needHeaderOpeningBrace)-		{-			isCharImmediatelyPostCloseBlock = true;-			needHeaderOpeningBrace = false;-		}-		return false;-	}-	return true;+    isInAllocator = false; // GH16+    isInMultlineStatement = false;+    passedSemicolon = false;++    if (parenStack->back() == 0 && !isCharImmediatelyPostComment && currentChar != ';') // allow ;;+    {+        // does a one-line block have ending comments?+        if (isBraceType(braceTypeStack->back(), BraceType::SINGLE_LINE_TYPE))+        {+            size_t blockEnd = currentLine.rfind(ASResource::AS_CLOSE_BRACE);+            assert(blockEnd != std::string::npos);+            // move ending comments to this formattedLine+            if (isBeforeAnyLineEndComment(blockEnd))+            {+                size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1);+                assert(commentStart != std::string::npos);+                assert((currentLine.compare(commentStart, 2, "//") == 0)+                       || (currentLine.compare(commentStart, 2, "/*") == 0));+                formattedLine.append(getIndentLength() - 1, ' ');+                // append comment+                int charNumSave = charNum;+                charNum = commentStart;+                while (charNum < (int) currentLine.length())+                {+                    currentChar = currentLine[charNum];+                    if (currentChar == '\t' && shouldConvertTabs)+                        convertTabToSpaces();+                    formattedLine.append(1, currentChar);+                    ++charNum;+                }+                size_t commentLength = currentLine.length() - commentStart;+                currentLine.erase(commentStart, commentLength);+                charNum = charNumSave;+                currentChar = currentLine[charNum];+                testForTimeToSplitFormattedLine();+            }+        }+        isInExecSQL = false;+        shouldReparseCurrentChar = true;+        if (formattedLine.find_first_not_of(" \t") != std::string::npos)+            isInLineBreak = true;+        if (needHeaderOpeningBrace)+        {+            isCharImmediatelyPostCloseBlock = true;+            needHeaderOpeningBrace = false;+        }+        return false;+    }+    return true; }  void ASFormatter::handleAttachedReturnTypes() {-	if ((size_t) charNum == methodAttachCharNum)-	{-		int pa = pointerAlignment;-		int ra = referenceAlignment;-		int itemAlignment = (previousNonWSChar == '*' || previousNonWSChar == '^')-		                    ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);-		isInLineBreak = false;-		if (previousNonWSChar == '*' || previousNonWSChar == '&' || previousNonWSChar == '^')-		{-			if (itemAlignment == REF_ALIGN_TYPE)-			{-				if (!formattedLine.empty()-				        && !std::isblank(formattedLine[formattedLine.length() - 1]))-					formattedLine.append(1, ' ');-			}-			else if (itemAlignment == REF_ALIGN_MIDDLE)-			{-				if (!formattedLine.empty()-				        && !std::isblank(formattedLine[formattedLine.length() - 1]))-					formattedLine.append(1, ' ');-			}-			else if (itemAlignment == REF_ALIGN_NAME)-			{-				if (!formattedLine.empty()-				        && std::isblank(formattedLine[formattedLine.length() - 1]))-					formattedLine.erase(formattedLine.length() - 1);-			}-			else-			{-				if (formattedLine.length() > 1-				        && !std::isblank(formattedLine[formattedLine.length() - 2]))-					formattedLine.append(1, ' ');-			}-		}-		else-			formattedLine.append(1, ' ');-	}-	methodAttachCharNum = std::string::npos;-	methodAttachLineNum = 0;+    if ((size_t) charNum == methodAttachCharNum)+    {+        int pa = pointerAlignment;+        int ra = referenceAlignment;+        int itemAlignment = (previousNonWSChar == '*' || previousNonWSChar == '^')+                            ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);+        isInLineBreak = false;+        if (previousNonWSChar == '*' || previousNonWSChar == '&' || previousNonWSChar == '^')+        {+            if (itemAlignment == REF_ALIGN_TYPE)+            {+                if (!formattedLine.empty()+                        && !std::isblank(formattedLine[formattedLine.length() - 1]))+                    formattedLine.append(1, ' ');+            }+            else if (itemAlignment == REF_ALIGN_MIDDLE)+            {+                if (!formattedLine.empty()+                        && !std::isblank(formattedLine[formattedLine.length() - 1]))+                    formattedLine.append(1, ' ');+            }+            else if (itemAlignment == REF_ALIGN_NAME)+            {+                if (!formattedLine.empty()+                        && std::isblank(formattedLine[formattedLine.length() - 1]))+                    formattedLine.erase(formattedLine.length() - 1);+            }+            else+            {+                if (formattedLine.length() > 1+                        && !std::isblank(formattedLine[formattedLine.length() - 2]))+                    formattedLine.append(1, ' ');+            }+        }+        else+            formattedLine.append(1, ' ');+    }+    methodAttachCharNum = std::nullopt;+    methodAttachLineNum = 0; }  void ASFormatter::handleClosedBracesOrParens() {-	foundPreCommandHeader = false;-	parenStack->back()--;-	// this can happen in preprocessor directives-	if (parenStack->back() < 0)-		parenStack->back() = 0;-	if (!questionMarkStack->empty())-	{-		foundQuestionMark = questionMarkStack->back();-		questionMarkStack->pop_back();-	}--	if (isInTemplate && currentChar == '>')-	{-		templateDepth--;-		if (templateDepth == 0)-		{-			isInTemplate = false;-			isImmediatelyPostTemplate = true;-		}-	}--	// check if this parenthesis closes a header, e.g. if (...), while (...)-	//GH16-	if ( !(isSharpStyle() && peekNextChar() == ',') && isInHeader && parenStack->back() == 0)-	{-		isInHeader = false;-		isImmediatelyPostHeader = true;-		foundQuestionMark = false;-	}-	if (currentChar == ']')-	{-		--squareBracketCount;-		if (squareBracketCount <= 0)-		{-			squareBracketCount = 0;-			objCColonAlign = 0;-		}-	}--	// GH16 break-	if (currentChar == ')')-	{-		--parenthesesCount;-		foundCastOperator = false;-		if (parenStack->back() == 0)-			endOfAsmReached = true;-	}+    foundPreCommandHeader = false;+    parenStack->back()--;+    // this can happen in preprocessor directives+    if (parenStack->back() < 0)+        parenStack->back() = 0;+    if (!questionMarkStack->empty())+    {+        foundQuestionMark = questionMarkStack->back();+        questionMarkStack->pop_back();+    }++    if (isInTemplate && currentChar == '>')+    {+        templateDepth--;+        if (templateDepth == 0)+        {+            isInTemplate = false;+            isImmediatelyPostTemplate = true;+        }+    }++    // check if this parenthesis closes a header, e.g. if (...), while (...)+    //GH16+    if ( !(isSharpStyle() && peekNextChar() == ',') && isInHeader && parenStack->back() == 0)+    {+        isInHeader = false;+        isImmediatelyPostHeader = true;+        foundQuestionMark = false;+    }+    if (currentChar == ']')+    {+        --squareBracketCount;+        if (squareBracketCount <= 0)+        {+            squareBracketCount = 0;+            objCColonAlign = 0;+        }+    }++    // GH16 break+    if (currentChar == ')')+    {+        --parenthesesCount;+        foundCastOperator = false;+        if (parenStack->back() == 0)+            endOfAsmReached = true;+    } }  void ASFormatter::handleBraces() {-	// if appendOpeningBrace this was already done for the original brace-	if (currentChar == '{' && !appendOpeningBrace)-	{-		BraceType newBraceType = getBraceType();-		breakCurrentOneLineBlock = false;-		foundNamespaceHeader = false;-		foundClassHeader = false;-		foundStructHeader = false;-		foundInterfaceHeader = false;-		foundPreDefinitionHeader = false;-		foundPreCommandHeader = false;-		foundPreCommandMacro = false;-		foundTrailingReturnType = false;-		isInPotentialCalculation = false;-		isInObjCMethodDefinition = false;-		isImmediatelyPostObjCMethodPrefix = false;-		isInObjCInterface = false;-		isInEnum = false;--		isJavaStaticConstructor = false;-		isCharImmediatelyPostNonInStmt = false;-		needHeaderOpeningBrace = false;-		shouldKeepLineUnbroken = false;-		returnTypeChecked = false;--		isInExplicitBlock++;--		objCColonAlign = 0;--		methodBreakCharNum = std::string::npos;-		methodBreakLineNum = 0;-		methodAttachCharNum = std::string::npos;-		methodAttachLineNum = 0;--		isPreviousBraceBlockRelated = !isBraceType(newBraceType, ARRAY_TYPE);-		braceTypeStack->emplace_back(newBraceType);-		preBraceHeaderStack->emplace_back(currentHeader);-		currentHeader = nullptr;-		// do not use emplace_back on std::vector<bool> until supported by macOS-		structStack->push_back(isInIndentableStruct);-		if (isBraceType(newBraceType, STRUCT_TYPE) && isCStyle())-			isInIndentableStruct = isStructAccessModified(currentLine, charNum);-		else-			isInIndentableStruct = false;--		bracesNestingLevel++;-	}--	// this must be done before the braceTypeStack is popped-	BraceType braceType = braceTypeStack->back();-	bool isOpeningArrayBrace = (isBraceType(braceType, ARRAY_TYPE)-	                            && braceTypeStack->size() >= 2-	                            && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2], ARRAY_TYPE)-	                           );--	if (currentChar == '}')-	{-		// if a request has been made to append a post block empty line,-		// but the block exists immediately before a closing brace,-		// then there is no need for the post block empty line.-		isAppendPostBlockEmptyLineRequested = false;-		if (isInAsm)-			endOfAsmReached = true;-		isInAsmOneLine = isInQuote = false;-		shouldKeepLineUnbroken = false;-		squareBracketCount = 0;-		isInAllocator = false;-		isInMultlineStatement = false;-		isInExplicitBlock--;--		if (braceTypeStack->size() > 1)-		{-			previousBraceType = braceTypeStack->back();-			braceTypeStack->pop_back();-			isPreviousBraceBlockRelated = !isBraceType(braceType, ARRAY_TYPE);-		}-		else-		{-			previousBraceType = NULL_TYPE;-			isPreviousBraceBlockRelated = false;-		}--		if (!preBraceHeaderStack->empty())-		{-			previousHeader = currentHeader;-			currentHeader = preBraceHeaderStack->back();-			preBraceHeaderStack->pop_back();-		}-		else-			currentHeader = nullptr;--		if (!structStack->empty())-		{-			isInIndentableStruct = structStack->back();-			structStack->pop_back();-		}-		else-			isInIndentableStruct = false;--		if (isNonInStatementArray-		        && (!isBraceType(braceTypeStack->back(), ARRAY_TYPE)	// check previous brace-		            || peekNextChar() == ';'))							// check for "};" added V2.01-			isImmediatelyPostNonInStmt = true;--		if (!shouldBreakOneLineStatements-		        && ASBeautifier::getNextWord(currentLine, charNum) == ASResource::AS_ELSE)-		{-			// handle special case of "else" at the end of line-			size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);-			if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')-				shouldBreakLineAtNextChar = true;-		}-		bracesNestingLevel--;-	}--	// format braces-	appendOpeningBrace = false;-	if (isBraceType(braceType, ARRAY_TYPE))-	{-		formatArrayBraces(braceType, isOpeningArrayBrace);-	}-	else-	{-		if (currentChar == '{')-			formatOpeningBrace(braceType);-		else-			formatClosingBrace(braceType);-	}+    // if appendOpeningBrace this was already done for the original brace+    if (currentChar == '{' && !appendOpeningBrace)+    {+        BraceType newBraceType = getBraceType();+        breakCurrentOneLineBlock = false;+        foundNamespaceHeader = false;+        foundClassHeader = false;+        foundStructHeader = false;+        foundDefinitionAttribute = false;+        foundInterfaceHeader = false;+        foundPreDefinitionHeader = false;+        foundPreCommandHeader = false;+        foundPreCommandMacro = false;+        foundTrailingReturnType = false;+        foundConstevalCondition = false;+        isInPotentialCalculation = false;+        isInObjCMethodDefinition = false;+        isImmediatelyPostObjCMethodPrefix = false;+        isInObjCInterface = false;+        isInEnum = false;++        isJavaStaticConstructor = false;+        isCharImmediatelyPostNonInStmt = false;+        needHeaderOpeningBrace = false;+        shouldKeepLineUnbroken = false;+        returnTypeChecked = false;++        isInExplicitBlock++;++        objCColonAlign = 0;++        methodBreakCharNum = std::nullopt;+        methodBreakLineNum = 0;+        methodAttachCharNum = std::nullopt;+        methodAttachLineNum = 0;++        isPreviousBraceBlockRelated = !isBraceType(newBraceType, BraceType::ARRAY_TYPE);+        braceTypeStack->emplace_back(newBraceType);+        // a ?: sequence continues after a brace like a lambda body,+        // braceQuestionMarkStack[n] belongs to braceTypeStack[n + 1]+        braceQuestionMarkStack->resize(braceTypeStack->size() - 2);+        braceQuestionMarkStack->push_back(foundQuestionMark);+        foundQuestionMark = false;+        if (foundRequiresExpression)+        {+            requiresBodyStack->emplace_back(braceTypeStack->size());+            foundRequiresExpression = false;+        }+        preBraceHeaderStack->emplace_back(currentHeader);+        currentHeader = nullptr;+        // do not use emplace_back on std::vector<bool> until supported by macOS+        structStack->push_back(isInIndentableStruct);+        if (isBraceType(newBraceType, BraceType::STRUCT_TYPE) && isCStyle())+            isInIndentableStruct = isStructAccessModified(currentLine, charNum);+        else+            isInIndentableStruct = false;++        bracesNestingLevel++;+    }++    // this must be done before the braceTypeStack is popped+    BraceType braceType = braceTypeStack->back();+    bool isOpeningArrayBrace = (isBraceType(braceType, BraceType::ARRAY_TYPE)+                                && braceTypeStack->size() >= 2+                                && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2], BraceType::ARRAY_TYPE)+                               );++    if (currentChar == '}')+    {+        // if a request has been made to append a post block empty line,+        // but the block exists immediately before a closing brace,+        // then there is no need for the post block empty line.+        isAppendPostBlockEmptyLineRequested = false;+        if (isInAsm)+            endOfAsmReached = true;+        isInAsmOneLine = isInQuote = false;+        shouldKeepLineUnbroken = false;+        squareBracketCount = 0;+        isInAllocator = false;+        isInMultlineStatement = false;+        isInExplicitBlock--;++        if (braceTypeStack->size() > 1)+        {+            previousBraceType = braceTypeStack->back();+            braceTypeStack->pop_back();+            if (!requiresBodyStack->empty() && requiresBodyStack->back() > braceTypeStack->size())+                requiresBodyStack->pop_back();+            if (braceQuestionMarkStack->size() >= braceTypeStack->size())+            {+                foundQuestionMark = (*braceQuestionMarkStack)[braceTypeStack->size() - 1];+                braceQuestionMarkStack->resize(braceTypeStack->size() - 1);+            }+            isPreviousBraceBlockRelated = !isBraceType(braceType, BraceType::ARRAY_TYPE);+        }+        else+        {+            previousBraceType = BraceType::NULL_TYPE;+            isPreviousBraceBlockRelated = false;+        }++        if (!preBraceHeaderStack->empty())+        {+            previousHeader = currentHeader;+            currentHeader = preBraceHeaderStack->back();+            preBraceHeaderStack->pop_back();+        }+        else+            currentHeader = nullptr;++        if (!structStack->empty())+        {+            isInIndentableStruct = structStack->back();+            structStack->pop_back();+        }+        else+            isInIndentableStruct = false;++        if (isNonInStatementArray+                && (!isBraceType(braceTypeStack->back(), BraceType::ARRAY_TYPE)	// check previous brace+                    || peekNextChar() == ';'))							// check for "};" added V2.01+            isImmediatelyPostNonInStmt = true;++        if (!shouldBreakOneLineStatements+                && ASBeautifier::getNextWord(currentLine, charNum) == ASResource::AS_ELSE)+        {+            // handle special case of "else" at the end of line+            size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);+            if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')+                shouldBreakLineAtNextChar = true;+        }+        bracesNestingLevel--;++        // the struct body has been closed, so options that are suppressed+        // inside a struct (e.g. unpad-paren) apply again to the code that follows+        if (isInStruct && bracesNestingLevel <= structNestingLevel)+        {+            isInStruct = false;+            structNestingLevel = 0;+        }+    }++    // format braces+    appendOpeningBrace = false;+    if (isBraceType(braceType, BraceType::ARRAY_TYPE))+    {+        formatArrayBraces(braceType, isOpeningArrayBrace);+    }+    else+    {+        if (currentChar == '{')+            formatOpeningBrace(braceType);+        else+            formatClosingBrace(braceType);+    } }   void ASFormatter::handleBreakLine() {-	isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');-	isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');--	if (isCharImmediatelyPostOpenBlock-	        && !isCharImmediatelyPostComment-	        && !isCharImmediatelyPostLineComment)-	{-		previousCommandChar = ' ';--		if (braceFormatMode == NONE_MODE)-		{-			if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)-			        && (isBraceType(braceTypeStack->back(), BREAK_BLOCK_TYPE)-			            || shouldBreakOneLineBlocks))-				isInLineBreak = true;-			else if (currentLineBeginsWithBrace)-				formatRunIn();-			else-				breakLine();-		}-		else if (braceFormatMode == RUN_IN_MODE-		         && currentChar != '#')-			formatRunIn();-		else-			isInLineBreak = true;-	}-	else if (isCharImmediatelyPostCloseBlock-	         && shouldBreakOneLineStatements-	         && !isCharImmediatelyPostComment-	         && ((isLegalNameChar(currentChar) && currentChar != '.')-	             || currentChar == '+'-	             || currentChar == '-'-	             || currentChar == '*'-	             || currentChar == '&'-	             || currentChar == '('))-	{-		previousCommandChar = ' ';-		isInLineBreak = true;-	}+    isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');+    isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');++    if (isCharImmediatelyPostOpenBlock+            && !isCharImmediatelyPostComment+            && !isCharImmediatelyPostLineComment)+    {+        previousCommandChar = ' ';++        if (braceFormatMode == NONE_MODE)+        {+            if (isBraceType(braceTypeStack->back(), BraceType::SINGLE_LINE_TYPE)+                    && (isBraceType(braceTypeStack->back(), BraceType::BREAK_BLOCK_TYPE)+                        || shouldBreakOneLineBlocks))+                isInLineBreak = true;+            else if (currentLineBeginsWithBrace)+                formatRunIn();+            else+                breakLine();+        }+        else if (braceFormatMode == RUN_IN_MODE+                 && currentChar != '#')+            formatRunIn();+        else+            isInLineBreak = true;+    }+    else if (isCharImmediatelyPostCloseBlock+             && shouldBreakOneLineStatements+             && !isCharImmediatelyPostComment+             && ((isLegalNameChar(currentChar) && currentChar != '.')+                 || currentChar == '+'+                 || currentChar == '-'+                 || currentChar == '*'+                 || currentChar == '&'+                 || currentChar == '('))+    {+        previousCommandChar = ' ';+        isInLineBreak = true;+    } }  bool ASFormatter::handlePotentialHeader(const std::string *&newHeader) {-	isNonParenHeader = false;-	foundClosingHeader = false;--	newHeader = findHeader(headers);--	// java can have a 'default' not in a switch-	if (newHeader == &ASResource::AS_DEFAULT-	        && ASBeautifier::peekNextChar(-	            currentLine, charNum + (*newHeader).length() - 1) != ':')-		newHeader = nullptr;-	// Qt headers may be variables in C++-	if (isCStyle()-	        && (newHeader == &ASResource::AS_FOREVER || newHeader == &ASResource::AS_FOREACH))-	{-		if (currentLine.find_first_of("=;", charNum) != std::string::npos)-			newHeader = nullptr;-	}-	if (isJavaStyle()-	        && (newHeader == &ASResource::AS_SYNCHRONIZED))-	{-		// want synchronized statements not synchronized methods-		if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE))-			newHeader = nullptr;-	}-	else if (newHeader == &ASResource::AS_USING-	         && ASBeautifier::peekNextChar(-	             currentLine, charNum + (*newHeader).length() - 1) != '(')-		newHeader = nullptr;--	if (newHeader != nullptr)-	{-		foundClosingHeader = isClosingHeader(newHeader);--		if (!foundClosingHeader)-		{-			// these are closing headers-			if ((newHeader == &ASResource::AS_WHILE && currentHeader == &ASResource::AS_DO)-			        || (newHeader == &ASResource::_AS_FINALLY && currentHeader == &ASResource::_AS_TRY)-			        || (newHeader == &ASResource::_AS_EXCEPT && currentHeader == &ASResource::_AS_TRY))-				foundClosingHeader = true;-			// don't append empty block for these related headers-			else if (isSharpStyle()-			         && previousNonWSChar == '}'-			         && ((newHeader == &ASResource::AS_SET && currentHeader == &ASResource::AS_GET)-			             || (newHeader == &ASResource::AS_REMOVE && currentHeader == &ASResource::AS_ADD))-			         && isOkToBreakBlock(braceTypeStack->back()))-				isAppendPostBlockEmptyLineRequested = false;-		}--		previousHeader = currentHeader;-		currentHeader = newHeader;-		needHeaderOpeningBrace = true;--		// is the previous statement on the same line?-		if ((previousNonWSChar == ';' || previousNonWSChar == ':')-		        && !isInLineBreak-		        && isOkToBreakBlock(braceTypeStack->back()))-		{-			// if breaking lines, break the line at the header-			// except for multiple 'case' statements on a line-			if (maxCodeLength != std::string::npos-			        && previousHeader != &ASResource::AS_CASE)-				isInLineBreak = true;-			else-				isHeaderInMultiStatementLine = true;-		}--		if (foundClosingHeader && previousNonWSChar == '}')-		{-			if (isOkToBreakBlock(braceTypeStack->back()))-				isLineBreakBeforeClosingHeader();--			// get the adjustment for a comment following the closing header-			if (isInLineBreak)-				nextLineSpacePadNum = getNextLineCommentAdjustment();-			else-				spacePadNum = getCurrentLineCommentAdjustment();-		}--		// check if the found header is non-paren header-		isNonParenHeader = findHeader(nonParenHeaders) != nullptr;--		if (isNonParenHeader-		        && (currentHeader == &ASResource::AS_CATCH-		            || currentHeader == &ASResource::AS_CASE))-		{-			int startChar = charNum + currentHeader->length() - 1;-			if (ASBeautifier::peekNextChar(currentLine, startChar) == '(')-				isNonParenHeader = false;-		}--		// join 'else if' statements-		if (currentHeader == &ASResource::AS_IF-		        && previousHeader == &ASResource::AS_ELSE-		        && isInLineBreak-		        && !shouldBreakElseIfs-		        && !isCharImmediatelyPostLineComment-		        && !isImmediatelyPostPreprocessor)-		{-			// 'else' must be last thing on the line-			size_t start = formattedLine.length() >= 6 ? formattedLine.length() - 6 : 0;-			if (formattedLine.find(ASResource::AS_ELSE, start) != std::string::npos)-			{-				appendSpacePad();-				isInLineBreak = false;-			}-		}--		appendSequence(*currentHeader);-		goForward(currentHeader->length() - 1);-		// if a paren-header is found add a space after it, if needed-		// this checks currentLine, appendSpacePad() checks formattedLine-		// in 'case' and C# 'catch' can be either a paren or non-paren header-		if (shouldPadHeader-		        && !isNonParenHeader-		        && charNum < (int) currentLine.length() - 1 && !std::isblank(currentLine[charNum + 1]))-			appendSpacePad();--		// Signal that a header has been reached-		// *** But treat a closing while() (as in do...while)-		//     as if it were NOT a header since a closing while()-		//     should never have a block after it!-		if (currentHeader != &ASResource::AS_CASE && currentHeader != &ASResource::AS_DEFAULT-		        && !(foundClosingHeader && currentHeader == &ASResource::AS_WHILE))-		{-			isInHeader = true;--			// in C# 'catch' and 'delegate' can be a paren or non-paren header-			if (isNonParenHeader && !isSharpStyleWithParen(currentHeader))-			{-				isImmediatelyPostHeader = true;-				isInHeader = false;-			}-		}--		// #569-		if (shouldBreakBlocks-		        && isOkToBreakBlock(braceTypeStack->back())-		        && !isHeaderInMultiStatementLine)-		{-			if (previousHeader == nullptr-			        && !foundClosingHeader-			        && !isCharImmediatelyPostOpenBlock-			        && !isImmediatelyPostCommentOnly)-			{-				isPrependPostBlockEmptyLineRequested = true;-			}--			if (isClosingHeader(currentHeader)-			        || foundClosingHeader)-			{-				isPrependPostBlockEmptyLineRequested = false;-			}--			if (shouldBreakClosingHeaderBlocks-			        && isCharImmediatelyPostCloseBlock-			        && !isImmediatelyPostCommentOnly-			        && !(currentHeader == &ASResource::AS_WHILE			// do-while-			             && foundClosingHeader))-			{-				isPrependPostBlockEmptyLineRequested = true;-			}-		}--		if (currentHeader == &ASResource::AS_CASE-		        || currentHeader == &ASResource::AS_DEFAULT)-			isInCase = true;--		return false;-	}-	if ((newHeader = findHeader(preDefinitionHeaders)) != nullptr-	        && parenStack->back() == 0-	        && !isInEnum)		// not C++11 enum class-	{-		if (newHeader == &ASResource::AS_NAMESPACE || newHeader == &ASResource::AS_MODULE)-			foundNamespaceHeader = true;-		if (newHeader == &ASResource::AS_CLASS)-			foundClassHeader = true;-		if (newHeader == &ASResource::AS_STRUCT)-			foundStructHeader = true;-		if (newHeader == &ASResource::AS_INTERFACE && !foundNamespaceHeader && !foundClassHeader)-			foundInterfaceHeader = true;-		foundPreDefinitionHeader = true;-		appendSequence(*newHeader);-		goForward(newHeader->length() - 1);--		return false;-	}-	if ((newHeader = findHeader(preCommandHeaders)) != nullptr)-	{-		// must be after function arguments-		if (previousNonWSChar == ')')-			foundPreCommandHeader = true;-	}-	else if ((newHeader = findHeader(castOperators)) != nullptr)-	{-		foundCastOperator = true;-		appendSequence(*newHeader);-		goForward(newHeader->length() - 1);-		return false;-	}-	return true;+    isNonParenHeader = false;+    foundClosingHeader = false;++    newHeader = findHeader(headers.get());++    // java can have a 'default' not in a switch+    if (newHeader == &ASResource::AS_DEFAULT+            && ASBeautifier::peekNextChar(+                currentLine, charNum + (*newHeader).length() - 1) != ':')+        newHeader = nullptr;+    // Qt headers may be variables in C+++    if (isCStyle()+            && (newHeader == &ASResource::AS_FOREVER || newHeader == &ASResource::AS_FOREACH))+    {+        if (currentLine.find_first_of("=;", charNum) != std::string::npos)+            newHeader = nullptr;+    }+    if (isJavaStyle()+            && (newHeader == &ASResource::AS_SYNCHRONIZED))+    {+        // want synchronized statements not synchronized methods+        if (!isBraceType(braceTypeStack->back(), BraceType::COMMAND_TYPE))+            newHeader = nullptr;+    }+    else if (newHeader == &ASResource::AS_USING+             && ASBeautifier::peekNextChar(+                 currentLine, charNum + (*newHeader).length() - 1) != '(')+        newHeader = nullptr;++    if (newHeader != nullptr)+    {+        foundClosingHeader = isClosingHeader(newHeader);++        if (!foundClosingHeader)+        {+            // these are closing headers+            if ((newHeader == &ASResource::AS_WHILE && currentHeader == &ASResource::AS_DO)+                    || (newHeader == &ASResource::_AS_FINALLY && currentHeader == &ASResource::_AS_TRY)+                    || (newHeader == &ASResource::_AS_EXCEPT && currentHeader == &ASResource::_AS_TRY))+                foundClosingHeader = true;+            // don't append empty block for these related headers+            else if (isSharpStyle()+                     && previousNonWSChar == '}'+                     && ((newHeader == &ASResource::AS_SET && currentHeader == &ASResource::AS_GET)+                         || (newHeader == &ASResource::AS_REMOVE && currentHeader == &ASResource::AS_ADD))+                     && isOkToBreakBlock(braceTypeStack->back()))+                isAppendPostBlockEmptyLineRequested = false;+        }++        previousHeader = currentHeader;+        currentHeader = newHeader;+        needHeaderOpeningBrace = true;++        // is the previous statement on the same line?+        if ((previousNonWSChar == ';' || previousNonWSChar == ':')+                && !isInLineBreak+                && isOkToBreakBlock(braceTypeStack->back()))+        {+            // if breaking lines, break the line at the header+            // except for multiple 'case' statements on a line+            if (maxCodeLength != std::string::npos+                    && previousHeader != &ASResource::AS_CASE)+                isInLineBreak = true;+            else+                isHeaderInMultiStatementLine = true;+        }++        if (foundClosingHeader && previousNonWSChar == '}')+        {+            if (isOkToBreakBlock(braceTypeStack->back()))+                isLineBreakBeforeClosingHeader();++            // get the adjustment for a comment following the closing header+            if (isInLineBreak)+                nextLineSpacePadNum = getNextLineCommentAdjustment();+            else+                spacePadNum = getCurrentLineCommentAdjustment();+        }++        // check if the found header is non-paren header+        isNonParenHeader = findHeader(nonParenHeaders.get()) != nullptr;++        if (isNonParenHeader+                && (currentHeader == &ASResource::AS_CATCH+                    || currentHeader == &ASResource::AS_CASE))+        {+            int startChar = charNum + currentHeader->length() - 1;+            if (ASBeautifier::peekNextChar(currentLine, startChar) == '(')+                isNonParenHeader = false;+        }++        // join 'else if' statements+        if (currentHeader == &ASResource::AS_IF+                && previousHeader == &ASResource::AS_ELSE+                && isInLineBreak+                && !shouldBreakElseIfs+                && !isCharImmediatelyPostLineComment+                && !isImmediatelyPostPreprocessor)+        {+            // 'else' must be last thing on the line+            size_t start = formattedLine.length() >= 6 ? formattedLine.length() - 6 : 0;+            if (formattedLine.find(ASResource::AS_ELSE, start) != std::string::npos)+            {+                appendSpacePad();+                isInLineBreak = false;+            }+        }++        appendSequence(*currentHeader);+        goForward(currentHeader->length() - 1);+        // if a paren-header is found add a space after it, if needed+        // this checks currentLine, appendSpacePad() checks formattedLine+        // in 'case' and C# 'catch' can be either a paren or non-paren header+        if (shouldPadHeader+                && !isNonParenHeader+                && charNum < (int) currentLine.length() - 1 && !std::isblank(currentLine[charNum + 1]))+            appendSpacePad();++        // Signal that a header has been reached+        // *** But treat a closing while() (as in do...while)+        //     as if it were NOT a header since a closing while()+        //     should never have a block after it!+        if (currentHeader != &ASResource::AS_CASE && currentHeader != &ASResource::AS_DEFAULT+                && !(foundClosingHeader && currentHeader == &ASResource::AS_WHILE))+        {+            isInHeader = true;++            // in C# 'catch' and 'delegate' can be a paren or non-paren header+            if (isNonParenHeader && !isSharpStyleWithParen(currentHeader))+            {+                isImmediatelyPostHeader = true;+                isInHeader = false;+            }++            // C++23 'if consteval' has no paren, the header ends after 'consteval'+            if (currentHeader == &ASResource::AS_IF)+            {+                size_t conditionEnd = findConstevalConditionEnd(currentLine, charNum + 1);+                if (conditionEnd != std::string::npos)+                {+                    size_t conditionLength = conditionEnd - (charNum + 1);+                    appendSequence(currentLine.substr(charNum + 1, conditionLength));+                    goForward(conditionLength);+                    isImmediatelyPostHeader = true;+                    isInHeader = false;+                    foundConstevalCondition = true;+                }+            }+        }++        // #569+        if (shouldBreakBlocks+                && isOkToBreakBlock(braceTypeStack->back())+                && !isHeaderInMultiStatementLine)+        {+            if (previousHeader == nullptr+                    && !foundClosingHeader+                    && !isCharImmediatelyPostOpenBlock+                    && !isImmediatelyPostCommentOnly)+            {+                isPrependPostBlockEmptyLineRequested = true;+            }++            if (isClosingHeader(currentHeader)+                    || foundClosingHeader)+            {+                isPrependPostBlockEmptyLineRequested = false;+            }++            if (shouldBreakClosingHeaderBlocks+                    && isCharImmediatelyPostCloseBlock+                    && !isImmediatelyPostCommentOnly+                    && !(currentHeader == &ASResource::AS_WHILE			// do-while+                         && foundClosingHeader))+            {+                isPrependPostBlockEmptyLineRequested = true;+            }+        }++        if (currentHeader == &ASResource::AS_CASE+                || currentHeader == &ASResource::AS_DEFAULT)+            isInCase = true;++        return false;+    }+    if ((newHeader = findHeader(preDefinitionHeaders.get())) != nullptr+            && parenStack->back() == 0+            && !isInEnum)		// not C++11 enum class+    {+        if (newHeader == &ASResource::AS_NAMESPACE || newHeader == &ASResource::AS_MODULE)+            foundNamespaceHeader = true;+        if (newHeader == &ASResource::AS_CLASS)+            foundClassHeader = true;+        if (newHeader == &ASResource::AS_STRUCT)+            foundStructHeader = true;+        if (newHeader == &ASResource::AS_INTERFACE && !foundNamespaceHeader && !foundClassHeader)+            foundInterfaceHeader = true;+        foundPreDefinitionHeader = true;+        appendSequence(*newHeader);+        goForward(newHeader->length() - 1);++        return false;+    }+    if ((newHeader = findHeader(preCommandHeaders.get())) != nullptr)+    {+        // must be after function arguments+        if (previousNonWSChar == ')')+            foundPreCommandHeader = true;+    }+    else if ((newHeader = findHeader(castOperators.get())) != nullptr)+    {+        foundCastOperator = true;+        appendSequence(*newHeader);+        goForward(newHeader->length() - 1);+        return false;+    }+    return true; }   void ASFormatter::handleEndOfBlock() {-	if (currentChar == ';' && !isInAsmBlock)-	{-		squareBracketCount = 0;--		methodBreakCharNum = std::string::npos;-		methodBreakLineNum = 0;-		methodAttachCharNum = std::string::npos;-		methodAttachLineNum = 0;--		if (((shouldBreakOneLineStatements-		        || isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))-		        && isOkToBreakBlock(braceTypeStack->back()))-		        && !(attachClosingBraceMode && peekNextChar() == '}'))-		{-			passedSemicolon = true;-		}-		else if (!shouldBreakOneLineStatements-		         && ASBeautifier::getNextWord(currentLine, charNum) == ASResource::AS_ELSE)-		{-			// handle special case of "else" at the end of line-			size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);-			if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')-				passedSemicolon = true;-		}+    if (currentChar == ';' && !isInAsmBlock)+    {+        squareBracketCount = 0;++        methodBreakCharNum = std::nullopt;+        methodBreakLineNum = 0;+        methodAttachCharNum = std::nullopt;+        methodAttachLineNum = 0;++        if (((shouldBreakOneLineStatements+                || isBraceType(braceTypeStack->back(), BraceType::SINGLE_LINE_TYPE))+                && isOkToBreakBlock(braceTypeStack->back()))+                && !(attachClosingBraceMode && peekNextChar() == '}'))+        {+            passedSemicolon = true;+        }+        else if (!shouldBreakOneLineStatements+                 && ASBeautifier::getNextWord(currentLine, charNum) == ASResource::AS_ELSE)+        {+            // handle special case of "else" at the end of line+            size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);+            if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')+                passedSemicolon = true;+        }  //is set in struct case? #518 #569-		if (shouldBreakBlocks-		        && currentHeader != nullptr-		        && currentHeader != &ASResource::AS_CASE-		        && currentHeader != &ASResource::AS_DEFAULT-		        && !isHeaderInMultiStatementLine-		        && parenStack->back() == 0-		   )-		{-			isAppendPostBlockEmptyLineRequested = true;-		}-	}-	if (currentChar != ';'-	        || foundStructHeader // #518-	        || (needHeaderOpeningBrace && parenStack->back() == 0))-		currentHeader = nullptr;--	resetEndOfStatement();+        if (shouldBreakBlocks+                && currentHeader != nullptr+                && currentHeader != &ASResource::AS_CASE+                && currentHeader != &ASResource::AS_DEFAULT+                && !isHeaderInMultiStatementLine+                && parenStack->back() == 0+           )+        {+            isAppendPostBlockEmptyLineRequested = true;+        }++        // line-between-members=all: insert blank after field at class scope+        if (shouldLineBetweenAllMembers+                && isBraceType(braceTypeStack->back(), BraceType::DEFINITION_TYPE)+                && !isBraceType(braceTypeStack->back(), BraceType::NAMESPACE_TYPE)+                && parenStack->back() == 0)+        {+            needBlankBeforeNextMember = true;+        }+    }+    if (currentChar != ';'+            || foundStructHeader // #518+            || (needHeaderOpeningBrace && parenStack->back() == 0))+        currentHeader = nullptr;++    resetEndOfStatement(); }  void ASFormatter::handleColonSection() {-	if (isInCase)-	{-		isInCase = false;-		if (shouldBreakOneLineStatements)-			passedColon = true;-	}-	else if (isCStyle()                     // for C/C++ only-	         && isOkToBreakBlock(braceTypeStack->back())-	         && shouldBreakOneLineStatements-	         && !foundQuestionMark          // not in a ?: sequence-	         && !foundPreDefinitionHeader   // not in a definition block-	         && previousCommandChar != ')'  // not after closing paren of a method header-	         && !foundPreCommandHeader      // not after a 'noexcept'-	         && squareBracketCount == 0     // not in objC method call-	         && !isInObjCMethodDefinition   // not objC '-' or '+' method-	         && !isInObjCInterface          // not objC @interface-	         && !isInObjCSelector           // not objC @selector-	         && !isDigit(peekNextChar()) && !lineStartsWithNumericType(currentLine)    // not a bit field xxxx-	         && !isInEnum                   // not an enum with a base type-	         && !isInStruct                 // not an struct-	         && !isInContinuedPreProc           // not in preprocessor line-	         && !isInAsm                    // not in extended assembler-	         && !isInAsmOneLine             // not in extended assembler-	         && !isInAsmBlock)              // not in extended assembler-	{-		passedColon = true;-	}--	if (isObjCStyle()-	        && (squareBracketCount > 0 || isInObjCMethodDefinition || isInObjCSelector)-	        && !foundQuestionMark)			// not in a ?: sequence-	{-		isImmediatelyPostObjCMethodPrefix = false;-		isInObjCReturnType = false;-		isInObjCParam = true;-		if (shouldPadMethodColon)-			padObjCMethodColon();-	}--	if (isInObjCInterface)-	{-		appendSpacePad();-		if ((int) currentLine.length() > charNum + 1-		        && !std::isblank(currentLine[charNum + 1]))-			currentLine.insert(charNum + 1, " ");-	}--	if (isClassInitializer())-	{-		isInClassInitializer = true;-	}+    if (isInCase)+    {+        isInCase = false;+        if (shouldBreakOneLineStatements)+            passedColon = true;+    }+    else if (isCStyle()                     // for C/C++ only+             && isOkToBreakBlock(braceTypeStack->back())+             && shouldBreakOneLineStatements+             && !foundQuestionMark          // not in a ?: sequence+             && !foundPreDefinitionHeader   // not in a definition block+             && previousCommandChar != ')'  // not after closing paren of a method header+             && !foundPreCommandHeader      // not after a 'noexcept'+             && squareBracketCount == 0     // not in objC method call+             && !isInObjCMethodDefinition   // not objC '-' or '+' method+             && !isInObjCInterface          // not objC @interface+             && !isInObjCSelector           // not objC @selector+             && !isDigit(peekNextChar()) && !lineStartsWithNumericType(currentLine)    // not a bit field xxxx+             && !isInEnum                   // not an enum with a base type+             && !isInStruct                 // not an struct+             && !isInContinuedPreProc           // not in preprocessor line+             && !isInAsm                    // not in extended assembler+             && !isInAsmOneLine             // not in extended assembler+             && !isInAsmBlock               // not in extended assembler+             && !isModuleImportColon())     // not a C++20 module partition import+    {+        passedColon = true;+    }++    if (isObjCStyle()+            && (squareBracketCount > 0 || isInObjCMethodDefinition || isInObjCSelector)+            && !foundQuestionMark)			// not in a ?: sequence+    {+        isImmediatelyPostObjCMethodPrefix = false;+        isInObjCReturnType = false;+        isInObjCParam = true;+        if (shouldPadMethodColon)+            padObjCMethodColon();+    }++    if (isInObjCInterface)+    {+        appendSpacePad();+        if ((int) currentLine.length() > charNum + 1+                && !std::isblank(currentLine[charNum + 1]))+            currentLine.insert(charNum + 1, " ");+    }++    if (isClassInitializer())+    {+        isInClassInitializer = true;+    } }  void ASFormatter::handlePotentialHeaderPart2() {-	//GL30-	if (!isGSCStyle() && (findKeyword(currentLine, charNum, ASResource::AS_NEW)-	                      || findKeyword(currentLine, charNum, ASResource::AS_DELETE)))-	{-		isInPotentialCalculation = false;-		isImmediatelyPostNewDelete = true;-	}--	//https://sourceforge.net/p/astyle/bugs/464/ + GH16-	if (isSharpStyle() && findKeyword(currentLine, charNum, ASResource::AS_NEW)-	        && currentHeader != &ASResource::AS_FOREACH-	        && currentHeader != &ASResource::AS_FOR-	        && currentHeader != &ASResource::AS_USING-	        && currentHeader != &ASResource::AS_WHILE-	        && currentHeader != &ASResource::AS_IF-	        && currentLine.find(ASResource::AS_PUBLIC) == std::string::npos-	        && currentLine.find(ASResource::AS_PROTECTED) == std::string::npos-	        && currentLine.find(ASResource::AS_PRIVATE) == std::string::npos-	   )-	{-		isInAllocator = true;-	}--	if (findKeyword(currentLine, charNum, ASResource::AS_RETURN))-	{-		isInPotentialCalculation = true;-		isImmediatelyPostReturn = true;		// return is the same as an = sign-	}--	if (findKeyword(currentLine, charNum, ASResource::AS_OPERATOR))-		isImmediatelyPostOperator = true;--	if (findKeyword(currentLine, charNum, ASResource::AS_ENUM))-	{-		size_t firstNum = currentLine.find_first_of("(){},/");-		if (firstNum == std::string::npos-		        || currentLine[firstNum] == '{'-		        || currentLine[firstNum] == '/')-			isInEnum = true;-	}--	if (findKeyword(currentLine, charNum, ASResource::AS_TYPEDEF_STRUCT) || findKeyword(currentLine, charNum, ASResource::AS_STRUCT))-	{-		size_t firstNum = currentLine.find_first_of("(){},/");--		if (firstNum == std::string::npos-		        || currentLine[firstNum] == '{'-		        || currentLine[firstNum] == '/')-		{-			isInStruct = true;-		}-	}--	if (isCStyle()-	        && findKeyword(currentLine, charNum, ASResource::AS_THROW)-	        && previousCommandChar != ')'-	        && !foundPreCommandHeader)      // 'const' throw()-		isImmediatelyPostThrow = true;--	if (isCStyle() && findKeyword(currentLine, charNum, ASResource::AS_EXTERN) && isExternC())-		isInExternC = true;--	if (isCStyle() && findKeyword(currentLine, charNum, ASResource::AS_AUTO)-	        && (isBraceType(braceTypeStack->back(), NULL_TYPE)-	            || isBraceType(braceTypeStack->back(), DEFINITION_TYPE))-	        && (currentLine.find('(') != std::string::npos)) // #516 auto array initializer with braces should not be blocks-		foundTrailingReturnType = true;--	// check for break/attach return type-	if (shouldBreakReturnType || shouldBreakReturnTypeDecl-	        || shouldAttachReturnType || shouldAttachReturnTypeDecl)-	{-		if ((isBraceType(braceTypeStack->back(), NULL_TYPE)-		        || isBraceType(braceTypeStack->back(), DEFINITION_TYPE))-		        && !returnTypeChecked-		        && !foundNamespaceHeader-		        && !foundClassHeader-		        && !isInObjCMethodDefinition-		        // bypass objective-C and java @ character-		        && charNum == (int) currentLine.find_first_not_of(" \t")--		        // possibly related to #504-		        && !(isCStyle() && isCharPotentialHeader(currentLine, charNum)-		             && (findKeyword(currentLine, charNum, ASResource::AS_PUBLIC)-		                 || findKeyword(currentLine, charNum, ASResource::AS_PRIVATE)-		                 || findKeyword(currentLine, charNum, ASResource::AS_PROTECTED)))-		   )-		{-			findReturnTypeSplitPoint(currentLine);-			returnTypeChecked = true;-		}-	}--	// Objective-C NSException macros are preCommandHeaders-	if (isCStyle() && findKeyword(currentLine, charNum, ASResource::AS_NS_DURING))-		foundPreCommandMacro = true;-	if (isCStyle() && findKeyword(currentLine, charNum, ASResource::AS_NS_HANDLER))-		foundPreCommandMacro = true;--	if (isCStyle() && isExecSQL(currentLine, charNum))-		isInExecSQL = true;--	if (isCStyle())-	{-		if (findKeyword(currentLine, charNum, ASResource::AS_ASM)-		        || findKeyword(currentLine, charNum, ASResource::AS__ASM__))-		{-			isInAsm = true;-		}-		else if (findKeyword(currentLine, charNum, ASResource::AS_MS_ASM)		// microsoft specific-		         || findKeyword(currentLine, charNum, ASResource::AS_MS__ASM))-		{-			int index = 4;-			if (peekNextChar() == '_')	// check for __asm-				index = 5;--			char peekedChar = ASBase::peekNextChar(currentLine, charNum + index);-			if (peekedChar == '{' || peekedChar == ' ')-				isInAsmBlock = true;-			else-				isInAsmOneLine = true;-		}-	}--	if (isJavaStyle()-	        && (findKeyword(currentLine, charNum, ASResource::AS_STATIC)-	            && isNextCharOpeningBrace(charNum + 6)))-		isJavaStaticConstructor = true;--	if (isSharpStyle()-	        && (findKeyword(currentLine, charNum, ASResource::AS_DELEGATE)-	            || findKeyword(currentLine, charNum, ASResource::AS_UNCHECKED)))-		isSharpDelegate = true;--	// append the entire name-	std::string_view name = getCurrentWord(currentLine, charNum);-	// must pad the 'and' and 'or' operators if required-	if (name == "and" || name == "or")-	{-		if (shouldPadOperators && previousNonWSChar != ':')-		{-			appendSpacePad();-			appendOperator(std::string(name));-			goForward(name.length() - 1);-			if (!isBeforeAnyComment()-			        && !(currentLine.compare(charNum + 1, 1, ASResource::AS_SEMICOLON) == 0)-			        && !(currentLine.compare(charNum + 1, 2, ASResource::AS_SCOPE_RESOLUTION) == 0))-				appendSpaceAfter();-		}-		else-		{-			appendOperator(std::string(name));-			goForward(name.length() - 1);-		}-	}-	else-	{-		appendSequence(std::string(name));-		goForward(name.length() - 1);-	}+    //GL30+    if (!isGSCStyle() && (findKeyword(currentLine, charNum, ASResource::AS_NEW)+                          || findKeyword(currentLine, charNum, ASResource::AS_DELETE)))+    {+        isInPotentialCalculation = false;+        isImmediatelyPostNewDelete = true;+    }++    //https://sourceforge.net/p/astyle/bugs/464/ + GH16+    if (isSharpStyle() && findKeyword(currentLine, charNum, ASResource::AS_NEW)+            && currentHeader != &ASResource::AS_FOREACH+            && currentHeader != &ASResource::AS_FOR+            && currentHeader != &ASResource::AS_USING+            && currentHeader != &ASResource::AS_WHILE+            && currentHeader != &ASResource::AS_IF+            && currentLine.find(ASResource::AS_PUBLIC) == std::string::npos+            && currentLine.find(ASResource::AS_PROTECTED) == std::string::npos+            && currentLine.find(ASResource::AS_PRIVATE) == std::string::npos+       )+    {+        isInAllocator = true;+    }++    if (findKeyword(currentLine, charNum, ASResource::AS_RETURN))+    {+        isInPotentialCalculation = true;+        isImmediatelyPostReturn = true;		// return is the same as an = sign+    }++    if (findKeyword(currentLine, charNum, ASResource::AS_OPERATOR))+        isImmediatelyPostOperator = true;++    if (findKeyword(currentLine, charNum, ASResource::AS_ENUM))+    {+        size_t firstNum = currentLine.find_first_of("(){},/");+        if (firstNum == std::string::npos+                || currentLine[firstNum] == '{'+                || currentLine[firstNum] == '/')+            isInEnum = true;+    }++    if (findKeyword(currentLine, charNum, ASResource::AS_TYPEDEF_STRUCT) || findKeyword(currentLine, charNum, ASResource::AS_STRUCT))+    {+        size_t firstNum = currentLine.find_first_of("(){},/");++        if (firstNum == std::string::npos+                || currentLine[firstNum] == '{'+                || currentLine[firstNum] == '/')+        {+            isInStruct = true;+            structNestingLevel = bracesNestingLevel;+        }+    }++    if (isCStyle()+            && findKeyword(currentLine, charNum, ASResource::AS_THROW)+            && previousCommandChar != ')'+            && !foundPreCommandHeader)      // 'const' throw()+        isImmediatelyPostThrow = true;++    if (isCStyle() && findKeyword(currentLine, charNum, ASResource::AS_EXTERN) && isExternC())+        isInExternC = true;++    // #342 attribute of a struct/class definition, e.g. 'typedef struct __attribute__((packed)) {'+    if (isCStyle() && foundPreDefinitionHeader && parenStack->back() == 0+            && (findKeyword(currentLine, charNum, ASResource::AS__ATTRIBUTE__)+                || findKeyword(currentLine, charNum, ASResource::AS__DECLSPEC)+                || findKeyword(currentLine, charNum, ASResource::AS_ALIGNAS)))+        foundDefinitionAttribute = true;++    if (isCStyle() && findKeyword(currentLine, charNum, ASResource::AS_AUTO)+            && (isBraceType(braceTypeStack->back(), BraceType::NULL_TYPE)+                || isBraceType(braceTypeStack->back(), BraceType::DEFINITION_TYPE))+            && (currentLine.find('(') != std::string::npos)) // #516 auto array initializer with braces should not be blocks+        foundTrailingReturnType = true;++    // C++20 requires-expression like 'requires(T a) { ... }', not a requires-clause+    // like 'template<class T> requires C<T>' or 'void f() requires C<T> {'+    if (isCStyle() && findKeyword(currentLine, charNum, ASResource::AS_REQUIRES))+    {+        std::string_view prevWord = getPreviousWord(currentLine, charNum);+        if (std::string_view("=(,&|!?:").find(previousNonWSChar) != std::string_view::npos+                || prevWord == ASResource::AS_REQUIRES+                || prevWord == ASResource::AS_RETURN)+            foundRequiresExpression = true;+    }++    // check for break/attach return type+    if (shouldBreakReturnType || shouldBreakReturnTypeDecl+            || shouldAttachReturnType || shouldAttachReturnTypeDecl)+    {+        if ((isBraceType(braceTypeStack->back(), BraceType::NULL_TYPE)+                || isBraceType(braceTypeStack->back(), BraceType::DEFINITION_TYPE))+                && !returnTypeChecked+                && !foundNamespaceHeader+                && !foundClassHeader+                && !isInObjCMethodDefinition+                // bypass objective-C and java @ character+                && charNum == (int) currentLine.find_first_not_of(" \t")++                // possibly related to #504+                && !(isCStyle() && isCharPotentialHeader(currentLine, charNum)+                     && (findKeyword(currentLine, charNum, ASResource::AS_PUBLIC)+                         || findKeyword(currentLine, charNum, ASResource::AS_PRIVATE)+                         || findKeyword(currentLine, charNum, ASResource::AS_PROTECTED)))+           )+        {+            findReturnTypeSplitPoint(currentLine);+            returnTypeChecked = true;+        }+    }++    // Objective-C NSException macros are preCommandHeaders+    if (isCStyle() && findKeyword(currentLine, charNum, ASResource::AS_NS_DURING))+        foundPreCommandMacro = true;+    if (isCStyle() && findKeyword(currentLine, charNum, ASResource::AS_NS_HANDLER))+        foundPreCommandMacro = true;++    if (isCStyle() && isExecSQL(currentLine, charNum))+        isInExecSQL = true;++    if (isCStyle())+    {+        if (findKeyword(currentLine, charNum, ASResource::AS_ASM)+                || findKeyword(currentLine, charNum, ASResource::AS__ASM__))+        {+            isInAsm = true;+        }+        else if (findKeyword(currentLine, charNum, ASResource::AS_MS_ASM)		// microsoft specific+                 || findKeyword(currentLine, charNum, ASResource::AS_MS__ASM))+        {+            int index = 4;+            if (peekNextChar() == '_')	// check for __asm+                index = 5;++            char peekedChar = ASBase::peekNextChar(currentLine, charNum + index);+            if (peekedChar == '{' || peekedChar == ' ')+                isInAsmBlock = true;+            else+                isInAsmOneLine = true;+        }+    }++    if (isJavaStyle()+            && (findKeyword(currentLine, charNum, ASResource::AS_STATIC)+                && isNextCharOpeningBrace(charNum + 6)))+        isJavaStaticConstructor = true;++    if (isSharpStyle()+            && (findKeyword(currentLine, charNum, ASResource::AS_DELEGATE)+                || findKeyword(currentLine, charNum, ASResource::AS_UNCHECKED)))+        isSharpDelegate = true;++    // append the entire name+    std::string_view name = getCurrentWord(currentLine, charNum);+    // must pad the 'and' and 'or' operators if required+    if (name == "and" || name == "or")+    {+        if (shouldPadOperators && previousNonWSChar != ':')+        {+            appendSpacePad();+            appendOperator(std::string(name));+            goForward(name.length() - 1);+            if (!isBeforeAnyComment()+                    && !(currentLine.compare(charNum + 1, 1, ASResource::AS_SEMICOLON) == 0)+                    && !(currentLine.compare(charNum + 1, 2, ASResource::AS_SCOPE_RESOLUTION) == 0))+                appendSpaceAfter();+        }+        else+        {+            appendOperator(std::string(name));+            goForward(name.length() - 1);+        }+    }+    else+    {+        appendSequence(std::string(name));+        goForward(name.length() - 1);+    } }  void ASFormatter::handlePotentialOperator(const std::string *&newHeader) { -	// check for Java ? wildcard-	if (newHeader != nullptr-	        && newHeader == &ASResource::AS_GCC_MIN_ASSIGN-	        && isJavaStyle()-	        && isInTemplate)-		newHeader = nullptr;--	if (newHeader != nullptr)-	{-		if (newHeader == &ASResource::AS_LAMBDA)-			foundPreCommandHeader = true;--		// correct mistake of two >> closing a template-		if (isInTemplate && (newHeader == &ASResource::AS_GR_GR || newHeader == &ASResource::AS_GR_GR_GR))-			newHeader = &ASResource::AS_GR;--		if (!isInPotentialCalculation)-		{-			// must determine if newHeader is an assignment operator-			// do NOT use findOperator - the length must be exact!!!-			if (find(begin(*assignmentOperators), end(*assignmentOperators), newHeader)-			        != end(*assignmentOperators))-			{-				foundPreCommandHeader = false;-				char peekedChar = peekNextChar();-				isInPotentialCalculation = !(newHeader == &ASResource::AS_EQUAL && peekedChar == '*')-				                           && !(newHeader == &ASResource::AS_EQUAL && peekedChar == '&')-				                           && !isCharImmediatelyPostOperator;-			}-		}-	}+    // check for Java ? wildcard+    if (newHeader != nullptr+            && newHeader == &ASResource::AS_GCC_MIN_ASSIGN+            && isJavaStyle()+            && isInTemplate)+        newHeader = nullptr;++    if (newHeader != nullptr)+    {+        if (newHeader == &ASResource::AS_LAMBDA)+            foundPreCommandHeader = true;++        // correct mistake of two >> closing a template+        if (isInTemplate && (newHeader == &ASResource::AS_GR_GR || newHeader == &ASResource::AS_GR_GR_GR))+            newHeader = &ASResource::AS_GR;++        if (!isInPotentialCalculation)+        {+            // must determine if newHeader is an assignment operator+            // do NOT use findOperator - the length must be exact!!!+            if (find(begin(*assignmentOperators), end(*assignmentOperators), newHeader)+                    != end(*assignmentOperators))+            {+                foundPreCommandHeader = false;+                char peekedChar = peekNextChar();+                isInPotentialCalculation = !(newHeader == &ASResource::AS_EQUAL && peekedChar == '*')+                                           && !(newHeader == &ASResource::AS_EQUAL && peekedChar == '&')+                                           && !isCharImmediatelyPostOperator;+            }+        }+    } }  void ASFormatter::handleParens() {-	if (currentChar == '(')-	{-		if (shouldPadHeader-		        && (isCharImmediatelyPostReturn-		            || isCharImmediatelyPostThrow-		            || isCharImmediatelyPostNewDelete))-			appendSpacePad();-	}--	if (shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen)-		padParensOrBrackets('(', ')', shouldPadFirstParen);-	else-		appendCurrentChar();--	if (isInObjCMethodDefinition)-	{-		if (currentChar == '(' && isImmediatelyPostObjCMethodPrefix)-		{-			if (shouldPadMethodPrefix || shouldUnPadMethodPrefix)-				padObjCMethodPrefix();-			isImmediatelyPostObjCMethodPrefix = false;-			isInObjCReturnType = true;-		}-		else if (currentChar == ')' && isInObjCReturnType)-		{-			if (shouldPadReturnType || shouldUnPadReturnType)-				padObjCReturnType();-			isInObjCReturnType = false;-		}-		else if (isInObjCParam-		         && (shouldPadParamType || shouldUnPadParamType))-			padObjCParamType();-	}+    if (currentChar == '(')+    {+        if (shouldPadHeader+                && (isCharImmediatelyPostReturn+                    || isCharImmediatelyPostThrow+                    || isCharImmediatelyPostNewDelete))+            appendSpacePad();+    }++    if (shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen)+        padParensOrBrackets('(', ')', shouldPadFirstParen);+    else+        appendCurrentChar();++    if (isInObjCMethodDefinition)+    {+        if (currentChar == '(' && isImmediatelyPostObjCMethodPrefix)+        {+            if (shouldPadMethodPrefix || shouldUnPadMethodPrefix)+                padObjCMethodPrefix();+            isImmediatelyPostObjCMethodPrefix = false;+            isInObjCReturnType = true;+        }+        else if (currentChar == ')' && isInObjCReturnType)+        {+            if (shouldPadReturnType || shouldUnPadReturnType)+                padObjCReturnType();+            isInObjCReturnType = false;+        }+        else if (isInObjCParam+                 && (shouldPadParamType || shouldUnPadParamType))+            padObjCParamType();+    } }   void ASFormatter::handleOpenParens() {-	questionMarkStack->push_back(foundQuestionMark);-	foundQuestionMark = false;-	parenStack->back()++;-	if (currentChar == '[')-	{-		++squareBracketCount;-		if (getAlignMethodColon() && squareBracketCount == 1 &&-		        isCStyle())-			objCColonAlign = findObjCColonAlignment();-	}-	if (currentChar == '(')-	{-		++parenthesesCount;-	}+    questionMarkStack->push_back(foundQuestionMark);+    foundQuestionMark = false;+    parenStack->back()++;+    if (currentChar == '[')+    {+        ++squareBracketCount;+        if (getAlignMethodColon() && squareBracketCount == 1 &&+                isCStyle())+            objCColonAlign = findObjCColonAlignment();+    }+    if (currentChar == '(')+    {+        ++parenthesesCount;+    } }  void ASFormatter::formatFirstOpenBrace(BraceType braceType) {-	if (braceFormatMode == ATTACH_MODE || braceFormatMode == LINUX_MODE)-	{-		// break an enum if mozilla-		if (isBraceType(braceType, ENUM_TYPE)-		        && formattingStyle == STYLE_MOZILLA-		        && !(!shouldBreakOneLineBlocks && formattedLine.find('}' != std::string::npos) ) // GL38-		   )-		{-			isInLineBreak = true;-			appendCurrentChar();                // don't attach-		}-		// don't attach to a preprocessor directive or '\' line-		else if ((isImmediatelyPostPreprocessor-		          || (!formattedLine.empty()-		              && formattedLine[formattedLine.length() - 1] == '\\'))-		         && currentLineBeginsWithBrace)-		{-			isInLineBreak = true;-			appendCurrentChar();                // don't attach-		}-		else if (isCharImmediatelyPostComment)-		{-			// TODO: attach brace to line-end comment-			appendCurrentChar();                // don't attach-		}-		else if (isCharImmediatelyPostLineComment && !isBraceType(braceType, SINGLE_LINE_TYPE))-		{-			appendCharInsideComments();-		}-		else-		{-			// if a blank line precedes this don't attach-			if (isEmptyLine(formattedLine))-				appendCurrentChar();            // don't attach-			else-			{-				// if brace is broken or not an assignment-				if (currentLineBeginsWithBrace-				        && !isBraceType(braceType, SINGLE_LINE_TYPE))-				{-					appendSpacePad();-					appendCurrentChar(false);				// OK to attach-					// TODO: debug the following line-					testForTimeToSplitFormattedLine();		// line length will have changed--					if (currentLineBeginsWithBrace && currentLineFirstBraceNum == (size_t) charNum)-						shouldBreakLineAtNextChar = true;-				}-				else-				{-					if (previousNonWSChar != '(')-					{-						// don't space pad C++11 uniform initialization-						if (!isBraceType(braceType, INIT_TYPE))-							appendSpacePad();-					}-					appendCurrentChar();-				}-			}-		}-	}-	else if (braceFormatMode == BREAK_MODE)-	{-		if (std::isblank(peekNextChar()) && !isInVirginLine)-			breakLine();-		else if (isBeforeAnyComment() && sourceIterator->hasMoreLines())-		{-			// do not break unless comment is at line end-			if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)-			{-				currentChar = ' ';            // remove brace from current line-				appendOpeningBrace = true;    // append brace to following line-			}-		}-		if (!isInLineBreak && previousNonWSChar != '(')-		{-			// don't space pad C++11 uniform initialization-			if (!isBraceType(braceType, INIT_TYPE))-				appendSpacePad();-		}-		appendCurrentChar();--		if (currentLineBeginsWithBrace-		        && currentLineFirstBraceNum == (size_t) charNum-		        && !isBraceType(braceType, SINGLE_LINE_TYPE))-			shouldBreakLineAtNextChar = true;-	}-	else if (braceFormatMode == RUN_IN_MODE)-	{-		if (std::isblank(peekNextChar()) && !isInVirginLine)-			breakLine();-		else if (isBeforeAnyComment() && sourceIterator->hasMoreLines())-		{-			// do not break unless comment is at line end-			if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)-			{-				currentChar = ' ';            // remove brace from current line-				appendOpeningBrace = true;    // append brace to following line-			}-		}-		if (!isInLineBreak && previousNonWSChar != '(')-		{-			// don't space pad C++11 uniform initialization-			if (!isBraceType(braceType, INIT_TYPE))-				appendSpacePad();-		}-		appendCurrentChar();-	}-	else if (braceFormatMode == NONE_MODE)-	{-		if (currentLineBeginsWithBrace-		        && (size_t) charNum == currentLineFirstBraceNum)-		{-			appendCurrentChar();                // don't attach-		}-		else-		{-			if (previousNonWSChar != '(')-			{-				// don't space pad C++11 uniform initialization-				if (!isBraceType(braceType, INIT_TYPE))-					appendSpacePad();-			}-			appendCurrentChar(false);           // OK to attach-		}-	}+    if (shouldPreserveBraceFormat)+    {+        appendCurrentChar();+        return;+    }++    if (braceFormatMode == ATTACH_MODE || braceFormatMode == LINUX_MODE)+    {+        // break an enum if mozilla+        if (isBraceType(braceType, BraceType::ENUM_TYPE)+                && formattingStyle == STYLE_MOZILLA+                && !(!shouldBreakOneLineBlocks && formattedLine.find('}' != std::string::npos) ) // GL38+           )+        {+            isInLineBreak = true;+            appendCurrentChar();                // don't attach+        }+        // don't attach to a preprocessor directive or '\' line+        else if ((isImmediatelyPostPreprocessor+                  || (!formattedLine.empty()+                      && formattedLine[formattedLine.length() - 1] == '\\'))+                 && currentLineBeginsWithBrace)+        {+            isInLineBreak = true;+            appendCurrentChar();                // don't attach+        }+        else if (isCharImmediatelyPostComment)+        {+            // TODO: attach brace to line-end comment+            appendCurrentChar();                // don't attach+        }+        else if (isCharImmediatelyPostLineComment && !isBraceType(braceType, BraceType::SINGLE_LINE_TYPE))+        {+            appendCharInsideComments();+        }+        else+        {+            // if a blank line precedes this don't attach+            if (isEmptyLine(formattedLine))+                appendCurrentChar();            // don't attach+            else+            {+                // if brace is broken or not an assignment+                if (currentLineBeginsWithBrace+                        && !isBraceType(braceType, BraceType::SINGLE_LINE_TYPE))+                {+                    appendSpacePad();+                    appendCurrentChar(false);				// OK to attach+                    // TODO: debug the following line+                    testForTimeToSplitFormattedLine();		// line length will have changed++                    if (currentLineBeginsWithBrace && currentLineFirstBraceNum == (size_t) charNum)+                        shouldBreakLineAtNextChar = true;+                }+                else+                {+                    if (previousNonWSChar != '(')+                    {+                        // don't space pad C++11 uniform initialization+                        if (!isBraceType(braceType, BraceType::INIT_TYPE))+                            appendSpacePad();+                    }+                    appendCurrentChar();+                }+            }+        }+    }+    else if (braceFormatMode == BREAK_MODE)+    {+        if (std::isblank(peekNextChar()) && !isInVirginLine)+            breakLine();+        else if (isBeforeAnyComment() && sourceIterator->hasMoreLines())+        {+            // do not break unless comment is at line end+            if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)+            {+                currentChar = ' ';            // remove brace from current line+                appendOpeningBrace = true;    // append brace to following line+            }+        }+        if (!isInLineBreak && previousNonWSChar != '(')+        {+            // don't space pad C++11 uniform initialization+            if (!isBraceType(braceType, BraceType::INIT_TYPE))+                appendSpacePad();+        }+        appendCurrentChar();++        if (currentLineBeginsWithBrace+                && currentLineFirstBraceNum == (size_t) charNum+                && !isBraceType(braceType, BraceType::SINGLE_LINE_TYPE))+            shouldBreakLineAtNextChar = true;+    }+    else if (braceFormatMode == RUN_IN_MODE)+    {+        if (std::isblank(peekNextChar()) && !isInVirginLine)+            breakLine();+        else if (isBeforeAnyComment() && sourceIterator->hasMoreLines())+        {+            // do not break unless comment is at line end+            if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)+            {+                currentChar = ' ';            // remove brace from current line+                appendOpeningBrace = true;    // append brace to following line+            }+        }+        if (!isInLineBreak && previousNonWSChar != '(')+        {+            // don't space pad C++11 uniform initialization+            if (!isBraceType(braceType, BraceType::INIT_TYPE))+                appendSpacePad();+        }+        appendCurrentChar();+    }+    else if (braceFormatMode == NONE_MODE)+    {+        if (currentLineBeginsWithBrace+                && (size_t) charNum == currentLineFirstBraceNum)+        {+            appendCurrentChar();                // don't attach+        }+        else+        {+            if (previousNonWSChar != '(')+            {+                // don't space pad C++11 uniform initialization+                if (!isBraceType(braceType, BraceType::INIT_TYPE))+                    appendSpacePad();+            }+            appendCurrentChar(false);           // OK to attach+        }+    } }  void ASFormatter::formatOpenBrace() {-	if (braceFormatMode == RUN_IN_MODE)-	{-		if (previousNonWSChar == '{'-		        && braceTypeStack->size() > 2-		        && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],-		                        SINGLE_LINE_TYPE))-			formatArrayRunIn();-	}-	else if (!isInLineBreak-	         && !std::isblank(peekNextChar())-	         && previousNonWSChar == '{'-	         && braceTypeStack->size() > 2-	         && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],-	                         SINGLE_LINE_TYPE))-		formatArrayRunIn();--	appendCurrentChar();+    if (!shouldPreserveBraceFormat)+    {+        if (braceFormatMode == RUN_IN_MODE)+        {+            if (previousNonWSChar == '{'+                    && braceTypeStack->size() > 2+                    && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],+                                    BraceType::SINGLE_LINE_TYPE))+                formatArrayRunIn();+        }+        else if (!isInLineBreak+                 && !std::isblank(peekNextChar())+                 && previousNonWSChar == '{'+                 && braceTypeStack->size() > 2+                 && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],+                                 BraceType::SINGLE_LINE_TYPE))+            formatArrayRunIn();+    }++    appendCurrentChar(); }  void ASFormatter::formatCloseBrace(BraceType braceType) {-	if (attachClosingBraceMode)-	{-		if (isEmptyLine(formattedLine)			// if a blank line precedes this-		        || isImmediatelyPostPreprocessor-		        || isCharImmediatelyPostLineComment-		        || isCharImmediatelyPostComment)-			appendCurrentChar();				// don't attach-		else-		{-			appendSpacePad();-			appendCurrentChar(false);			// attach-		}-	}-	else-	{-		// does this close the first opening brace in the array?-		// must check if the block is still a single line because of anonymous statements-		if (!isBraceType(braceType, INIT_TYPE)-		        && (!isBraceType(braceType, SINGLE_LINE_TYPE)-		            || formattedLine.find('{') == std::string::npos))-			breakLine();-		appendCurrentChar();-	}--	// if a declaration follows an enum definition, space pad-	char peekedChar = peekNextChar();-	if ((isLegalNameChar(peekedChar) && peekedChar != '.')-	        || peekedChar == '[')-		appendSpaceAfter();+    if (shouldPreserveBraceFormat)+    {+        appendCurrentChar();+    }+    else if (attachClosingBraceMode)+    {+        if (isEmptyLine(formattedLine)			// if a blank line precedes this+                || isImmediatelyPostPreprocessor+                || isCharImmediatelyPostLineComment+                || isCharImmediatelyPostComment)+            appendCurrentChar();				// don't attach+        else+        {+            appendSpacePad();+            appendCurrentChar(false);			// attach+        }+    }+    else+    {+        // does this close the first opening brace in the array?+        // must check if the block is still a single line because of anonymous statements+        if (!isBraceType(braceType, BraceType::INIT_TYPE)+                && (!isBraceType(braceType, BraceType::SINGLE_LINE_TYPE)+                    || formattedLine.find('{') == std::string::npos))+            breakLine();+        appendCurrentChar();+    }++    // if a declaration follows an enum definition, space pad+    char peekedChar = peekNextChar();+    if ((isLegalNameChar(peekedChar) && peekedChar != '.')+            || peekedChar == '[')+        appendSpaceAfter(); }    std::string ASFormatter::nextLine() {-	const std::string* newHeader = nullptr;-	isInVirginLine = isVirgin;-	isCharImmediatelyPostComment = false;-	isPreviousCharPostComment = false;-	isCharImmediatelyPostLineComment = false;-	isCharImmediatelyPostOpenBlock = false;-	isCharImmediatelyPostCloseBlock = false;-	isCharImmediatelyPostTemplate = false;--	while (!isLineReady)-	{-		if (shouldReparseCurrentChar)-			shouldReparseCurrentChar = false;-		else if (!getNextChar())-		{-			breakLine();-			continue;-		}-		else // stuff to do when reading a new character...-		{-			// make sure that a virgin '{' at the beginning of the file will be treated as a block...-			if (isInVirginLine && currentChar == '{'-			        && currentLineBeginsWithBrace-			        && previousCommandChar == ' ')-				previousCommandChar = '{';-			if (isInClassInitializer-			        && isBraceType(braceTypeStack->back(), COMMAND_TYPE))-				isInClassInitializer = false;-			if (isInBraceRunIn)-				isInLineBreak = false;-			if (!std::isblank(currentChar))-				isInBraceRunIn = false;-			isPreviousCharPostComment = isCharImmediatelyPostComment;-			isCharImmediatelyPostComment = false;-			isCharImmediatelyPostTemplate = false;-			isCharImmediatelyPostReturn = false;-			isCharImmediatelyPostThrow = false;-			isCharImmediatelyPostNewDelete = false;-			isCharImmediatelyPostOperator = false;-			isCharImmediatelyPostPointerOrReference = false;-			isCharImmediatelyPostOpenBlock = false;-			isCharImmediatelyPostCloseBlock = false;-		}--		if ((lineIsLineCommentOnly || lineIsCommentOnly)-		        && currentLine.find("*INDENT-ON*", charNum) != std::string::npos-		        && isFormattingModeOff)-		{-			isFormattingModeOff = false;-			breakLine();-			formattedLine = currentLine;-			charNum = (int) currentLine.length() - 1;-			continue;-		}-		if (isFormattingModeOff)-		{-			breakLine();-			formattedLine = currentLine;-			charNum = (int) currentLine.length() - 1;-			continue;-		}--		if ((lineIsLineCommentOnly || lineIsCommentOnly)-		        && currentLine.find("*INDENT-OFF*", charNum) != std::string::npos)-		{-			isFormattingModeOff = true;-			if (isInLineBreak)			// is true if not the first line-				breakLine();-			formattedLine = currentLine;-			charNum = (int) currentLine.length() - 1;-			continue;-		}--		if (shouldBreakLineAtNextChar)-		{-			if (std::isblank(currentChar) && !lineIsEmpty)-				continue;-			isInLineBreak = true;-			shouldBreakLineAtNextChar = false;-		}--		if (isInExecSQL && !passedSemicolon)-		{-			if (currentChar == ';')-				passedSemicolon = true;-			appendCurrentChar();-			continue;-		}--		if (isInLineComment)-		{-			formatLineCommentBody();-			continue;-		}--		if (isInComment)-		{-			formatCommentBody();-			continue;-		}--		if (isInQuote)-		{-			formatQuoteBody();-			continue;-		}--		// not in quote or comment or line comment--		if (isSequenceReached(ASResource::AS_OPEN_LINE_COMMENT))-		{-			formatLineCommentOpener();-			testForTimeToSplitFormattedLine();-			continue;-		}-		if (isSequenceReached(ASResource::AS_OPEN_COMMENT) || (isGSCStyle() && isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT)))-		{-			formatCommentOpener();-			testForTimeToSplitFormattedLine();-			continue;-		}-		if (currentChar == '"'-		        || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)))-		{-			formatQuoteOpener();-			testForTimeToSplitFormattedLine();-			continue;-		}-		// treat these preprocessor statements as a line comment--		if ((currentChar == '#')-		        && currentLine.find_first_not_of(" \t") == (size_t) charNum)-		{-			isInContinuedPreProc = currentLine[currentLine.size() - 1] == '\\';-		}--		if (isInPreprocessor)-		{-			appendCurrentChar();-			continue;-		}--		if (isInTemplate && shouldCloseTemplates)-		{-			if (previousNonWSChar == '>' && std::isblank(currentChar) && peekNextChar() == '>')-				continue;-		}--		if (shouldRemoveNextClosingBrace && currentChar == '}')-		{-			currentLine[charNum] = currentChar = ' ';-			shouldRemoveNextClosingBrace = false;-			assert(adjustChecksumIn(-'}'));-			if (isEmptyLine(currentLine))-				continue;-		}--		// handle white space - needed to simplify the rest.-		if (std::isblank(currentChar))-		{-			appendCurrentChar();-			continue;-		}--		/* not in MIDDLE of quote or comment or SQL or white-space of any type ... */--		// check if in preprocessor-		// ** isInPreprocessor will be automatically reset at the beginning-		//    of a new line in getnextChar()-		if (currentChar == '#' && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))-		{-			isInPreprocessor = true;-			// check for run-in-			if (!formattedLine.empty() && formattedLine[0] == '{')-			{-				isInLineBreak = true;-				isInBraceRunIn = false;-			}-			processPreprocessor();-		}--		/* not in preprocessor ... */--		if (isImmediatelyPostComment)-		{-			caseHeaderFollowsComments = false;-			isImmediatelyPostComment = false;-			isCharImmediatelyPostComment = true;-		}--		if (isImmediatelyPostLineComment)-		{-			caseHeaderFollowsComments = false;-			isImmediatelyPostLineComment = false;-			isCharImmediatelyPostLineComment = true;-		}--		if (isImmediatelyPostReturn)-		{-			isImmediatelyPostReturn = false;-			isCharImmediatelyPostReturn = true;-		}--		if (isImmediatelyPostThrow)-		{-			isImmediatelyPostThrow = false;-			isCharImmediatelyPostThrow = true;-		}--		if (isImmediatelyPostNewDelete)-		{-			isImmediatelyPostNewDelete = false;-			isCharImmediatelyPostNewDelete = true;-		}--		if (isImmediatelyPostOperator)-		{-			isImmediatelyPostOperator = false;-			isCharImmediatelyPostOperator = true;-		}-		if (isImmediatelyPostTemplate)-		{-			isImmediatelyPostTemplate = false;-			isCharImmediatelyPostTemplate = true;-		}-		if (isImmediatelyPostPointerOrReference)-		{-			isImmediatelyPostPointerOrReference = false;-			isCharImmediatelyPostPointerOrReference = true;-		}--		// reset isImmediatelyPostHeader information-		if (isImmediatelyPostHeader)-		{-			if (!handleImmediatelyPostHeaderSection())-				continue;-		}--		if (passedSemicolon)    // need to break the formattedLine-		{-			if (!handlePassedSemicolonSection())-				continue;-		}--		if (passedColon)-		{-			passedColon = false;-			if (parenStack->back() == 0-			        && !isBeforeAnyComment()-			        && (formattedLine.find_first_not_of(" \t") != std::string::npos))-			{-				shouldReparseCurrentChar = true;-				isInLineBreak = true;-				continue;-			}-		}--		// Check if in template declaration, e.g. foo<bar> or foo<bar,fig>-		if (!isInTemplate && currentChar == '<')-		{-			checkIfTemplateOpener();-		}--		// Check for break return type-		if ((size_t) charNum >= methodBreakCharNum && methodBreakLineNum == 0)-		{-			if ((size_t) charNum == methodBreakCharNum)-				isInLineBreak = true;-			methodBreakCharNum = std::string::npos;-			methodBreakLineNum = 0;-		}-		// Check for attach return type-		if ((size_t) charNum >= methodAttachCharNum && methodAttachLineNum == 0)-		{-			handleAttachedReturnTypes();-		}--		// handle parens-		if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))-		{-			handleOpenParens();-		}--		else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))-		{-			handleClosedBracesOrParens();-		}--		// handle braces-		if (currentChar == '{' || currentChar == '}')-		{-			handleBraces();-			continue;-		}--		// #126-		if ( currentChar == '*' && shouldPadOperators &&-		        pointerAlignment != PTR_ALIGN_TYPE &&  // SF 557-		        peekNextChar() != '=' && // GH 81-		        ( currentHeader == &ASResource::AS_IF || currentHeader == &ASResource::AS_WHILE ||-		          currentHeader == &ASResource::AS_DO || currentHeader == &ASResource::AS_FOR)-		        && ( previousChar == ')' || std::isalpha(previousChar) )-		        && !isOperatorPaddingDisabled() )-		{-			appendSpacePad();-			appendOperator(ASResource::AS_MULT);-			goForward(0);-			appendSpaceAfter();-			continue;-		}--		if ((((previousCommandChar == '{' && isPreviousBraceBlockRelated)-		        || ((previousCommandChar == '}'-		             && !isImmediatelyPostEmptyBlock-		             && isPreviousBraceBlockRelated-		             && !isPreviousCharPostComment       // Fixes wrongly appended newlines after '}' immediately after comments-		             && peekNextChar() != ' '-		             && !isBraceType(previousBraceType, DEFINITION_TYPE))-		            && !isBraceType(braceTypeStack->back(), DEFINITION_TYPE)))-		        && isOkToBreakBlock(braceTypeStack->back()))-		        // check for array-		        || (previousCommandChar == '{'			// added 9/30/2010-		            && isBraceType(braceTypeStack->back(), ARRAY_TYPE)-		            && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)-		            && isNonInStatementArray)-		        // check for pico one line braces-		        || (formattingStyle == STYLE_PICO-		            && (previousCommandChar == '{' && isPreviousBraceBlockRelated)-		            && isBraceType(braceTypeStack->back(), COMMAND_TYPE)-		            && isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)-		            && braceFormatMode == RUN_IN_MODE)-		   )-		{-			handleBreakLine();-		}--		// reset block handling flags-		isImmediatelyPostEmptyBlock = false;--		// Objective-C method prefix with no return type-		if (isImmediatelyPostObjCMethodPrefix && currentChar != '(')-		{-			if (shouldPadMethodPrefix || shouldUnPadMethodPrefix)-				padObjCMethodPrefix();-			isImmediatelyPostObjCMethodPrefix = false;-		}--		// look for headers-		bool isPotentialHeader = isCharPotentialHeader(currentLine, charNum);--		if (isPotentialHeader && !isInTemplate && squareBracketCount == 0)-		{-			if (!handlePotentialHeader(newHeader))-				continue;-		}   // (isPotentialHeader && !isInTemplate)--		if (isInLineBreak)          // OK to break line here-		{-			breakLine();-			if (isInVirginLine)		// adjust for the first line-			{-				lineCommentNoBeautify = lineCommentNoIndent;-				lineCommentNoIndent = false;-				if (isImmediatelyPostPreprocessor)-				{-					isInIndentablePreproc = isIndentablePreprocessor;-					isIndentablePreprocessor = false;-				}-			}-		}--		if (previousNonWSChar == '}' || currentChar == ';')-		{-			handleEndOfBlock();-		}--		if (currentChar == ':'-		        && previousChar != ':'         // not part of '::'-		        && peekNextChar() != ':')      // not part of '::'-		{-			handleColonSection();-		}--		if (currentChar == '?')-			foundQuestionMark = true;--		if (isPotentialHeader && !isInTemplate)-		{-			handlePotentialHeaderPart2();-			continue;-		}   // (isPotentialHeader &&  !isInTemplate)--		// determine if this is an Objective-C statement--		if (currentChar == '@'-		        && isCStyle()-		        && (int) currentLine.length() > charNum + 1-		        && !std::isblank(currentLine[charNum + 1])-		        && isCharPotentialHeader(currentLine, charNum + 1)-		        && findKeyword(currentLine, charNum + 1, ASResource::AS_INTERFACE)-		        && isBraceType(braceTypeStack->back(), NULL_TYPE))-		{-			isInObjCInterface = true;-			std::string name = '@' + ASResource::AS_INTERFACE;-			appendSequence(name);-			goForward(name.length() - 1);-			continue;-		}-		if (currentChar == '@'-		        && isCStyle()-		        && (int) currentLine.length() > charNum + 1-		        && !std::isblank(currentLine[charNum + 1])-		        && isCharPotentialHeader(currentLine, charNum + 1)-		        && findKeyword(currentLine, charNum + 1, ASResource::AS_SELECTOR))-		{-			isInObjCSelector = true;-			std::string name = '@' + ASResource::AS_SELECTOR;-			appendSequence(name);-			goForward(name.length() - 1);-			continue;-		}-		if ((currentChar == '-' || currentChar == '+')-		        && isCStyle()-		        && (int) currentLine.find_first_not_of(" \t") == charNum-		        && !isInPotentialCalculation-		        && !isInObjCMethodDefinition-		        && (isBraceType(braceTypeStack->back(), NULL_TYPE)-		            || (isBraceType(braceTypeStack->back(), EXTERN_TYPE))))-		{-			isInObjCMethodDefinition = true;-			isImmediatelyPostObjCMethodPrefix = true;-			isInObjCParam = false;-			isInObjCInterface = false;-			if (getAlignMethodColon())-				objCColonAlign = findObjCColonAlignment();-			appendCurrentChar();-			continue;-		}--		// determine if this is a potential calculation--		bool isPotentialOperator = isCharPotentialOperator(currentChar);-		newHeader = nullptr;--		// Skip operator detection for git conflict markers-		if (isPotentialOperator && !isGitConflictMarker(currentLine))-		{-			newHeader = findOperator(operators);--			handlePotentialOperator(newHeader);-		}--		size_t lastNonWsChar = currentLine.find_last_not_of(" \t", charNum - 1);--		if (lastNonWsChar != std::string::npos && pointerAlignment == PTR_ALIGN_TYPE && !isGSCStyle() && !preserveWhitespace && !isInPreprocessor)-		{-			char lastChar = currentLine[lastNonWsChar];--			//fix SF605, possibly more cases pending-			char nextChar = 0;-			size_t nextCharPos = currentLine.find_first_not_of(" \t", lastNonWsChar+1);-			if (nextCharPos != std::string::npos) nextChar = currentLine[nextCharPos];--			if (lastChar == ',' && nextChar != '+' && nextChar != '-')-			{-				formattedLine = rtrim(formattedLine);-				formattedLine += ' ';-			}--		}--		// process pointers and references-		// check newHeader to eliminate things like '&&' sequence-		if (newHeader != nullptr && !isJavaStyle()-		        && (newHeader == &ASResource::AS_MULT-		            || newHeader == &ASResource::AS_BIT_AND-		            || newHeader == &ASResource::AS_BIT_XOR-		            || newHeader == &ASResource::AS_AND)-		        && isPointerOrReference())-		{--			if (!isDereferenceOrAddressOf() && !isOperatorPaddingDisabled())-			{-				formatPointerOrReference();-			}-			else-			{-				appendOperator(*newHeader);-				goForward(newHeader->length() - 1);-			}-			isImmediatelyPostPointerOrReference = true;-			continue;-		}--		if ((shouldPadOperators || negationPadMode != NEGATION_PAD_NO_CHANGE) && newHeader != nullptr && !isOperatorPaddingDisabled())-		{-			padOperators(newHeader);-			continue;-		}--		// remove spaces before commas-		if (currentChar == ',')-		{-			const size_t len = formattedLine.length();-			size_t lastText = formattedLine.find_last_not_of(' ');-			if (lastText != std::string::npos && lastText < len - 1)-			{-				formattedLine.resize(lastText + 1);-				int size_diff = len - (lastText + 1);-				spacePadNum -= size_diff;-			}-		}--		// pad commas and semi-colons-		if (currentChar == ';'-		        || (currentChar == ',' && (shouldPadOperators || shouldPadCommas)))-		{-			char nextChar = ' ';-			if (charNum + 1 < (int) currentLine.length())-				nextChar = currentLine[charNum + 1];-			if (!std::isblank(nextChar)-			        && nextChar != '}'-			        && nextChar != ')'-			        && nextChar != ']'-			        && nextChar != '>'-			        && nextChar != ';'-			        && !isBeforeAnyComment()-			   )-			{-				appendCurrentChar();-				appendSpaceAfter();-				continue;-			}-		}--		// pad parens-		if (currentChar == '(' || currentChar == ')')-		{-			handleParens();-			continue;-		}--		//GL31-		bool isDoubleOpenBrackets = isGSCStyle() && currentChar == '[' && peekNextChar() == '[';--		if ((currentChar == '[' || currentChar == ']' ) && (shouldPadBracketsOutside || shouldPadBracketsInside || shouldUnPadBrackets) && !isDoubleOpenBrackets)-		{-			padParensOrBrackets('[', ']', false);-			continue;-		}--		// bypass the entire operator-		if (newHeader != nullptr)-		{-			appendOperator(*newHeader);-			goForward(newHeader->length() - 1);-			continue;-		}--		appendCurrentChar();--	}   // end of while loop  *  end of while loop  *  end of while loop  *  end of while loop--	// return a beautified (i.e. correctly indented) line.--	std::string beautifiedLine;-	size_t readyFormattedLineLength = trim(readyFormattedLine).length();-	bool isInNamespace = isBraceType(braceTypeStack->back(), NAMESPACE_TYPE);--	if (prependEmptyLine		// prepend a blank line before this formatted line-	        && readyFormattedLineLength > 0-	        && previousReadyFormattedLineLength > 0)-	{-		isLineReady = true;		// signal a waiting readyFormattedLine-		beautifiedLine = beautify("");-		previousReadyFormattedLineLength = 0;-		// call the enhancer for new empty lines-		enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);-	}-	else		// format the current formatted line-	{-		isLineReady = false;-		runInIndentContinuation = runInIndentChars;-		beautifiedLine = beautify(readyFormattedLine);-		previousReadyFormattedLineLength = readyFormattedLineLength;-		// the enhancer is not called for no-indent line comments-		if (!lineCommentNoBeautify && !isFormattingModeOff)-			enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);-		runInIndentChars = 0;-		lineCommentNoBeautify = lineCommentNoIndent;-		lineCommentNoIndent = false;-		isInIndentablePreproc = isIndentablePreprocessor;-		isIndentablePreprocessor = false;-		isElseHeaderIndent = elseHeaderFollowsComments;-		isCaseHeaderCommentIndent = caseHeaderFollowsComments;-		objCColonAlignSubsequent = objCColonAlign;-		if (isCharImmediatelyPostNonInStmt)-		{-			isNonInStatementArray = false;-			isCharImmediatelyPostNonInStmt = false;-		}-		isInPreprocessorBeautify = isInPreprocessor;	// used by ASEnhancer-		isInBeautifySQL = isInExecSQL;					// used by ASEnhancer-	}--	prependEmptyLine = false;-	assert(computeChecksumOut(beautifiedLine));-	return beautifiedLine;+    const std::string* newHeader = nullptr;+    isInVirginLine = isVirgin;+    isCharImmediatelyPostComment = false;+    isPreviousCharPostComment = false;+    isCharImmediatelyPostLineComment = false;+    isCharImmediatelyPostOpenBlock = false;+    isCharImmediatelyPostCloseBlock = false;+    isCharImmediatelyPostTemplate = false;++    while (!isLineReady)+    {+        const bool isReparsingCurrentChar = shouldReparseCurrentChar;+        if (shouldReparseCurrentChar)+            shouldReparseCurrentChar = false;+        else if (!getNextChar())+        {+            breakLine();+            continue;+        }+        else // stuff to do when reading a new character...+        {+            // make sure that a virgin '{' at the beginning of the file will be treated as a block...+            if (isInVirginLine && currentChar == '{'+                    && currentLineBeginsWithBrace+                    && previousCommandChar == ' ')+                previousCommandChar = '{';+            if (isInClassInitializer+                    && isBraceType(braceTypeStack->back(), BraceType::COMMAND_TYPE))+                isInClassInitializer = false;+            if (isInBraceRunIn)+                isInLineBreak = false;+            if (!std::isblank(currentChar))+                isInBraceRunIn = false;+            isPreviousCharPostComment = isCharImmediatelyPostComment;+            isCharImmediatelyPostComment = false;+            isCharImmediatelyPostTemplate = false;+            isCharImmediatelyPostReturn = false;+            isCharImmediatelyPostThrow = false;+            isCharImmediatelyPostNewDelete = false;+            isCharImmediatelyPostOperator = false;+            isCharImmediatelyPostPointerOrReference = false;+            isCharImmediatelyPostOpenBlock = false;+            isCharImmediatelyPostCloseBlock = false;+        }++        if ((lineIsLineCommentOnly || lineIsCommentOnly)+                && currentLine.find("*INDENT-ON*", charNum) != std::string::npos+                && isFormattingModeOff)+        {+            isFormattingModeOff = false;+            breakLine();+            formattedLine = currentLine;+            charNum = (int) currentLine.length() - 1;+            continue;+        }+        if (isFormattingModeOff)+        {+            breakLine();+            formattedLine = currentLine;+            charNum = (int) currentLine.length() - 1;+            continue;+        }++        if ((lineIsLineCommentOnly || lineIsCommentOnly)+                && currentLine.find("*INDENT-OFF*", charNum) != std::string::npos)+        {+            isFormattingModeOff = true;+            if (isInLineBreak)			// is true if not the first line+                breakLine();+            formattedLine = currentLine;+            charNum = (int) currentLine.length() - 1;+            continue;+        }++        if (shouldBreakLineAtNextChar)+        {+            if (std::isblank(currentChar) && !lineIsEmpty)+                continue;+            isInLineBreak = true;+            shouldBreakLineAtNextChar = false;+        }++        if (isInExecSQL && !passedSemicolon)+        {+            if (currentChar == ';')+                passedSemicolon = true;+            appendCurrentChar();+            continue;+        }++        if (isInLineComment)+        {+            formatLineCommentBody();+            continue;+        }++        if (isInComment)+        {+            formatCommentBody();+            continue;+        }++        if (isInQuote)+        {+            formatQuoteBody();+            continue;+        }++        // not in quote or comment or line comment++        if (isSequenceReached(ASResource::AS_OPEN_LINE_COMMENT))+        {+            formatLineCommentOpener();+            testForTimeToSplitFormattedLine();+            continue;+        }+        if (isSequenceReached(ASResource::AS_OPEN_COMMENT) || (isGSCStyle() && isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT)))+        {+            formatCommentOpener();+            testForTimeToSplitFormattedLine();+            continue;+        }+        if (currentChar == '"'+                || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)))+        {+            formatQuoteOpener();+            testForTimeToSplitFormattedLine();+            continue;+        }+        // treat these preprocessor statements as a line comment++        if ((currentChar == '#')+                && currentLine.find_first_not_of(" \t") == (size_t) charNum)+        {+            isInContinuedPreProc = currentLine[currentLine.size() - 1] == '\\';+        }++        if (isInPreprocessor)+        {+            appendCurrentChar();+            continue;+        }++        if (isInTemplate && shouldCloseTemplates)+        {+            if (previousNonWSChar == '>' && std::isblank(currentChar) && peekNextChar() == '>')+                continue;+        }++        if (shouldRemoveNextClosingBrace && currentChar == '}')+        {+            currentLine[charNum] = currentChar = ' ';+            shouldRemoveNextClosingBrace = false;+            assert(adjustChecksumIn(-'}'));+            if (isEmptyLine(currentLine))+                continue;+        }++        // add the closing brace deferred by addBracesToStatement() to a multi-line statement+        if (shouldAddClosingBraceAtStatementEnd && !isReparsingCurrentChar)+        {+            if (currentChar == '(' || currentChar == '[')+                ++addedBraceStatementParenDepth;+            else if (currentChar == ')' || currentChar == ']')+                --addedBraceStatementParenDepth;+            else if (currentChar == ';' && addedBraceStatementParenDepth <= 0)+            {+                // keep a line end comment with the statement+                if (isBeforeAnyLineEndComment(charNum) && sourceIterator->hasMoreLines())+                    appendClosingBrace = true;    // append brace as the following line+                else+                {+                    currentLine.insert(charNum + 1, " }");+                    assert(computeChecksumIn("}"));+                }+                shouldAddClosingBraceAtStatementEnd = false;+                addedBraceStatementParenDepth = 0;+            }+        }++        // handle white space - needed to simplify the rest.+        if (std::isblank(currentChar))+        {+            appendCurrentChar();+            continue;+        }++        /* not in MIDDLE of quote or comment or SQL or white-space of any type ... */++        // check if in preprocessor+        // ** isInPreprocessor will be automatically reset at the beginning+        //    of a new line in getnextChar()+        if (currentChar == '#' && !isBraceType(braceTypeStack->back(), BraceType::SINGLE_LINE_TYPE))+        {+            isInPreprocessor = true;+            // check for run-in+            if (!formattedLine.empty() && formattedLine[0] == '{')+            {+                isInLineBreak = true;+                isInBraceRunIn = false;+            }+            processPreprocessor();+        }++        /* not in preprocessor ... */++        if (isImmediatelyPostComment)+        {+            caseHeaderFollowsComments = false;+            isImmediatelyPostComment = false;+            isCharImmediatelyPostComment = true;+        }++        if (isImmediatelyPostLineComment)+        {+            caseHeaderFollowsComments = false;+            isImmediatelyPostLineComment = false;+            isCharImmediatelyPostLineComment = true;+        }++        if (isImmediatelyPostReturn)+        {+            isImmediatelyPostReturn = false;+            isCharImmediatelyPostReturn = true;+        }++        if (isImmediatelyPostThrow)+        {+            isImmediatelyPostThrow = false;+            isCharImmediatelyPostThrow = true;+        }++        if (isImmediatelyPostNewDelete)+        {+            isImmediatelyPostNewDelete = false;+            isCharImmediatelyPostNewDelete = true;+        }++        if (isImmediatelyPostOperator)+        {+            isImmediatelyPostOperator = false;+            isCharImmediatelyPostOperator = true;+        }+        if (isImmediatelyPostTemplate)+        {+            isImmediatelyPostTemplate = false;+            isCharImmediatelyPostTemplate = true;+        }+        if (isImmediatelyPostPointerOrReference)+        {+            isImmediatelyPostPointerOrReference = false;+            isCharImmediatelyPostPointerOrReference = true;+        }++        // reset isImmediatelyPostHeader information+        if (isImmediatelyPostHeader)+        {+            if (!handleImmediatelyPostHeaderSection())+                continue;+        }++        if (passedSemicolon)    // need to break the formattedLine+        {+            if (!handlePassedSemicolonSection())+                continue;+        }++        if (passedColon)+        {+            passedColon = false;+            if (parenStack->back() == 0+                    && !isBeforeAnyComment()+                    && (formattedLine.find_first_not_of(" \t") != std::string::npos))+            {+                shouldReparseCurrentChar = true;+                isInLineBreak = true;+                continue;+            }+        }++        // Check if in template declaration, e.g. foo<bar> or foo<bar,fig>+        if (!isInTemplate && currentChar == '<')+        {+            checkIfTemplateOpener();+        }++        // Check for break return type+        if (methodBreakCharNum.has_value() && (size_t) charNum >= *methodBreakCharNum && methodBreakLineNum == 0)+        {+            if ((size_t) charNum == methodBreakCharNum)+                isInLineBreak = true;+            methodBreakCharNum = std::nullopt;+            methodBreakLineNum = 0;+        }+        // Check for attach return type+        if (methodAttachCharNum.has_value() && (size_t) charNum >= *methodAttachCharNum && methodAttachLineNum == 0)+        {+            handleAttachedReturnTypes();+        }++        // handle parens+        if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))+        {+            handleOpenParens();+        }++        else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))+        {+            handleClosedBracesOrParens();+        }++        // handle braces+        if (currentChar == '{' || currentChar == '}')+        {+            handleBraces();+            continue;+        }++        // #126+        if ( currentChar == '*' && shouldPadOperators &&+                pointerAlignment != PTR_ALIGN_TYPE &&  // SF 557+                peekNextChar() != '=' && // GH 81+                ( currentHeader == &ASResource::AS_IF || currentHeader == &ASResource::AS_WHILE ||+                  currentHeader == &ASResource::AS_DO || currentHeader == &ASResource::AS_FOR)+                && ( previousChar == ')' || std::isalpha(previousChar) )+                && !(previousChar == ')' && previousNonWSChar == ')' && isImmediatelyPostCast())+                && !isOperatorPaddingDisabled() )+        {+            appendSpacePad();+            appendOperator(ASResource::AS_MULT);+            goForward(0);+            appendSpaceAfter();+            continue;+        }++        if ((((previousCommandChar == '{' && isPreviousBraceBlockRelated)+                || ((previousCommandChar == '}'+                     && !isImmediatelyPostEmptyBlock+                     && isPreviousBraceBlockRelated+                     && !isPreviousCharPostComment       // Fixes wrongly appended newlines after '}' immediately after comments+                     && peekNextChar() != ' '+                     && !isBraceType(previousBraceType, BraceType::DEFINITION_TYPE))+                    && !isBraceType(braceTypeStack->back(), BraceType::DEFINITION_TYPE)))+                && isOkToBreakBlock(braceTypeStack->back()))+                // check for array+                || (previousCommandChar == '{'			// added 9/30/2010+                    && isBraceType(braceTypeStack->back(), BraceType::ARRAY_TYPE)+                    && !isBraceType(braceTypeStack->back(), BraceType::SINGLE_LINE_TYPE)+                    && isNonInStatementArray)+                // check for pico one line braces+                || (formattingStyle == STYLE_PICO+                    && (previousCommandChar == '{' && isPreviousBraceBlockRelated)+                    && isBraceType(braceTypeStack->back(), BraceType::COMMAND_TYPE)+                    && isBraceType(braceTypeStack->back(), BraceType::SINGLE_LINE_TYPE)+                    && braceFormatMode == RUN_IN_MODE)+           )+        {+            handleBreakLine();+        }++        // reset block handling flags+        isImmediatelyPostEmptyBlock = false;++        // Objective-C method prefix with no return type+        if (isImmediatelyPostObjCMethodPrefix && currentChar != '(')+        {+            if (shouldPadMethodPrefix || shouldUnPadMethodPrefix)+                padObjCMethodPrefix();+            isImmediatelyPostObjCMethodPrefix = false;+        }++        // look for headers+        bool isPotentialHeader = isCharPotentialHeader(currentLine, charNum);++        if (isPotentialHeader && !isInTemplate && squareBracketCount == 0)+        {+            if (!handlePotentialHeader(newHeader))+                continue;+        }   // (isPotentialHeader && !isInTemplate)++        if (isInLineBreak)          // OK to break line here+        {+            breakLine();+            if (isInVirginLine)		// adjust for the first line+            {+                lineCommentNoBeautify = lineCommentNoIndent;+                lineCommentNoIndent = false;+                if (isImmediatelyPostPreprocessor)+                {+                    isInIndentablePreproc = isIndentablePreprocessor;+                    isIndentablePreprocessor = false;+                }+            }+        }++        if (previousNonWSChar == '}' || currentChar == ';')+        {+            // a brace like 'S{1}' or a lambda body does not end a ?: sequence,+            // foundQuestionMark was restored by the closing brace+            bool keepQuestionMark = foundQuestionMark && currentChar != ';';+            handleEndOfBlock();+            if (keepQuestionMark)+                foundQuestionMark = true;+        }++        if (currentChar == ':'+                && previousChar != ':'         // not part of '::'+                && peekNextChar() != ':')      // not part of '::'+        {+            handleColonSection();+        }++        if (currentChar == '?')+            foundQuestionMark = true;++        if (isPotentialHeader && !isInTemplate)+        {+            handlePotentialHeaderPart2();+            continue;+        }   // (isPotentialHeader &&  !isInTemplate)++        // determine if this is an Objective-C statement++        if (currentChar == '@'+                && isCStyle()+                && (int) currentLine.length() > charNum + 1+                && !std::isblank(currentLine[charNum + 1])+                && isCharPotentialHeader(currentLine, charNum + 1)+                && findKeyword(currentLine, charNum + 1, ASResource::AS_INTERFACE)+                && isBraceType(braceTypeStack->back(), BraceType::NULL_TYPE))+        {+            isInObjCInterface = true;+            std::string name = '@' + ASResource::AS_INTERFACE;+            appendSequence(name);+            goForward(name.length() - 1);+            continue;+        }+        if (currentChar == '@'+                && isCStyle()+                && (int) currentLine.length() > charNum + 1+                && !std::isblank(currentLine[charNum + 1])+                && isCharPotentialHeader(currentLine, charNum + 1)+                && findKeyword(currentLine, charNum + 1, ASResource::AS_SELECTOR))+        {+            isInObjCSelector = true;+            std::string name = '@' + ASResource::AS_SELECTOR;+            appendSequence(name);+            goForward(name.length() - 1);+            continue;+        }+        if ((currentChar == '-' || currentChar == '+')+                && isCStyle()+                && (int) currentLine.find_first_not_of(" \t") == charNum+                && !isInPotentialCalculation+                && !isInObjCMethodDefinition+                && (isBraceType(braceTypeStack->back(), BraceType::NULL_TYPE)+                    || (isBraceType(braceTypeStack->back(), BraceType::EXTERN_TYPE))))+        {+            isInObjCMethodDefinition = true;+            isImmediatelyPostObjCMethodPrefix = true;+            isInObjCParam = false;+            isInObjCInterface = false;+            if (getAlignMethodColon())+                objCColonAlign = findObjCColonAlignment();+            appendCurrentChar();+            continue;+        }++        // determine if this is a potential calculation++        bool isPotentialOperator = isCharPotentialOperator(currentChar);+        newHeader = nullptr;++        // Skip operator detection for git conflict markers+        if (isPotentialOperator && !isGitConflictMarker(currentLine))+        {+            newHeader = findOperator(operators.get());++            handlePotentialOperator(newHeader);+        }++        size_t lastNonWsChar = currentLine.find_last_not_of(" \t", charNum - 1);++        if (lastNonWsChar != std::string::npos && pointerAlignment == PTR_ALIGN_TYPE && !isGSCStyle() && !preserveWhitespace && !isInPreprocessor)+        {+            char lastChar = currentLine[lastNonWsChar];++            //fix SF605, possibly more cases pending+            char nextChar = 0;+            size_t nextCharPos = currentLine.find_first_not_of(" \t", lastNonWsChar+1);+            if (nextCharPos != std::string::npos) nextChar = currentLine[nextCharPos];++            if (lastChar == ',' && nextChar != '+' && nextChar != '-')+            {+                formattedLine = rtrim(formattedLine);+                formattedLine += ' ';+            }++        }++        // process pointers and references+        // check newHeader to eliminate things like '&&' sequence+        if (newHeader != nullptr && !isJavaStyle()+                && (newHeader == &ASResource::AS_MULT+                    || newHeader == &ASResource::AS_BIT_AND+                    || newHeader == &ASResource::AS_BIT_XOR+                    || newHeader == &ASResource::AS_AND)+                && isPointerOrReference())+        {++            if (!isDereferenceOrAddressOf() && !isOperatorPaddingDisabled())+            {+                formatPointerOrReference();+            }+            else+            {+                appendOperator(*newHeader);+                goForward(newHeader->length() - 1);+            }+            isImmediatelyPostPointerOrReference = true;+            continue;+        }++        if ((shouldPadOperators || negationPadMode != NEGATION_PAD_NO_CHANGE) && newHeader != nullptr && !isOperatorPaddingDisabled())+        {+            padOperators(newHeader);+            continue;+        }++        // remove spaces before commas+        if (currentChar == ',')+        {+            const size_t len = formattedLine.length();+            size_t lastText = formattedLine.find_last_not_of(' ');+            if (lastText != std::string::npos && lastText < len - 1)+            {+                formattedLine.resize(lastText + 1);+                int size_diff = len - (lastText + 1);+                spacePadNum -= size_diff;+            }+        }++        // remove whitespace before semicolons+        if (currentChar == ';' && shouldUnPadSemicolon)+        {+            const size_t len = formattedLine.length();+            size_t lastText = formattedLine.find_last_not_of(" \t");+            // npos means the line holds only the indent, so this is an empty+            // statement on a line of its own and the indent must be kept.+            // A preceding '(' or ';' is an empty expression in a 'for' header,+            // e.g. "for ( ; ; )", where the spacing is owned by the paren+            // options and is left unchanged.+            if (lastText != std::string::npos+                    && lastText < len - 1+                    && formattedLine[lastText] != '('+                    && formattedLine[lastText] != ';')+            {+                formattedLine.resize(lastText + 1);+                int size_diff = len - (lastText + 1);+                spacePadNum -= size_diff;+            }+        }++        // pad commas and semi-colons+        if (currentChar == ';'+                || (currentChar == ',' && (shouldPadOperators || shouldPadCommas)))+        {+            char nextChar = ' ';+            if (charNum + 1 < (int) currentLine.length())+                nextChar = currentLine[charNum + 1];+            if (!std::isblank(nextChar)+                    && nextChar != '}'+                    && nextChar != ')'+                    && nextChar != ']'+                    && nextChar != '>'+                    && nextChar != ';'+                    && !isBeforeAnyComment()+               )+            {+                appendCurrentChar();+                appendSpaceAfter();+                continue;+            }+        }++        // pad parens+        if (currentChar == '(' || currentChar == ')')+        {+            handleParens();+            continue;+        }++        //GL31+        bool isDoubleOpenBrackets = isGSCStyle() && currentChar == '[' && peekNextChar() == '[';++        if ((currentChar == '[' || currentChar == ']' ) && (shouldPadBracketsOutside || shouldPadBracketsInside || shouldUnPadBrackets) && !isDoubleOpenBrackets)+        {+            padParensOrBrackets('[', ']', false);+            continue;+        }++        // bypass the entire operator+        if (newHeader != nullptr)+        {+            appendOperator(*newHeader);+            goForward(newHeader->length() - 1);+            continue;+        }++        appendCurrentChar();++    }   // end of while loop  *  end of while loop  *  end of while loop  *  end of while loop++    // return a beautified (i.e. correctly indented) line.++    std::string beautifiedLine;+    size_t readyFormattedLineLength = trim(readyFormattedLine).length();+    bool isInNamespace = isBraceType(braceTypeStack->back(), BraceType::NAMESPACE_TYPE);++    // line-between-members: if a field line was just output, arm blank before the next member.+    // This flag survives intermediate breakLine() calls (which can clear iPrependPostBlock).+    if (lineBetweenMembersDoBlank)+    {+        bool doInsertBlank = true;+        if (!shouldLineBetweenAllMembers)+        {+            // Non-all mode: insert blank only before methods/properties, not before data fields.+            // A data field line ends with ';' but the character before ';' is not ')'.+            // Method prototypes end with ');' and DO get a blank.+            const std::string trimLine = trim(readyFormattedLine);+            if (!trimLine.empty() && trimLine.back() == ';')+            {+                bool prevIsCloseParen = trimLine.size() >= 2+                                        && trimLine[trimLine.size() - 2] == ')';+                if (!prevIsCloseParen)+                    doInsertBlank = false;+            }+        }+        if (doInsertBlank)+            prependEmptyLine = true;++        lineBetweenMembersDoBlank = false;+    }++    // #608 do not prepend a blank line directly inside a preprocessor conditional+    if (prependEmptyLine+            && (isPreviousReadyLinePreprocCondStart+                || isPreprocCondBlockEdge(readyFormattedLine, false)))+        prependEmptyLine = false;++    if (prependEmptyLine		// prepend a blank line before this formatted line+            && readyFormattedLineLength > 0+            && (!previousReadyFormattedLineLength.has_value() || *previousReadyFormattedLineLength > 0))+    {+        isLineReady = true;		// signal a waiting readyFormattedLine+        beautifiedLine = beautify("");+        previousReadyFormattedLineLength = 0;+        // call the enhancer for new empty lines+        enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);+    }+    else		// format the current formatted line+    {+        isLineReady = false;+        runInIndentContinuation = runInIndentChars;+        beautifiedLine = beautify(readyFormattedLine);+        previousReadyFormattedLineLength = readyFormattedLineLength;+        isPreviousReadyLinePreprocCondStart = isPreprocCondBlockEdge(readyFormattedLine, true);+        // the enhancer is not called for no-indent line comments+        if (!lineCommentNoBeautify && !isFormattingModeOff)+            enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);+        runInIndentChars = 0;+        lineCommentNoBeautify = lineCommentNoIndent;+        lineCommentNoIndent = false;+        isInIndentablePreproc = isIndentablePreprocessor;+        isIndentablePreprocessor = false;+        isElseHeaderIndent = elseHeaderFollowsComments;+        isCaseHeaderCommentIndent = caseHeaderFollowsComments;+        objCColonAlignSubsequent = objCColonAlign;+        if (isCharImmediatelyPostNonInStmt)+        {+            isNonInStatementArray = false;+            isCharImmediatelyPostNonInStmt = false;+        }+        isInPreprocessorBeautify = isInPreprocessor;	// used by ASEnhancer+        isInBeautifySQL = isInExecSQL;					// used by ASEnhancer+        // line-between-members=all: after outputting a field line, arm blank before next member.+        // Skip if lineBetweenMembersPassedClassClose: the class scope just closed, meaning+        // this is the last field before '}'. Arming doBlank here would produce a spurious+        // blank before '}'.+        if (needBlankBeforeNextMember && !lineBetweenMembersPassedClassClose)+        {+            lineBetweenMembersDoBlank = true;+            needBlankBeforeNextMember = false;+        }+        else+        {+            needBlankBeforeNextMember = false;+            lineBetweenMembersPassedClassClose = false;+        }+    }++    prependEmptyLine = false;+    assert(computeChecksumOut(beautifiedLine));+    return beautifiedLine; }  /**@@ -2271,7 +2468,7 @@ std::string ASFormatter::nextLine()  */ bool ASFormatter::hasMoreLines() const {-	return !endOfCodeReached;+    return !endOfCodeReached; }  /**@@ -2279,9 +2476,9 @@ bool ASFormatter::hasMoreLines() const  */ bool ASFormatter::isBraceType(BraceType a, BraceType b) const {-	if (a == NULL_TYPE || b == NULL_TYPE)-		return (a == b);-	return ((a & b) == b);+    if (a == BraceType::NULL_TYPE || b == BraceType::NULL_TYPE)+        return (a == b);+    return ((a & b) == b); }  /**@@ -2291,7 +2488,7 @@ bool ASFormatter::isBraceType(BraceType a, BraceType b) const  */ void ASFormatter::setFormattingStyle(FormatStyle style) {-	formattingStyle = style;+    formattingStyle = style; }  /**@@ -2305,7 +2502,7 @@ void ASFormatter::setFormattingStyle(FormatStyle style)  */ void ASFormatter::setAddBracesMode(bool state) {-	shouldAddBraces = state;+    shouldAddBraces = state; }  /**@@ -2318,8 +2515,8 @@ void ASFormatter::setAddBracesMode(bool state)  */ void ASFormatter::setAddOneLineBracesMode(bool state) {-	shouldAddBraces = state ? 1 : 0;-	shouldAddOneLineBraces = state;+    shouldAddBraces = state ? 1 : 0;+    shouldAddOneLineBraces = state; }  /**@@ -2332,7 +2529,12 @@ void ASFormatter::setAddOneLineBracesMode(bool state)  */ void ASFormatter::setRemoveBracesMode(bool state) {-	shouldRemoveBraces = state;+    shouldRemoveBraces = state;+}++void ASFormatter::setRemoveOneLineBracesMode(bool state)+{+    shouldRemoveOneLineBraces = state; }  // retained for compatibility with release 2.06@@ -2340,7 +2542,7 @@ void ASFormatter::setRemoveBracesMode(bool state) // it is referenced only by the old "bracket" options void ASFormatter::setAddBracketsMode(bool state) {-	setAddBracesMode(state);+    setAddBracesMode(state); }  // retained for compatibility with release 2.06@@ -2348,7 +2550,7 @@ void ASFormatter::setAddBracketsMode(bool state) // it is referenced only by the old "bracket" options void ASFormatter::setAddOneLineBracketsMode(bool state) {-	setAddOneLineBracesMode(state);+    setAddOneLineBracesMode(state); }  // retained for compatibility with release 2.06@@ -2356,7 +2558,7 @@ void ASFormatter::setAddOneLineBracketsMode(bool state) // it is referenced only by the old "bracket" options void ASFormatter::setRemoveBracketsMode(bool state) {-	setRemoveBracesMode(state);+    setRemoveBracesMode(state); }  // retained for compatibility with release 2.06@@ -2364,7 +2566,7 @@ void ASFormatter::setRemoveBracketsMode(bool state) // it is referenced only by the old "bracket" options void ASFormatter::setBreakClosingHeaderBracketsMode(bool state) {-	setBreakClosingHeaderBracesMode(state);+    setBreakClosingHeaderBracesMode(state); }  /**@@ -2375,7 +2577,7 @@ void ASFormatter::setBreakClosingHeaderBracketsMode(bool state)  */ void ASFormatter::setBraceFormatMode(BraceMode mode) {-	braceFormatMode = mode;+    braceFormatMode = mode; }  /**@@ -2385,7 +2587,7 @@ void ASFormatter::setBraceFormatMode(BraceMode mode)  */ void ASFormatter::setBreakAfterMode(bool state) {-	shouldBreakLineAfterLogical = state;+    shouldBreakLineAfterLogical = state; }  /**@@ -2399,7 +2601,7 @@ void ASFormatter::setBreakAfterMode(bool state)  */ void ASFormatter::setBreakClosingHeaderBracesMode(bool state) {-	shouldBreakClosingHeaderBraces = state;+    shouldBreakClosingHeaderBraces = state; }  /**@@ -2412,7 +2614,7 @@ void ASFormatter::setBreakClosingHeaderBracesMode(bool state)  */ void ASFormatter::setBreakElseIfsMode(bool state) {-	shouldBreakElseIfs = state;+    shouldBreakElseIfs = state; }  /**@@ -2425,7 +2627,12 @@ void ASFormatter::setBreakElseIfsMode(bool state) */ void ASFormatter::setCommaPaddingMode(bool state) {-	shouldPadCommas = state;+    shouldPadCommas = state;+}++void ASFormatter::setPreserveBraceFormat(bool state)+{+    shouldPreserveBraceFormat = state; }  /**@@ -2435,9 +2642,34 @@ void ASFormatter::setCommaPaddingMode(bool state)  */ void ASFormatter::setMaxCodeLength(int max) {-	maxCodeLength = max;+    maxCodeLength = max;+}+++/**+ * set maximum code length mode+ *+ * @param max         the maximum code length.+ */+void ASFormatter::setMaxCodeLengthMode(MaxCodeLengthMode mode)+{+    maxCodeLengthMode = mode;+}+++/**+ * When true, trailing side comments are excluded from the line-length+ * calculation used by max-code-length, so existing alignment of side+ * comments is preserved instead of triggering a split.+ *+ * @param state         true to ignore side-comment lengths.+ */+void ASFormatter::setIgnoreSideCommentLengths(bool state)+{+    shouldIgnoreSideCommentLengths = state; } + /**  * set operator padding mode.  * options:@@ -2448,7 +2680,7 @@ void ASFormatter::setMaxCodeLength(int max)  */ void ASFormatter::setOperatorPaddingMode(bool state) {-	shouldPadOperators = state;+    shouldPadOperators = state; }  /**@@ -2457,7 +2689,7 @@ void ASFormatter::setOperatorPaddingMode(bool state)  */ void ASFormatter::setNegationPaddingMode(NegationPaddingMode mode) {-	negationPadMode = mode;+    negationPadMode = mode; }  /**@@ -2466,7 +2698,7 @@ void ASFormatter::setNegationPaddingMode(NegationPaddingMode mode)  */ void ASFormatter::setIncludeDirectivePaddingMode(IncludeDirectivePaddingMode mode) {-	includeDirectivePaddingMode = mode;+    includeDirectivePaddingMode = mode; }  /**@@ -2479,7 +2711,7 @@ void ASFormatter::setIncludeDirectivePaddingMode(IncludeDirectivePaddingMode mod  */ void ASFormatter::setParensOutsidePaddingMode(bool state) {-	shouldPadParensOutside = state;+    shouldPadParensOutside = state; }  /**@@ -2492,7 +2724,7 @@ void ASFormatter::setParensOutsidePaddingMode(bool state)  */ void ASFormatter::setParensInsidePaddingMode(bool state) {-	shouldPadParensInside = state;+    shouldPadParensInside = state; }  /**@@ -2505,7 +2737,7 @@ void ASFormatter::setParensInsidePaddingMode(bool state)  */ void ASFormatter::setBracketsOutsidePaddingMode(bool state) {-	shouldPadBracketsOutside = state;+    shouldPadBracketsOutside = state; }  /**@@ -2518,7 +2750,7 @@ void ASFormatter::setBracketsOutsidePaddingMode(bool state)  */ void ASFormatter::setBracketsInsidePaddingMode(bool state) {-	shouldPadBracketsInside = state;+    shouldPadBracketsInside = state; }  /**@@ -2531,7 +2763,7 @@ void ASFormatter::setBracketsInsidePaddingMode(bool state)  */ void ASFormatter::setParensFirstPaddingMode(bool state) {-	shouldPadFirstParen = state;+    shouldPadFirstParen = state; }  /**@@ -2544,7 +2776,7 @@ void ASFormatter::setParensFirstPaddingMode(bool state)  */ void ASFormatter::setEmptyParensPaddingMode(bool state) {-	shouldPadEmptyParens = state;+    shouldPadEmptyParens = state; }  /**@@ -2557,7 +2789,7 @@ void ASFormatter::setEmptyParensPaddingMode(bool state)  */ void ASFormatter::setParensHeaderPaddingMode(bool state) {-	shouldPadHeader = state;+    shouldPadHeader = state; }  /**@@ -2570,7 +2802,7 @@ void ASFormatter::setParensHeaderPaddingMode(bool state)  */ void ASFormatter::setParensUnPaddingMode(bool state) {-	shouldUnPadParens = state;+    shouldUnPadParens = state; }  /**@@ -2583,7 +2815,20 @@ void ASFormatter::setParensUnPaddingMode(bool state)  */ void ASFormatter::setBracketsUnPaddingMode(bool state) {-	shouldUnPadBrackets = state;+    shouldUnPadBrackets = state;+}++/**+ * set semicolon unpadding mode.+ * options:+ *    true     whitespace preceding a semicolon will be removed.+ *    false    whitespace preceding a semicolon will not be changed.+ *+ * @param state         the padding mode.+ */+void ASFormatter::setSemicolonUnPaddingMode(bool state)+{+    shouldUnPadSemicolon = state; }  /**@@ -2594,7 +2839,7 @@ void ASFormatter::setBracketsUnPaddingMode(bool state) */ void ASFormatter::setPreprocBlockIndent(bool state) {-	shouldIndentPreprocBlock = state;+    shouldIndentPreprocBlock = state; }  /**@@ -2607,7 +2852,7 @@ void ASFormatter::setPreprocBlockIndent(bool state)  */ void ASFormatter::setStripCommentPrefix(bool state) {-	shouldStripCommentPrefix = state;+    shouldStripCommentPrefix = state; }  /**@@ -2620,7 +2865,7 @@ void ASFormatter::setStripCommentPrefix(bool state)  */ void ASFormatter::setMethodPrefixPaddingMode(bool state) {-	shouldPadMethodPrefix = state;+    shouldPadMethodPrefix = state; }  /**@@ -2633,31 +2878,31 @@ void ASFormatter::setMethodPrefixPaddingMode(bool state)  */ void ASFormatter::setMethodPrefixUnPaddingMode(bool state) {-	shouldUnPadMethodPrefix = state;+    shouldUnPadMethodPrefix = state; }  // set objective-c '-' or '+' return type padding mode. void ASFormatter::setReturnTypePaddingMode(bool state) {-	shouldPadReturnType = state;+    shouldPadReturnType = state; }  // set objective-c '-' or '+' return type unpadding mode. void ASFormatter::setReturnTypeUnPaddingMode(bool state) {-	shouldUnPadReturnType = state;+    shouldUnPadReturnType = state; }  // set objective-c method parameter type padding mode. void ASFormatter::setParamTypePaddingMode(bool state) {-	shouldPadParamType = state;+    shouldPadParamType = state; }  // set objective-c method parameter type unpadding mode. void ASFormatter::setParamTypeUnPaddingMode(bool state) {-	shouldUnPadParamType = state;+    shouldUnPadParamType = state; }  /**@@ -2667,8 +2912,8 @@ void ASFormatter::setParamTypeUnPaddingMode(bool state)  */ void ASFormatter::setObjCColonPaddingMode(ObjCColonPad mode) {-	shouldPadMethodColon = true;-	objCColonPadMode = mode;+    shouldPadMethodColon = true;+    objCColonPadMode = mode; }  /**@@ -2678,7 +2923,7 @@ void ASFormatter::setObjCColonPaddingMode(ObjCColonPad mode)  */ void ASFormatter::setAttachClosingBraceMode(bool state) {-	attachClosingBraceMode = state;+    attachClosingBraceMode = state; }  /**@@ -2688,7 +2933,7 @@ void ASFormatter::setAttachClosingBraceMode(bool state)  */ void ASFormatter::setAttachClass(bool state) {-	shouldAttachClass = state;+    shouldAttachClass = state; }  /**@@ -2698,7 +2943,7 @@ void ASFormatter::setAttachClass(bool state)  */ void ASFormatter::setAttachExternC(bool state) {-	shouldAttachExternC = state;+    shouldAttachExternC = state; }  /**@@ -2708,7 +2953,7 @@ void ASFormatter::setAttachExternC(bool state)  */ void ASFormatter::setAttachNamespace(bool state) {-	shouldAttachNamespace = state;+    shouldAttachNamespace = state; }  /**@@ -2718,12 +2963,12 @@ void ASFormatter::setAttachNamespace(bool state)  */ void ASFormatter::setAttachInline(bool state) {-	shouldAttachInline = state;+    shouldAttachInline = state; }  void ASFormatter::setAttachClosingWhile(bool state) {-	shouldAttachClosingWhile = state;+    shouldAttachClosingWhile = state; }  /**@@ -2733,7 +2978,7 @@ void ASFormatter::setAttachClosingWhile(bool state)  */ void ASFormatter::setBreakOneLineBlocksMode(bool state) {-	shouldBreakOneLineBlocks = state;+    shouldBreakOneLineBlocks = state; }  /**@@ -2741,7 +2986,7 @@ void ASFormatter::setBreakOneLineBlocksMode(bool state) */ void ASFormatter::setBreakOneLineHeadersMode(bool state) {-	shouldBreakOneLineHeaders = state;+    shouldBreakOneLineHeaders = state; }  /**@@ -2751,12 +2996,12 @@ void ASFormatter::setBreakOneLineHeadersMode(bool state) */ void ASFormatter::setBreakOneLineStatementsMode(bool state) {-	shouldBreakOneLineStatements = state;+    shouldBreakOneLineStatements = state; }  void ASFormatter::setCloseTemplatesMode(bool state) {-	shouldCloseTemplates = state;+    shouldCloseTemplates = state; }  /**@@ -2766,7 +3011,7 @@ void ASFormatter::setCloseTemplatesMode(bool state)  */ void ASFormatter::setTabSpaceConversionMode(bool state) {-	shouldConvertTabs = state;+    shouldConvertTabs = state; }  /**@@ -2776,7 +3021,7 @@ void ASFormatter::setTabSpaceConversionMode(bool state)  */ void ASFormatter::setIndentCol1CommentsMode(bool state) {-	shouldIndentCol1Comments = state;+    shouldIndentCol1Comments = state; }  /**@@ -2786,7 +3031,17 @@ void ASFormatter::setIndentCol1CommentsMode(bool state)  */ void ASFormatter::setLineEndFormat(LineEndFormat fmt) {-	lineEnd = fmt;+    lineEnd = fmt;+}++/**+ * set option to end the output with exactly one line end.+ *+ * @param state        true = enforce, false = keep the input file end.+ */+void ASFormatter::setEOFNewlineMode(bool state)+{+    shouldEndWithSingleNewline = state; }  /**@@ -2796,7 +3051,7 @@ void ASFormatter::setLineEndFormat(LineEndFormat fmt)  */ void ASFormatter::setBreakBlocksMode(bool state) {-	shouldBreakBlocks = state;+    shouldBreakBlocks = state; }  /**@@ -2806,9 +3061,32 @@ void ASFormatter::setBreakBlocksMode(bool state)  */ void ASFormatter::setBreakClosingHeaderBlocksMode(bool state) {-	shouldBreakClosingHeaderBlocks = state;+    shouldBreakClosingHeaderBlocks = state;+}++/**+ * set option to insert an empty line between class members (methods/properties).+ *+ * @param state        true = insert, false = don't insert.+ */+void ASFormatter::setLineBetweenMembersMode(bool state)+{+    shouldLineBetweenMembers = state;+}++/**+ * set option to insert an empty line between all class members including fields.+ *+ * @param state        true = insert, false = don't insert.+ */+void ASFormatter::setLineBetweenAllMembersMode(bool state)+{+    shouldLineBetweenAllMembers = state;+    if (state)+        shouldLineBetweenMembers = true; } + /**  * set option to delete empty lines.  *@@ -2816,32 +3094,32 @@ void ASFormatter::setBreakClosingHeaderBlocksMode(bool state)  */ void ASFormatter::setDeleteEmptyLinesMode(bool state) {-	shouldDeleteEmptyLines = state;+    shouldDeleteEmptyLines = state; }  void ASFormatter::setBreakReturnType(bool state) {-	shouldBreakReturnType = state;+    shouldBreakReturnType = state; }  void ASFormatter::setBreakReturnTypeDecl(bool state) {-	shouldBreakReturnTypeDecl = state;+    shouldBreakReturnTypeDecl = state; }  void ASFormatter::setAttachReturnType(bool state) {-	shouldAttachReturnType = state;+    shouldAttachReturnType = state; }  void ASFormatter::setAttachReturnTypeDecl(bool state) {-	shouldAttachReturnTypeDecl = state;+    shouldAttachReturnTypeDecl = state; }  void ASFormatter::setSqueezeEmptyLinesNumber(int num) {-	squeezeEmptyLineNum = num;+    squeezeEmptyLineNum = num; }  @@ -2852,12 +3130,12 @@ void ASFormatter::setSqueezeEmptyLinesNumber(int num)  */ void ASFormatter::setPointerAlignment(PointerAlign alignment) {-	pointerAlignment = alignment;+    pointerAlignment = alignment; }  void ASFormatter::setReferenceAlignment(ReferenceAlign alignment) {-	referenceAlignment = alignment;+    referenceAlignment = alignment; }  /**@@ -2867,8 +3145,8 @@ void ASFormatter::setReferenceAlignment(ReferenceAlign alignment)  */ void ASFormatter::goForward(int i) {-	while (--i >= 0)-		getNextChar();+    while (--i >= 0)+        getNextChar(); }  /**@@ -2878,15 +3156,15 @@ void ASFormatter::goForward(int i)  */ char ASFormatter::peekNextChar() const {-	char ch = ' ';-	size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);+    char ch = ' ';+    size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1); -	if (peekNum == std::string::npos)-		return ch;+    if (peekNum == std::string::npos)+        return ch; -	ch = currentLine[peekNum];+    ch = currentLine[peekNum]; -	return ch;+    return ch; }  /**@@ -2896,15 +3174,15 @@ char ASFormatter::peekNextChar() const  */ bool ASFormatter::isBeforeComment() const {-	bool foundComment = false;-	size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);+    bool foundComment = false;+    size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1); -	if (peekNum == std::string::npos)-		return foundComment;+    if (peekNum == std::string::npos)+        return foundComment; -	foundComment = (currentLine.compare(peekNum, 2, "/*") == 0);+    foundComment = (currentLine.compare(peekNum, 2, "/*") == 0); -	return foundComment;+    return foundComment; }  /**@@ -2914,16 +3192,16 @@ bool ASFormatter::isBeforeComment() const  */ bool ASFormatter::isBeforeAnyComment() const {-	bool foundComment = false;-	size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);+    bool foundComment = false;+    size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1); -	if (peekNum == std::string::npos)-		return foundComment;+    if (peekNum == std::string::npos)+        return foundComment; -	foundComment = (currentLine.compare(peekNum, 2, "/*") == 0-	                || currentLine.compare(peekNum, 2, "//") == 0);+    foundComment = (currentLine.compare(peekNum, 2, "/*") == 0+                    || currentLine.compare(peekNum, 2, "//") == 0); -	return foundComment;+    return foundComment; }  /**@@ -2934,26 +3212,26 @@ bool ASFormatter::isBeforeAnyComment() const  */ bool ASFormatter::isBeforeAnyLineEndComment(int startPos) const {-	bool foundLineEndComment = false;-	size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);--	if (peekNum != std::string::npos)-	{-		if (currentLine.compare(peekNum, 2, "//") == 0)-			foundLineEndComment = true;-		else if (currentLine.compare(peekNum, 2, "/*") == 0)-		{-			// comment must be closed on this line with nothing after it-			size_t endNum = currentLine.find("*/", peekNum + 2);-			if (endNum != std::string::npos)-			{-				size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);-				if (nextChar == std::string::npos)-					foundLineEndComment = true;-			}-		}-	}-	return foundLineEndComment;+    bool foundLineEndComment = false;+    size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);++    if (peekNum != std::string::npos)+    {+        if (currentLine.compare(peekNum, 2, "//") == 0)+            foundLineEndComment = true;+        else if (currentLine.compare(peekNum, 2, "/*") == 0)+        {+            // comment must be closed on this line with nothing after it+            size_t endNum = currentLine.find("*/", peekNum + 2);+            if (endNum != std::string::npos)+            {+                size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);+                if (nextChar == std::string::npos)+                    foundLineEndComment = true;+            }+        }+    }+    return foundLineEndComment; }  /**@@ -2963,25 +3241,25 @@ bool ASFormatter::isBeforeAnyLineEndComment(int startPos) const  */ bool ASFormatter::isBeforeMultipleLineEndComments(int startPos) const {-	bool foundMultipleLineEndComment = false;-	size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);+    bool foundMultipleLineEndComment = false;+    size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1); -	if (peekNum != std::string::npos)-	{-		if (currentLine.compare(peekNum, 2, "/*") == 0)-		{-			// comment must be closed on this line with nothing after it-			size_t endNum = currentLine.find("*/", peekNum + 2);-			if (endNum != std::string::npos)-			{-				size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);-				if (nextChar != std::string::npos-				        && currentLine.compare(nextChar, 2, "//") == 0)-					foundMultipleLineEndComment = true;-			}-		}-	}-	return foundMultipleLineEndComment;+    if (peekNum != std::string::npos)+    {+        if (currentLine.compare(peekNum, 2, "/*") == 0)+        {+            // comment must be closed on this line with nothing after it+            size_t endNum = currentLine.find("*/", peekNum + 2);+            if (endNum != std::string::npos)+            {+                size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);+                if (nextChar != std::string::npos+                        && currentLine.compare(nextChar, 2, "//") == 0)+                    foundMultipleLineEndComment = true;+            }+        }+    }+    return foundMultipleLineEndComment; }  /**@@ -2992,34 +3270,34 @@ bool ASFormatter::isBeforeMultipleLineEndComments(int startPos) const  */ bool ASFormatter::getNextChar() {-	isInLineBreak = false;-	previousChar = currentChar;+    isInLineBreak = false;+    previousChar = currentChar; -	if (!std::isblank(currentChar))-	{-		previousNonWSChar = currentChar;-		if (!isInComment && !isInLineComment && !isInQuote-		        && !isImmediatelyPostComment-		        && !isImmediatelyPostLineComment-		        && !isInPreprocessor-		        && !isSequenceReached(ASResource::AS_OPEN_COMMENT)-		        && !(isGSCStyle() && isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT))-		        && !isSequenceReached(ASResource::AS_OPEN_LINE_COMMENT))-			previousCommandChar = currentChar;-	}+    if (!std::isblank(currentChar))+    {+        previousNonWSChar = currentChar;+        if (!isInComment && !isInLineComment && !isInQuote+                && !isImmediatelyPostComment+                && !isImmediatelyPostLineComment+                && !isInPreprocessor+                && !isSequenceReached(ASResource::AS_OPEN_COMMENT)+                && !(isGSCStyle() && isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT))+                && !isSequenceReached(ASResource::AS_OPEN_LINE_COMMENT))+            previousCommandChar = currentChar;+    } -	if (charNum + 1 < (int) currentLine.length()-	        && (!std::isblank(peekNextChar()) || isInComment || isInLineComment))-	{-		currentChar = currentLine[++charNum];-		if (currentChar == '\t' && shouldConvertTabs)-			convertTabToSpaces();+    if (charNum + 1 < (int) currentLine.length()+            && (!std::isblank(peekNextChar()) || isInComment || isInLineComment))+    {+        currentChar = currentLine[++charNum];+        if (currentChar == '\t' && shouldConvertTabs)+            convertTabToSpaces(); -		return true;-	}+        return true;+    } -	// end of line has been reached-	return getNextLine();+    // end of line has been reached+    return getNextLine(); }  /**@@ -3030,109 +3308,121 @@ bool ASFormatter::getNextChar()  */ bool ASFormatter::getNextLine(bool emptyLineWasDeleted /*false*/) {-	if (!sourceIterator->hasMoreLines())-	{-		endOfCodeReached = true;-		return false;-	}-	if (appendOpeningBrace)-		currentLine = "{";		// append brace that was removed from the previous line-	else-	{-		currentLine = sourceIterator->nextLine(emptyLineWasDeleted);-		assert(computeChecksumIn(currentLine));-	}--	// reset variables for new line-	inLineNumber++;-	if (endOfAsmReached)-		endOfAsmReached = isInAsmBlock = isInAsm = false;-	shouldKeepLineUnbroken = false;-	isInCommentStartLine = false;-	isInCase = false;-	isInAsmOneLine = false;-	isHeaderInMultiStatementLine = false;-	isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;-	haveLineContinuationChar = false;-	isImmediatelyPostEmptyLine = lineIsEmpty;-	previousChar = ' ';--	if (currentLine.empty())-	{-		//#574 avoid deletion of empty lines after continuation-		if (!isInComment && previousNonWSChar == '\\')-		{-			isInPreprocessor = true;-			return false;-		}--		isInContinuedPreProc = false;-		currentLine = std::string(" ");        // a null is inserted if this is not done-	}--	if (methodBreakLineNum > 0)-		--methodBreakLineNum;-	if (methodAttachLineNum > 0)-		--methodAttachLineNum;--	// unless reading in the first line of the file, break a new line.-	if (!isVirgin)-		isInLineBreak = true;-	else-		isVirgin = false;--	if (isImmediatelyPostNonInStmt)-	{-		isCharImmediatelyPostNonInStmt = true;-		isImmediatelyPostNonInStmt = false;-	}--	// check if is in preprocessor before line trimming-	// a blank line after a \ will remove the flag-	isImmediatelyPostPreprocessor = isInPreprocessor;--	if (!isInComment-	        && (previousNonWSChar != '\\'-	            || isEmptyLine(currentLine)))-	{-		isInPreprocessor = false;-		isInPreprocessorDefineDef = false;-	}--	if (passedSemicolon)-		isInExecSQL = false;-	initNewLine();--	currentChar = currentLine[charNum];-	if (isInBraceRunIn && previousNonWSChar == '{' && !isInComment)-		isInLineBreak = false;-	isInBraceRunIn = false;--	if (currentChar == '\t' && shouldConvertTabs)-		convertTabToSpaces();--	// check for an empty line inside a command brace.-	// if yes then read the next line (calls getNextLine recursively).-	// must be after initNewLine.-	if (shouldDeleteEmptyLines-	        && lineIsEmpty-	        && isBraceType((*braceTypeStack)[braceTypeStack->size() - 1], COMMAND_TYPE))-	{-		if (!shouldBreakBlocks || previousNonWSChar == '{' || !commentAndHeaderFollows())-		{-			isInPreprocessor = isImmediatelyPostPreprocessor;		// restore-			lineIsEmpty = false;-			return getNextLine(true);-		}-	}--	if ( ++squeezeEmptyLineCount > squeezeEmptyLineNum && lineIsEmpty && isImmediatelyPostEmptyLine)-	{-		isInPreprocessor = isImmediatelyPostPreprocessor;		// restore-		return getNextLine(true);-	}--	return true;+    if (!sourceIterator->hasMoreLines())+    {+        endOfCodeReached = true;+        return false;+    }+    if (appendOpeningBrace)+        currentLine = "{";		// append brace that was removed from the previous line+    else if (appendClosingBrace)+    {+        currentLine = "}";		// append brace added to the previous multi-line statement+        appendClosingBrace = false;+        assert(computeChecksumIn(currentLine));+    }+    else+    {+        currentLine = sourceIterator->nextLine(emptyLineWasDeleted);+        assert(computeChecksumIn(currentLine));+    }++    // snapshot paren depth before this line's chars are parsed: if non-zero,+    // this source line begins inside a paren that opened on a previous line,+    // i.e. it is a continuation. Used by getEffectiveLineLength() so the+    // first continuation line predicts the indent ASBeautifier will apply.+    isLineContinuation = !parenStack->empty() && parenStack->back() > 0;++    // reset variables for new line+    inLineNumber++;+    if (endOfAsmReached)+        endOfAsmReached = isInAsmBlock = isInAsm = false;+    shouldKeepLineUnbroken = false;+    isInCommentStartLine = false;+    isInCase = false;+    isInAsmOneLine = false;+    isHeaderInMultiStatementLine = false;+    isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;+    haveLineContinuationChar = false;+    isImmediatelyPostEmptyLine = lineIsEmpty;+    previousChar = ' ';++    if (currentLine.empty())+    {+        //#574 avoid deletion of empty lines after continuation+        if (!isInComment && previousNonWSChar == '\\')+        {+            isInPreprocessor = true;+            return false;+        }++        isInContinuedPreProc = false;+        currentLine = std::string(" ");        // a null is inserted if this is not done+    }++    if (methodBreakLineNum > 0)+        --methodBreakLineNum;+    if (methodAttachLineNum > 0)+        --methodAttachLineNum;++    // unless reading in the first line of the file, break a new line.+    if (!isVirgin)+        isInLineBreak = true;+    else+        isVirgin = false;++    if (isImmediatelyPostNonInStmt)+    {+        isCharImmediatelyPostNonInStmt = true;+        isImmediatelyPostNonInStmt = false;+    }++    // check if is in preprocessor before line trimming+    // a blank line after a \ will remove the flag+    isImmediatelyPostPreprocessor = isInPreprocessor;++    if (!isInComment+            && (previousNonWSChar != '\\'+                || isEmptyLine(currentLine)))+    {+        isInPreprocessor = false;+        isInPreprocessorDefineDef = false;+    }++    if (passedSemicolon)+        isInExecSQL = false;+    initNewLine();++    currentChar = currentLine[charNum];+    if (isInBraceRunIn && previousNonWSChar == '{' && !isInComment)+        isInLineBreak = false;+    isInBraceRunIn = false;++    if (currentChar == '\t' && shouldConvertTabs)+        convertTabToSpaces();++    // check for an empty line inside a command brace.+    // if yes then read the next line (calls getNextLine recursively).+    // must be after initNewLine.+    if (shouldDeleteEmptyLines+            && lineIsEmpty+            && isBraceType((*braceTypeStack)[braceTypeStack->size() - 1], BraceType::COMMAND_TYPE))+    {+        if (!shouldBreakBlocks || previousNonWSChar == '{' || !commentAndHeaderFollows())+        {+            isInPreprocessor = isImmediatelyPostPreprocessor;		// restore+            lineIsEmpty = false;+            return getNextLine(true);+        }+    }++    if ( ++squeezeEmptyLineCount > squeezeEmptyLineNum && lineIsEmpty && isImmediatelyPostEmptyLine)+    {+        isInPreprocessor = isImmediatelyPostPreprocessor;		// restore+        return getNextLine(true);+    }++    return true; }  /**@@ -3141,123 +3431,128 @@ bool ASFormatter::getNextLine(bool emptyLineWasDeleted /*false*/)  */ void ASFormatter::initNewLine() {-	size_t len = currentLine.length();-	size_t tabSize = getTabLength();-	charNum = 0;--	// don't trim these-	if (isInQuoteContinuation-	        || (isInPreprocessor && !getPreprocDefineIndent()))-		return;--	// SQL continuation lines must be adjusted so the leading spaces-	// is equivalent to the opening EXEC SQL-	if (isInExecSQL)-	{-		// replace leading tabs with spaces-		// so that continuation indent will be spaces-		size_t tabCount_ = 0;-		size_t i;-		for (i = 0; i < currentLine.length(); i++)-		{-			if (!std::isblank(currentLine[i]))		// stop at first text-				break;-			if (currentLine[i] == '\t')-			{-				size_t numSpaces = tabSize - ((tabCount_ + i) % tabSize);-				currentLine.replace(i, 1, numSpaces, ' ');-				tabCount_++;-				i += tabSize - 1;-			}-		}-		// this will correct the format if EXEC SQL is not a hanging indent-		trimContinuationLine();-		return;-	}--	// comment continuation lines must be adjusted so the leading spaces-	// is equivalent to the opening comment-	if (isInComment)-	{-		if (noTrimCommentContinuation)-			leadingSpaces = tabIncrementIn = 0;-		trimContinuationLine();-		return;-	}--	// compute leading spaces-	isImmediatelyPostCommentOnly = lineIsLineCommentOnly || lineEndsInCommentOnly;-	lineIsCommentOnly = false;-	lineIsLineCommentOnly = false;-	lineEndsInCommentOnly = false;-	doesLineStartComment = false;-	currentLineBeginsWithBrace = false;-	lineIsEmpty = false;-	currentLineFirstBraceNum = std::string::npos;-	tabIncrementIn = 0;--	// bypass whitespace at the start of a line-	// preprocessor tabs are replaced later in the program-	for (charNum = 0; std::isblank(currentLine[charNum]) && charNum + 1 < (int) len; charNum++)-	{-		if (currentLine[charNum] == '\t'-		        && (!isInPreprocessor || isInPreprocessorDefineDef))-			tabIncrementIn += tabSize - 1 - ((tabIncrementIn + charNum) % tabSize);-	}-	leadingSpaces = charNum + tabIncrementIn;--	if (isSequenceReached(ASResource::AS_OPEN_COMMENT) || (isGSCStyle() && isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT)))-	{-		doesLineStartComment = true;-		if ((int) currentLine.length() > charNum + 2-		        && currentLine.find("*/", charNum + 2) != std::string::npos)-			lineIsCommentOnly = true;-	}-	else if (isSequenceReached(ASResource::AS_OPEN_LINE_COMMENT))-	{-		lineIsLineCommentOnly = true;-	}-	else if (isSequenceReached("{"))-	{-		currentLineBeginsWithBrace = true;-		currentLineFirstBraceNum = charNum;-		size_t firstText = currentLine.find_first_not_of(" \t", charNum + 1);-		if (firstText != std::string::npos)-		{-			if (currentLine.compare(firstText, 2, "//") == 0)-				lineIsLineCommentOnly = true;-			else if (currentLine.compare(firstText, 2, "/*") == 0-			         || isExecSQL(currentLine, firstText))-			{-				// get the extra adjustment-				size_t j;-				for (j = charNum + 1; j < firstText && std::isblank(currentLine[j]); j++)-				{-					if (currentLine[j] == '\t')-						tabIncrementIn += tabSize - 1 - ((tabIncrementIn + j) % tabSize);-				}-				leadingSpaces = j + tabIncrementIn;-				if (currentLine.compare(firstText, 2, "/*") == 0)-					doesLineStartComment = true;-			}-		}-	}-	else if (std::isblank(currentLine[charNum]) && !(charNum + 1 < (int) currentLine.length()))-	{-		lineIsEmpty = true;-		if (!isImmediatelyPostEmptyLine  )-		{-			squeezeEmptyLineCount = 0;-		}-	}--	// do not trim indented preprocessor define (except for comment continuation lines)-	if (isInPreprocessor)-	{-		if (!doesLineStartComment)-			leadingSpaces = 0;-		charNum = 0;-	}+    size_t len = currentLine.length();+    size_t tabSize = getTabLength();+    charNum = 0;++    if (shouldPreserveIndent)+        preserveIndentLeading = "";++    // don't trim these+    if (isInQuoteContinuation+            || (isInPreprocessor && !getPreprocDefineIndent()))+        return;++    // SQL continuation lines must be adjusted so the leading spaces+    // is equivalent to the opening EXEC SQL+    if (isInExecSQL)+    {+        // replace leading tabs with spaces+        // so that continuation indent will be spaces+        size_t tabCount_ = 0;+        size_t i;+        for (i = 0; i < currentLine.length(); i++)+        {+            if (!std::isblank(currentLine[i]))		// stop at first text+                break;+            if (currentLine[i] == '\t')+            {+                size_t numSpaces = tabSize - ((tabCount_ + i) % tabSize);+                currentLine.replace(i, 1, numSpaces, ' ');+                tabCount_++;+                i += tabSize - 1;+            }+        }+        // this will correct the format if EXEC SQL is not a hanging indent+        trimContinuationLine();+        return;+    }++    // comment continuation lines must be adjusted so the leading spaces+    // is equivalent to the opening comment+    if (isInComment)+    {+        if (noTrimCommentContinuation)+            leadingSpaces = tabIncrementIn = 0;+        trimContinuationLine();+        return;+    }++    // compute leading spaces+    isImmediatelyPostCommentOnly = lineIsLineCommentOnly || lineEndsInCommentOnly;+    lineIsCommentOnly = false;+    lineIsLineCommentOnly = false;+    lineEndsInCommentOnly = false;+    doesLineStartComment = false;+    currentLineBeginsWithBrace = false;+    lineIsEmpty = false;+    currentLineFirstBraceNum = std::nullopt;+    tabIncrementIn = 0;++    // bypass whitespace at the start of a line+    // preprocessor tabs are replaced later in the program+    for (charNum = 0; std::isblank(currentLine[charNum]) && charNum + 1 < (int) len; charNum++)+    {+        if (currentLine[charNum] == '\t'+                && (!isInPreprocessor || isInPreprocessorDefineDef))+            tabIncrementIn += tabSize - 1 - ((tabIncrementIn + charNum) % tabSize);+    }+    leadingSpaces = charNum + tabIncrementIn;+    if (shouldPreserveIndent)+        preserveIndentLeading = currentLine.substr(0, charNum);++    if (isSequenceReached(ASResource::AS_OPEN_COMMENT) || (isGSCStyle() && isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT)))+    {+        doesLineStartComment = true;+        if ((int) currentLine.length() > charNum + 2+                && currentLine.find("*/", charNum + 2) != std::string::npos)+            lineIsCommentOnly = true;+    }+    else if (isSequenceReached(ASResource::AS_OPEN_LINE_COMMENT))+    {+        lineIsLineCommentOnly = true;+    }+    else if (isSequenceReached("{"))+    {+        currentLineBeginsWithBrace = true;+        currentLineFirstBraceNum = charNum;+        size_t firstText = currentLine.find_first_not_of(" \t", charNum + 1);+        if (firstText != std::string::npos)+        {+            if (currentLine.compare(firstText, 2, "//") == 0)+                lineIsLineCommentOnly = true;+            else if (currentLine.compare(firstText, 2, "/*") == 0+                     || isExecSQL(currentLine, firstText))+            {+                // get the extra adjustment+                size_t j;+                for (j = charNum + 1; j < firstText && std::isblank(currentLine[j]); j++)+                {+                    if (currentLine[j] == '\t')+                        tabIncrementIn += tabSize - 1 - ((tabIncrementIn + j) % tabSize);+                }+                leadingSpaces = j + tabIncrementIn;+                if (currentLine.compare(firstText, 2, "/*") == 0)+                    doesLineStartComment = true;+            }+        }+    }+    else if (std::isblank(currentLine[charNum]) && !(charNum + 1 < (int) currentLine.length()))+    {+        lineIsEmpty = true;+        if (!isImmediatelyPostEmptyLine  )+        {+            squeezeEmptyLineCount = 0;+        }+    }++    // do not trim indented preprocessor define (except for comment continuation lines)+    if (isInPreprocessor)+    {+        if (!doesLineStartComment)+            leadingSpaces = 0;+        charNum = 0;+    } }  /**@@ -3269,19 +3564,19 @@ void ASFormatter::initNewLine()  */ void ASFormatter::appendChar(char ch, bool canBreakLine) {-	if (canBreakLine && isInLineBreak)-		breakLine();+    if (canBreakLine && isInLineBreak)+        breakLine(); -	formattedLine.append(1, ch);-	isImmediatelyPostCommentOnly = false;-	if (maxCodeLength != std::string::npos)-	{-		// These compares reduce the frequency of function calls.-		if (isOkToSplitFormattedLine())-			updateFormattedLineSplitPoints(ch);-		if (formattedLine.length() > maxCodeLength)-			testForTimeToSplitFormattedLine();-	}+    formattedLine.append(1, ch);+    isImmediatelyPostCommentOnly = false;+    if (maxCodeLength != std::string::npos)+    {+        // These compares reduce the frequency of function calls.+        if (isOkToSplitFormattedLine())+            updateFormattedLineSplitPoints(ch);+        if (getEffectiveLineLength() > maxCodeLength)+            testForTimeToSplitFormattedLine();+    } }  /**@@ -3294,11 +3589,11 @@ void ASFormatter::appendChar(char ch, bool canBreakLine)  */ void ASFormatter::appendSequence(std::string_view sequence, bool canBreakLine) {-	if (canBreakLine && isInLineBreak)-		breakLine();-	formattedLine.append(sequence);-	if (formattedLine.length() > maxCodeLength)-		testForTimeToSplitFormattedLine();+    if (canBreakLine && isInLineBreak)+        breakLine();+    formattedLine.append(sequence);+    if (getEffectiveLineLength() > maxCodeLength)+        testForTimeToSplitFormattedLine(); }  /**@@ -3310,17 +3605,17 @@ void ASFormatter::appendSequence(std::string_view sequence, bool canBreakLine)  */ void ASFormatter::appendOperator(std::string_view sequence, bool canBreakLine) {-	if (canBreakLine && isInLineBreak)-		breakLine();-	formattedLine.append(sequence);-	if (maxCodeLength != std::string::npos)-	{-		// These compares reduce the frequency of function calls.-		if (isOkToSplitFormattedLine())-			updateFormattedLineSplitPointsOperator(sequence);-		if (formattedLine.length() > maxCodeLength)-			testForTimeToSplitFormattedLine();-	}+    if (canBreakLine && isInLineBreak)+        breakLine();+    formattedLine.append(sequence);+    if (maxCodeLength != std::string::npos)+    {+        // These compares reduce the frequency of function calls.+        if (isOkToSplitFormattedLine())+            updateFormattedLineSplitPointsOperator(sequence);+        if (getEffectiveLineLength() > maxCodeLength)+            testForTimeToSplitFormattedLine();+    } }  /**@@ -3329,20 +3624,20 @@ void ASFormatter::appendOperator(std::string_view sequence, bool canBreakLine)  */ void ASFormatter::appendSpacePad() {-	int len = formattedLine.length();-	if (len > 0 && !std::isblank(formattedLine[len - 1]))-	{-		formattedLine.append(1, ' ');-		spacePadNum++;-		if (maxCodeLength != std::string::npos)-		{-			// These compares reduce the frequency of function calls.-			if (isOkToSplitFormattedLine())-				updateFormattedLineSplitPoints(' ');-			if (formattedLine.length() > maxCodeLength)-				testForTimeToSplitFormattedLine();-		}-	}+    int len = formattedLine.length();+    if (len > 0 && !std::isblank(formattedLine[len - 1]))+    {+        formattedLine.append(1, ' ');+        spacePadNum++;+        if (maxCodeLength != std::string::npos)+        {+            // These compares reduce the frequency of function calls.+            if (isOkToSplitFormattedLine())+                updateFormattedLineSplitPoints(' ');+            if (getEffectiveLineLength() > maxCodeLength)+                testForTimeToSplitFormattedLine();+        }+    } }  /**@@ -3351,20 +3646,20 @@ void ASFormatter::appendSpacePad()  */ void ASFormatter::appendSpaceAfter() {-	int len = currentLine.length();-	if (charNum + 1 < len && !std::isblank(currentLine[charNum + 1]))-	{-		formattedLine.append(1, ' ');-		spacePadNum++;-		if (maxCodeLength != std::string::npos)-		{-			// These compares reduce the frequency of function calls.-			if (isOkToSplitFormattedLine())-				updateFormattedLineSplitPoints(' ');-			if (formattedLine.length() > maxCodeLength)-				testForTimeToSplitFormattedLine();-		}-	}+    int len = currentLine.length();+    if (charNum + 1 < len && !std::isblank(currentLine[charNum + 1]))+    {+        formattedLine.append(1, ' ');+        spacePadNum++;+        if (maxCodeLength != std::string::npos)+        {+            // These compares reduce the frequency of function calls.+            if (isOkToSplitFormattedLine())+                updateFormattedLineSplitPoints(' ');+            if (getEffectiveLineLength() > maxCodeLength)+                testForTimeToSplitFormattedLine();+        }+    } }  /**@@ -3372,28 +3667,32 @@ void ASFormatter::appendSpaceAfter()  */ void ASFormatter::breakLine(bool isSplitLine /*false*/) {-	isLineReady = true;-	isInLineBreak = false;-	spacePadNum = nextLineSpacePadNum;-	nextLineSpacePadNum = 0;-	readyFormattedLine = formattedLine;-	formattedLine.erase();-	// queue an empty line prepend request if one exists-	prependEmptyLine = isPrependPostBlockEmptyLineRequested;--	if (!isSplitLine)-	{-		formattedLineCommentNum = std::string::npos;-		clearFormattedLineSplitPoints();--		if (isAppendPostBlockEmptyLineRequested)-		{-			isAppendPostBlockEmptyLineRequested = false;-			isPrependPostBlockEmptyLineRequested = true;-		}-		else-			isPrependPostBlockEmptyLineRequested = false;-	}+    isLineReady = true;+    isInLineBreak = false;+    spacePadNum = nextLineSpacePadNum;+    nextLineSpacePadNum = 0;+    readyFormattedLine = formattedLine;+    formattedLine.erase();+    if (shouldPreserveIndent && !preserveIndentLeading.empty())+    {+        formattedLine = preserveIndentLeading;+        preserveIndentLeading = "";+    }+    // queue an empty line prepend request if one exists+    prependEmptyLine = isPrependPostBlockEmptyLineRequested;+    if (!isSplitLine)+    {+        formattedLineCommentNum = std::string::npos;+        clearFormattedLineSplitPoints();++        if (isAppendPostBlockEmptyLineRequested)+        {+            isAppendPostBlockEmptyLineRequested = false;+            isPrependPostBlockEmptyLineRequested = true;+        }+        else+            isPrependPostBlockEmptyLineRequested = false;+    } }  /**@@ -3409,99 +3708,121 @@ void ASFormatter::breakLine(bool isSplitLine /*false*/)  */ BraceType ASFormatter::getBraceType() {-	assert(currentChar == '{');--	BraceType returnVal = NULL_TYPE;--	if ((previousNonWSChar == '='-	        || isBraceType(braceTypeStack->back(), ARRAY_TYPE))-	        && previousCommandChar != ')'-	        && !isNonParenHeader)-		returnVal = ARRAY_TYPE;-	else if (foundPreDefinitionHeader && previousCommandChar != ')')-	{-		returnVal = DEFINITION_TYPE;-		if (foundNamespaceHeader)-			returnVal = (BraceType)(returnVal | NAMESPACE_TYPE);-		else if (foundClassHeader)-			returnVal = (BraceType)(returnVal | CLASS_TYPE);-		else if (foundStructHeader)-			returnVal = (BraceType)(returnVal | STRUCT_TYPE);-		else if (foundInterfaceHeader)-			returnVal = (BraceType)(returnVal | INTERFACE_TYPE);-	}-	else if (isInEnum)-	{-		returnVal = (BraceType)(ARRAY_TYPE | ENUM_TYPE);-	}-	else if (isSharpStyle() &&-	         !isOneLineBlockReached(currentLine, charNum) &&-	         (currentHeader == &ASResource::AS_IF || currentHeader == &ASResource::AS_WHILE-	          || currentHeader == &ASResource::AS_USING || currentHeader == &ASResource::AS_WHILE-	          || currentHeader == &ASResource::AS_FOR  || currentHeader == &ASResource::AS_FOREACH) )   // GH16-	{-		returnVal = (BraceType) COMMAND_TYPE;-	}-	else-	{-		bool isCommandType = (foundPreCommandHeader-		                      || foundPreCommandMacro-		                      || (currentHeader != nullptr && isNonParenHeader)-		                      || (previousCommandChar == ')' && !isInAllocator)-		                      || (previousCommandChar == ':' && !foundQuestionMark)-		                      || (previousCommandChar == ';')-		                      || ((previousCommandChar == '{' || previousCommandChar == '}')-		                          && isPreviousBraceBlockRelated)-		                      || (isInClassInitializer-		                          && ((!isLegalNameChar(previousNonWSChar) && previousNonWSChar != '(')-		                              || foundPreCommandHeader))-		                      || foundTrailingReturnType-		                      || isInObjCMethodDefinition-		                      || isInObjCInterface-		                      || isJavaStaticConstructor-		                      || isSharpDelegate);-		// C# methods containing 'get', 'set', 'add', and 'remove' do NOT end with parens-		if (!isCommandType && isSharpStyle() && isNextWordSharpNonParenHeader(charNum + 1))-		{-			isCommandType = true;-			isSharpAccessor = true;-		}--		if (isInExternC)-			returnVal = (isCommandType ? COMMAND_TYPE : EXTERN_TYPE);-		else-			returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);-	}--	int foundOneLineBlock = isOneLineBlockReached(currentLine, charNum);--	if (foundOneLineBlock == 2 && returnVal == COMMAND_TYPE)-		returnVal = ARRAY_TYPE;--	if (foundOneLineBlock > 0)-	{-		returnVal = (BraceType) (returnVal | SINGLE_LINE_TYPE);-		if (breakCurrentOneLineBlock)-			returnVal = (BraceType) (returnVal | BREAK_BLOCK_TYPE);-		if (foundOneLineBlock == 3)-			returnVal = (BraceType)(returnVal | EMPTY_BLOCK_TYPE);-	}--	if (isBraceType(returnVal, ARRAY_TYPE))-	{-		if (isNonInStatementArrayBrace())-		{-			returnVal = (BraceType)(returnVal | ARRAY_NIS_TYPE);-			isNonInStatementArray = true;-			isImmediatelyPostNonInStmt = false;		// in case of "},{"-			nonInStatementBrace = formattedLine.length() - 1;-		}-		if (isUniformInitializerBrace())-			returnVal = (BraceType)(returnVal | INIT_TYPE);-	}---	return returnVal;+    assert(currentChar == '{');++    BraceType returnVal = BraceType::NULL_TYPE;++    // a one-line compound requirement like '{ a + b } -> C<T>;' in a requires-expression body+    bool isCompoundRequirement = !requiresBodyStack->empty()+                                 && requiresBodyStack->back() == braceTypeStack->size()+                                 && (previousCommandChar == '{' || previousCommandChar == ';'+                                     || previousCommandChar == '}')+                                 && isOneLineBlockReached(currentLine, charNum) > 0;++    if (isCompoundRequirement)+        returnVal = BraceType::ARRAY_TYPE;+    else if ((previousNonWSChar == '='+            || isBraceType(braceTypeStack->back(), BraceType::ARRAY_TYPE))+            && previousCommandChar != ')'+            && !isNonParenHeader)+        returnVal = BraceType::ARRAY_TYPE;+    else if (foundPreDefinitionHeader && (previousCommandChar != ')' || foundDefinitionAttribute))+    {+        returnVal = BraceType::DEFINITION_TYPE;+        if (foundNamespaceHeader)+            returnVal = returnVal | BraceType::NAMESPACE_TYPE;+        else if (foundClassHeader)+            returnVal = returnVal | BraceType::CLASS_TYPE;+        else if (foundStructHeader)+            returnVal = returnVal | BraceType::STRUCT_TYPE;+        else if (foundInterfaceHeader)+            returnVal = returnVal | BraceType::INTERFACE_TYPE;+    }+    else if (isInEnum)+    {+        returnVal = BraceType::ARRAY_TYPE | BraceType::ENUM_TYPE;+    }+    else if (isSharpStyle() &&+             !isOneLineBlockReached(currentLine, charNum) &&+             (currentHeader == &ASResource::AS_IF || currentHeader == &ASResource::AS_WHILE+              || currentHeader == &ASResource::AS_USING || currentHeader == &ASResource::AS_WHILE+              || currentHeader == &ASResource::AS_FOR  || currentHeader == &ASResource::AS_FOREACH) )   // GH16+    {+        returnVal = BraceType::COMMAND_TYPE;+    }+    else+    {+        bool isCommandType = (foundPreCommandHeader+                              || foundPreCommandMacro+                              || (currentHeader != nullptr && isNonParenHeader)+                              || (previousCommandChar == ')' && !isInAllocator)+                              || (previousCommandChar == ':' && !foundQuestionMark+                                  && parenStack->back() == 0)   // not 'for (x : {1, 2})'+                              || (previousCommandChar == ';')+                              || ((previousCommandChar == '{' || previousCommandChar == '}')+                                  && isPreviousBraceBlockRelated)+                              || (isInClassInitializer+                                  && ((!isLegalNameChar(previousNonWSChar) && previousNonWSChar != '(')+                                      || foundPreCommandHeader))+                              || foundTrailingReturnType+                              || foundConstevalCondition+                              || isInObjCMethodDefinition+                              || isInObjCInterface+                              || isJavaStaticConstructor+                              || isSharpDelegate);+        // C# methods containing 'get', 'set', 'add', and 'remove' do NOT end with parens+        if (!isCommandType && isSharpStyle() && isNextWordSharpNonParenHeader(charNum + 1))+        {+            isCommandType = true;+            isSharpAccessor = true;+        }++        if (isInExternC)+            returnVal = (isCommandType ? BraceType::COMMAND_TYPE : BraceType::EXTERN_TYPE);+        else+            returnVal = (isCommandType ? BraceType::COMMAND_TYPE : BraceType::ARRAY_TYPE);+    }++    int foundOneLineBlock = isOneLineBlockReached(currentLine, charNum);++    if (foundOneLineBlock == 2 && returnVal == BraceType::COMMAND_TYPE)+        returnVal = BraceType::ARRAY_TYPE;++    // keep a one-line lambda with parameters like '[&](int v) { return v; }' on one line,+    // as it is done for a lambda without parameters like '[&] { return v; }'+    if (foundOneLineBlock == 1 && returnVal == BraceType::COMMAND_TYPE+            && isLambdaBodyWithParamsBrace())+        returnVal = BraceType::ARRAY_TYPE;++    // keep a one-line requires-expression like 'requires(T x) { x.f(); }' on one line+    if (foundOneLineBlock == 1 && returnVal == BraceType::COMMAND_TYPE+            && foundRequiresExpression)+        returnVal = BraceType::ARRAY_TYPE;++    if (foundOneLineBlock > 0)+    {+        returnVal = returnVal | BraceType::SINGLE_LINE_TYPE;+        if (breakCurrentOneLineBlock)+            returnVal = returnVal | BraceType::BREAK_BLOCK_TYPE;+        if (foundOneLineBlock == 3)+            returnVal = returnVal | BraceType::EMPTY_BLOCK_TYPE;+    }++    if (isBraceType(returnVal, BraceType::ARRAY_TYPE))+    {+        if (isNonInStatementArrayBrace())+        {+            returnVal = returnVal | BraceType::ARRAY_NIS_TYPE;+            isNonInStatementArray = true;+            isImmediatelyPostNonInStmt = false;		// in case of "},{"+            nonInStatementBrace = formattedLine.length() - 1;+        }+        if (isUniformInitializerBrace())+            returnVal = returnVal | BraceType::INIT_TYPE;+    }+++    return returnVal; }  /**@@ -3511,21 +3832,21 @@ BraceType ASFormatter::getBraceType() */ bool ASFormatter::isClassInitializer() const {-	assert(currentChar == ':');-	assert(previousChar != ':' && peekNextChar() != ':'); // not part of '::'+    assert(currentChar == ':');+    assert(previousChar != ':' && peekNextChar() != ':'); // not part of '::' -	// Early exit if conditions that prevent class initializer detection are met-	if (foundQuestionMark || parenStack->back() > 0 || isInEnum)-	{-		return false;-	}+    // Early exit if conditions that prevent class initializer detection are met+    if (foundQuestionMark || parenStack->back() > 0 || isInEnum)+    {+        return false;+    } -	// Check if we are in a C-style class constructor initializer-	bool isCStyleInitializer = isCStyle() &&-	                           !isInCase &&-	                           (previousCommandChar == ')' || foundPreCommandHeader);+    // Check if we are in a C-style class constructor initializer+    bool isCStyleInitializer = isCStyle() &&+                               !isInCase &&+                               (previousCommandChar == ')' || foundPreCommandHeader); -	return isCStyleInitializer;+    return isCStyleInitializer; }  @@ -3536,7 +3857,36 @@ bool ASFormatter::isClassInitializer() const  */ bool ASFormatter::isEmptyLine(std::string_view line) const {-	return line.find_first_not_of(" \t") == std::string::npos;+    return line.find_first_not_of(" \t") == std::string::npos;+}++/**+ * check if a line is a preprocessor directive which starts or ends+ * a conditional block (#if, #ifdef, #else, #endif, ...)+ *+ * @param line           the line to check+ * @param isBlockStart   true: check for a directive followed by a conditional block+ *                       false: check for a directive which ends a conditional block+ * @return               whether the line is such a directive+ */+bool ASFormatter::isPreprocCondBlockEdge(std::string_view line, bool isBlockStart) const+{+    size_t start = line.find_first_not_of(" \t");+    if (start == std::string_view::npos || line[start] != '#')+        return false;+    start = line.find_first_not_of(" \t", start + 1);+    if (start == std::string_view::npos)+        return false;+    size_t end = start;+    while (end < line.length() && std::isalpha(static_cast<unsigned char>(line[end])))+        ++end;+    std::string_view directive = line.substr(start, end - start);++    if (directive == "else" || directive.substr(0, 4) == "elif")+        return true;+    if (isBlockStart)+        return directive.substr(0, 2) == "if";+    return directive == "endif"; }  /**@@ -3546,17 +3896,17 @@ bool ASFormatter::isEmptyLine(std::string_view line) const  */ bool ASFormatter::isExternC() const {-	// charNum should be at 'extern'-	assert(!std::isblank(currentLine[charNum]));-	size_t startQuote = currentLine.find_first_of(" \t\"", charNum);-	if (startQuote == std::string::npos)-		return false;-	startQuote = currentLine.find_first_not_of(" \t", startQuote);-	if (startQuote == std::string::npos)-		return false;-	if (currentLine.compare(startQuote, 3, "\"C\"") != 0)-		return false;-	return true;+    // charNum should be at 'extern'+    assert(!std::isblank(currentLine[charNum]));+    size_t startQuote = currentLine.find_first_of(" \t\"", charNum);+    if (startQuote == std::string::npos)+        return false;+    startQuote = currentLine.find_first_not_of(" \t", startQuote);+    if (startQuote == std::string::npos)+        return false;+    if (currentLine.compare(startQuote, 3, "\"C\"") != 0)+        return false;+    return true; }  /**@@ -3570,159 +3920,165 @@ bool ASFormatter::isExternC() const  */ bool ASFormatter::isPointerOrReference() const {-	assert(currentChar == '*' || currentChar == '&' || currentChar == '^');--	if (isJavaStyle())-		return false;--	if (isCharImmediatelyPostOperator)-		return false;--	// get the last legal word (may be a number)-	std::string lastWord = getPreviousWord(currentLine, charNum);-	if (lastWord.empty())-		lastWord = " ";--	// check for preceding or following numeric values-	std::string nextText = peekNextText(currentLine.substr(charNum + 1));-	if (nextText.empty())-		nextText = " ";-	if (isDigit(lastWord[0])-	        || isDigit(nextText[0])-	        || nextText[0] == '!'-	        || nextText[0] == '~')-		return false;--	// check for multiply then a dereference (a * *b)-	char nextChar = peekNextChar();-	if (currentChar == '*'-	        && nextChar == '*'-	        && !isPointerToPointer(currentLine, charNum))-		return false;--	if ((foundCastOperator && nextChar == '>')-	        || isPointerOrReferenceVariable(lastWord))-	{-		return true;-	}--	if (pointerAlignment == PTR_ALIGN_TYPE-	        && !shouldPadOperators //TODO 578-	        && !isPointerOrReferenceVariable(lastWord))-	{-		return false;-	}--	if (isInClassInitializer-	        && previousNonWSChar != '('-	        && previousNonWSChar != '{'-	        && previousCommandChar != ','-	        && nextChar != ')'-	        && nextChar != '}')-		return false;--	//check for rvalue reference-	if (currentChar == '&' && nextChar == '&')-	{-		if (lastWord == ASResource::AS_AUTO)-			return true;-		if (previousNonWSChar == '>')-			return true;-		std::string followingText;-		if ((int) currentLine.length() > charNum + 2)-			followingText = peekNextText(currentLine.substr(charNum + 2));-		if (!followingText.empty() && followingText[0] == ')')-			return true;-		if (currentHeader != nullptr || isInPotentialCalculation)-			return false;-		if (parenStack->back() > 0 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))-			return false;-		return true;-	}--	if (nextChar == '*'-	        || previousNonWSChar == '='-	        || previousNonWSChar == '('-	        || previousNonWSChar == '['-	        || isCharImmediatelyPostReturn-	        || isInTemplate-	        || isCharImmediatelyPostTemplate-	        || currentHeader == &ASResource::AS_CATCH-	        || currentHeader == &ASResource::AS_FOREACH-	        || currentHeader == &ASResource::AS_QFOREACH)-	{-		return true;-	}---	if (isBraceType(braceTypeStack->back(), ARRAY_TYPE)-	        && isLegalNameChar(lastWord[0])-	        && isLegalNameChar(nextChar)-	        && previousNonWSChar != ')')-	{-		if (isArrayOperator())-			return false;-	}--	// checks on operators in parens-	if (parenStack->back() > 0-	        && isLegalNameChar(lastWord[0])-	        && isLegalNameChar(nextChar))-	{-		// if followed by an assignment it is a pointer or reference-		// if followed by semicolon it is a pointer or reference in range-based for-		const std::string* followingOperator = getFollowingOperator();-		if (followingOperator != nullptr-		        && followingOperator != &ASResource::AS_MULT-		        && followingOperator != &ASResource::AS_BIT_AND)-		{-			if (followingOperator == &ASResource::AS_ASSIGN || followingOperator == &ASResource::AS_COLON)-			{-				return true;-			}--			return false;-		}--		if (isBraceType(braceTypeStack->back(), COMMAND_TYPE)-		        || squareBracketCount > 0)-			return false;-		return true;-	}--	// checks on operators in parens with following '('-	std::set<char> disallowedChars = {',', '(', '!', '&', '*', '|'};--	if (parenStack->back() > 0-	        && nextChar == '('-	        && disallowedChars.find(previousNonWSChar) == disallowedChars.end())-		return false;--	if (nextChar == '-'-	        || nextChar == '+')-	{-		size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);-		if (nextNum != std::string::npos)-		{-			if (currentLine.compare(nextNum, 2, "++") != 0-			        && currentLine.compare(nextNum, 2, "--") != 0)-				return false;-		}-	}--	bool isPR = (!isInPotentialCalculation-	             || (!isLegalNameChar(previousNonWSChar)-	                 && !(previousNonWSChar == ')' && nextChar == '(')-	                 && !(previousNonWSChar == ')' && currentChar == '*' && !isImmediatelyPostCast())-	                 && previousNonWSChar != ']')-	             || (!std::isblank(nextChar)-	                 && nextChar != '-'-	                 && nextChar != '('-	                 && nextChar != '['-	                 && !isLegalNameChar(nextChar))-	            );--	return isPR;+    assert(currentChar == '*' || currentChar == '&' || currentChar == '^');++    if (isJavaStyle())+        return false;++    if (isCharImmediatelyPostOperator)+        return false;++    // get the last legal word (may be a number)+    std::string_view lastWord = getPreviousWord(currentLine, charNum);+    if (lastWord.empty())+        lastWord = " ";++    // check for preceding or following numeric values+    std::string nextText = peekNextText(currentLine.substr(charNum + 1));+    if (nextText.empty())+        nextText = " ";+    if (isDigit(lastWord[0])+            || isDigit(nextText[0])+            || nextText[0] == '!'+            || nextText[0] == '~')+        return false;++    // check for multiply then a dereference (a * *b)+    char nextChar = peekNextChar();+    if (currentChar == '*'+            && nextChar == '*'+            && !isPointerToPointer(currentLine, charNum))+        return false;++    // dereference after a cast like "(unsigned char) *ptr" or "(int*) *(ptr + 1)"+    if (currentChar == '*'+            && previousNonWSChar == ')'+            && isImmediatelyPostCast())+        return true;++    if ((foundCastOperator && nextChar == '>')+            || isPointerOrReferenceVariable(lastWord))+    {+        return true;+    }++    if (pointerAlignment == PTR_ALIGN_TYPE+            && !shouldPadOperators //TODO 578+            && !isPointerOrReferenceVariable(lastWord))+    {+        return false;+    }++    if (isInClassInitializer+            && previousNonWSChar != '('+            && previousNonWSChar != '{'+            && previousCommandChar != ','+            && nextChar != ')'+            && nextChar != '}')+        return false;++    //check for rvalue reference+    if (currentChar == '&' && nextChar == '&')+    {+        if (lastWord == ASResource::AS_AUTO)+            return true;+        if (previousNonWSChar == '>')+            return true;+        std::string followingText;+        if ((int) currentLine.length() > charNum + 2)+            followingText = peekNextText(currentLine.substr(charNum + 2));+        if (!followingText.empty() && followingText[0] == ')')+            return true;+        if (currentHeader != nullptr || isInPotentialCalculation)+            return false;+        if (parenStack->back() > 0 && isBraceType(braceTypeStack->back(), BraceType::COMMAND_TYPE))+            return false;+        return true;+    }++    if (nextChar == '*'+            || previousNonWSChar == '='+            || previousNonWSChar == '('+            || previousNonWSChar == '['+            || isCharImmediatelyPostReturn+            || isInTemplate+            || isCharImmediatelyPostTemplate+            || currentHeader == &ASResource::AS_CATCH+            || currentHeader == &ASResource::AS_FOREACH+            || currentHeader == &ASResource::AS_QFOREACH)+    {+        return true;+    }+++    if (isBraceType(braceTypeStack->back(), BraceType::ARRAY_TYPE)+            && isLegalNameChar(lastWord[0])+            && isLegalNameChar(nextChar)+            && previousNonWSChar != ')')+    {+        if (isArrayOperator())+            return false;+    }++    // checks on operators in parens+    if (parenStack->back() > 0+            && isLegalNameChar(lastWord[0])+            && isLegalNameChar(nextChar))+    {+        // if followed by an assignment it is a pointer or reference+        // if followed by semicolon it is a pointer or reference in range-based for+        const std::string* followingOperator = getFollowingOperator();+        if (followingOperator != nullptr+                && followingOperator != &ASResource::AS_MULT+                && followingOperator != &ASResource::AS_BIT_AND)+        {+            if (followingOperator == &ASResource::AS_ASSIGN || followingOperator == &ASResource::AS_COLON)+            {+                return true;+            }++            return false;+        }++        if (isBraceType(braceTypeStack->back(), BraceType::COMMAND_TYPE)+                || squareBracketCount > 0)+            return false;+        return true;+    }++    // checks on operators in parens with following '('+    std::set<char> disallowedChars = {',', '(', '!', '&', '*', '|'};++    if (parenStack->back() > 0+            && nextChar == '('+            && disallowedChars.find(previousNonWSChar) == disallowedChars.end())+        return false;++    if (nextChar == '-'+            || nextChar == '+')+    {+        size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);+        if (nextNum != std::string::npos)+        {+            if (currentLine.compare(nextNum, 2, "++") != 0+                    && currentLine.compare(nextNum, 2, "--") != 0)+                return false;+        }+    }++    bool isPR = (!isInPotentialCalculation+                 || (!isLegalNameChar(previousNonWSChar)+                     && !(previousNonWSChar == ')' && nextChar == '(')+                     && !(previousNonWSChar == ')' && currentChar == '*' && !isImmediatelyPostCast())+                     && previousNonWSChar != ']')+                 || (!std::isblank(nextChar)+                     && nextChar != '-'+                     && nextChar != '('+                     && nextChar != '['+                     && !isLegalNameChar(nextChar))+                );++    return isPR; }  /**@@ -3735,94 +4091,110 @@ bool ASFormatter::isPointerOrReference() const  */ bool ASFormatter::isDereferenceOrAddressOf() const {-	assert(currentChar == '*' || currentChar == '&' || currentChar == '^');--	if (isCharImmediatelyPostTemplate)-		return false;--	// https://sourceforge.net/p/astyle/bugs/537/-	// https://sourceforge.net/p/astyle/bugs/552/-	if ( previousNonWSChar == ',' && parenthesesCount <= 0 && currentChar != '&')-	{-		return false;-	}--	if ( currentChar == '*' && pointerAlignment == PTR_ALIGN_NAME )-	{-		size_t openParen = currentLine.rfind('(', charNum);-		if (openParen != std::string::npos)-		{-			return true;-		}-	}--	std::set<char> allowedChars = {'=', '.', '{', '>', '<', '?'};--	if ( allowedChars.find(previousNonWSChar) != allowedChars.end()-	        || (previousNonWSChar == ',' && currentChar == '&')  // #537, #552-	        || isCharImmediatelyPostLineComment-	        || isCharImmediatelyPostComment-	        || isCharImmediatelyPostReturn)-		return true;--	char nextChar = peekNextChar();-	if (currentChar == '*' && nextChar == '*')-	{-		if (previousNonWSChar == '(')-			return true;-		if ((int) currentLine.length() < charNum + 2)-			return true;-		return false;-	}--	if (currentChar == '&' && nextChar == '&')-	{-		if (previousNonWSChar == '(' || isInTemplate)-			return true;-		if ((int) currentLine.length() < charNum + 2)-			return true;-		return false;-	}--	if (previousNonWSChar == '(' && currentChar == '&' && pointerAlignment == PTR_ALIGN_TYPE)-	{-		return true;-	}--	// check first char on the line-	if (charNum == (int) currentLine.find_first_not_of(" \t")-	        && (isBraceType(braceTypeStack->back(), COMMAND_TYPE)-	            || parenStack->back() != 0))-		return true;--	std::string nextText = peekNextText(currentLine.substr(charNum + 1));-	if (!nextText.empty())-	{-		if (nextText[0] == ')' || nextText[0] == '>'-		        || nextText[0] == ',' || nextText[0] == '=')-			return false;-		if (nextText[0] == ';')-			return true;-	}-	// check for reference to a pointer *&-	if ((currentChar == '*' && nextChar == '&')-	        || (previousNonWSChar == '*' && currentChar == '&'))-		return false;--	if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE)-	        && parenStack->back() == 0)-		return false;-	std::string lastWord = getPreviousWord(currentLine, charNum);-	if (lastWord == "else" || lastWord == "delete")-		return true;--	bool isDA = (!(isLegalNameChar(previousNonWSChar) || previousNonWSChar == '>')          // TODO GH14-	             || (!nextText.empty() && !isLegalNameChar(nextText[0]) && nextText[0] != '/')-	             || (ispunct((unsigned char)previousNonWSChar) && previousNonWSChar != '.') // TODO GH14-	             || isCharImmediatelyPostReturn-	             || !isPointerOrReferenceVariable(lastWord));--	return isDA;+    assert(currentChar == '*' || currentChar == '&' || currentChar == '^');++    if (isCharImmediatelyPostTemplate)+        return false;++    // https://sourceforge.net/p/astyle/bugs/537/+    // https://sourceforge.net/p/astyle/bugs/552/+    if ( previousNonWSChar == ',' && parenthesesCount <= 0 && currentChar != '&')+    {+        return false;+    }++    std::set<char> allowedChars = {'=', '.', '{', '>', '<', '?'};++    if ( allowedChars.find(previousNonWSChar) != allowedChars.end()+            || (previousNonWSChar == ',' && currentChar == '&')  // #537, #552+            || isCharImmediatelyPostLineComment+            || isCharImmediatelyPostComment+            || isCharImmediatelyPostReturn)+        return true;++    char nextChar = peekNextChar();+    if (currentChar == '*' && nextChar == '*')+    {+        if (previousNonWSChar == '(')+            return true;+        if ((int) currentLine.length() < charNum + 2)+            return true;+        return false;+    }++    if (currentChar == '&' && nextChar == '&')+    {+        if (previousNonWSChar == '(' || isInTemplate)+            return true;+        if ((int) currentLine.length() < charNum + 2)+            return true;+        return false;+    }++    if (previousNonWSChar == '(' && currentChar == '&' && pointerAlignment == PTR_ALIGN_TYPE)+    {+        return true;+    }++    // check first char on the line+    if (charNum == (int) currentLine.find_first_not_of(" \t")+            && (isBraceType(braceTypeStack->back(), BraceType::COMMAND_TYPE)+                || parenStack->back() != 0))+        return true;++    std::string nextText = peekNextText(currentLine.substr(charNum + 1));+    if (!nextText.empty())+    {+        if (nextText[0] == ')' || nextText[0] == '>'+                || nextText[0] == ',' || nextText[0] == '=')+            return false;+        if (nextText[0] == ';')+            return true;+    }+    // check for reference to a pointer *&+    if ((currentChar == '*' && nextChar == '&')+            || (previousNonWSChar == '*' && currentChar == '&'))+        return false;++    // check for address-of after a pointer cast like (int *)&var+    // isImmediatelyPostCast() only handles *, so we inline equivalent logic here+    if (currentChar == '&' && previousNonWSChar == ')')+    {+        std::string line;+        size_t paren = currentLine.rfind(')', charNum);+        if (paren != std::string::npos)+            line = currentLine;+        else+        {+            line = readyFormattedLine;+            paren = line.rfind(')');+        }+        if (paren != std::string::npos && paren > 0)+        {+            size_t lastCh = line.find_last_not_of(" \t", paren - 1);+            if (lastCh != std::string::npos && line[lastCh] == '*')+                return true;+        }+    }++    // check for dereference after a cast like (int *)*ptr or (int)*ptr+    if (currentChar == '*' && previousNonWSChar == ')' && isImmediatelyPostCast())+        return true;++    if (!isBraceType(braceTypeStack->back(), BraceType::COMMAND_TYPE)+            && parenStack->back() == 0)+        return false;+    std::string_view lastWord = getPreviousWord(currentLine, charNum);+    if (lastWord == "else" || lastWord == "delete")+        return true;++    bool isDA = (!(isLegalNameChar(previousNonWSChar) || previousNonWSChar == '>')          // TODO GH14+                 || (!nextText.empty() && !isLegalNameChar(nextText[0]) && nextText[0] != '/')+                 || (ispunct((unsigned char)previousNonWSChar) && previousNonWSChar != '.') // TODO GH14+                 || isCharImmediatelyPostReturn+                 || !isPointerOrReferenceVariable(lastWord));++    return isDA; }  /**@@ -3835,41 +4207,41 @@ bool ASFormatter::isDereferenceOrAddressOf() const  */ bool ASFormatter::isPointerOrReferenceCentered() const {-	assert(currentChar == '*' || currentChar == '&' || currentChar == '^');+    assert(currentChar == '*' || currentChar == '&' || currentChar == '^'); -	int prNum = charNum;-	int lineLength = (int) currentLine.length();+    int prNum = charNum;+    int lineLength = (int) currentLine.length(); -	// check for end of line-	if (peekNextChar() == ' ')-		return false;+    // check for end of line+    if (peekNextChar() == ' ')+        return false; -	// check space before-	if (prNum < 1-	        || currentLine[prNum - 1] != ' ')-		return false;+    // check space before+    if (prNum < 1+            || currentLine[prNum - 1] != ' ')+        return false; -	// check no space before that-	if (prNum < 2-	        || currentLine[prNum - 2] == ' ')-		return false;+    // check no space before that+    if (prNum < 2+            || currentLine[prNum - 2] == ' ')+        return false; -	// check for ** or &&-	if (prNum + 1 < lineLength-	        && (currentLine[prNum + 1] == '*' || currentLine[prNum + 1] == '&'))-		prNum++;+    // check for ** or &&+    if (prNum + 1 < lineLength+            && (currentLine[prNum + 1] == '*' || currentLine[prNum + 1] == '&'))+        prNum++; -	// check space after-	if (prNum + 1 <= lineLength-	        && currentLine[prNum + 1] != ' ')-		return false;+    // check space after+    if (prNum + 1 <= lineLength+            && currentLine[prNum + 1] != ' ')+        return false; -	// check no space after that-	if (prNum + 2 < lineLength-	        && currentLine[prNum + 2] == ' ')-		return false;+    // check no space after that+    if (prNum + 2 < lineLength+            && currentLine[prNum + 2] == ' ')+        return false; -	return true;+    return true; }  /**@@ -3879,40 +4251,40 @@ bool ASFormatter::isPointerOrReferenceCentered() const  */ bool ASFormatter::isPointerOrReferenceVariable(std::string_view word) const {-	assert(currentChar == '*' || currentChar == '&' || currentChar == '^');--	// to avoid problem with multiplications - we need LSP--	bool retval = false;-	if (word == "char"-	        || word == "std::string"-	        || word == "String"-	        || word == "NSString"-	        || word == "int"-	        || word == "void"-	        || word == "short"-	        || word == "long"-	        || word == "double"-	        || word == "float"-	        || word == "sizeof"-	        || (word.length() >= 6     // check end of word for _t-	            && word.compare(word.length() - 2, 2, "_t") == 0)-	   )-		retval = true;--	// check for C# object type "x is std::string"-	if (retval && isSharpStyle())-	{-		// find the word previous to the 'word' parameter-		std::string prevWord;-		size_t wordStart = currentLine.rfind(word, charNum);-		if (wordStart != std::string::npos)-			prevWord = getPreviousWord(currentLine, wordStart);-		if (prevWord == "is")-			retval = false;-	}--	return retval;+    assert(currentChar == '*' || currentChar == '&' || currentChar == '^');++    // to avoid problem with multiplications - we need LSP++    bool retval = false;+    if (word == "char"+            || word == "std::string"+            || word == "String"+            || word == "NSString"+            || word == "int"+            || word == "void"+            || word == "short"+            || word == "long"+            || word == "double"+            || word == "float"+            || word == "sizeof"+            || (word.length() >= 6     // check end of word for _t+                && word.compare(word.length() - 2, 2, "_t") == 0)+       )+        retval = true;++    // check for C# object type "x is std::string"+    if (retval && isSharpStyle())+    {+        // find the word previous to the 'word' parameter+        std::string_view prevWord;+        size_t wordStart = currentLine.rfind(word, charNum);+        if (wordStart != std::string::npos)+            prevWord = getPreviousWord(currentLine, wordStart);+        if (prevWord == "is")+            retval = false;+    }++    return retval; }  /**@@ -3922,18 +4294,18 @@ bool ASFormatter::isPointerOrReferenceVariable(std::string_view word) const  */ bool ASFormatter::isPointerToPointer(std::string_view line, int currPos) const {-	assert(line[currPos] == '*' && peekNextChar() == '*');-	if ((int) line.length() > currPos + 1 && line[currPos + 1] == '*')-		return true;-	size_t nextText = line.find_first_not_of(" \t", currPos + 1);-	if (nextText == std::string::npos || line[nextText] != '*')-		return false;-	size_t nextText2 = line.find_first_not_of(" \t", nextText + 1);-	if (nextText == std::string::npos)-		return false;-	if (line[nextText2] == ')' || line[nextText2] == '*')-		return true;-	return false;+    assert(line[currPos] == '*' && peekNextChar() == '*');+    if ((int) line.length() > currPos + 1 && line[currPos + 1] == '*')+        return true;+    size_t nextText = line.find_first_not_of(" \t", currPos + 1);+    if (nextText == std::string::npos || line[nextText] != '*')+        return false;+    size_t nextText2 = line.find_first_not_of(" \t", nextText + 1);+    if (nextText == std::string::npos)+        return false;+    if (line[nextText2] == ')' || line[nextText2] == '*')+        return true;+    return false; }  /**@@ -3945,37 +4317,38 @@ bool ASFormatter::isPointerToPointer(std::string_view line, int currPos) const  */ bool ASFormatter::isUnaryOperator() const {-	assert(currentChar == '+' || currentChar == '-');+    assert(currentChar == '+' || currentChar == '-'); -	// does a digit follow a c-style cast-	if (previousCommandChar == ')')-	{-		if (!isdigit(peekNextChar()))-			return false;-		size_t end = currentLine.rfind(')', charNum);-		if (end == std::string::npos)-			return false;-		size_t lastChar = currentLine.find_last_not_of(" \t", end - 1);-		if (lastChar == std::string::npos)-			return false;-		if (currentLine[lastChar] == '*')-			end = lastChar;-		std::string prevWord = getPreviousWord(currentLine, end);-		if (prevWord.empty())-			return false;+    // does a digit follow a c-style cast+    if (previousCommandChar == ')')+    {+        if (!isdigit(peekNextChar()))+            return false;+        size_t end = currentLine.rfind(')', charNum);+        if (end == std::string::npos)+            return false; -		// a cast can be a user defined type-		//if (!isNumericVariable(prevWord))-		//	return false;+        size_t lastChar = currentLine.find_last_not_of(" \t", end - 1);+        if (lastChar == std::string::npos)+            return false;+        if (currentLine[lastChar] == '*')+            end = lastChar;+        std::string_view prevWord = getPreviousWord(currentLine, end);+        if (prevWord.empty())+            return false; -		return true;-	}+        // a cast can be a user defined type+        //if (!isNumericVariable(prevWord))+        //	return false; -	return ((isCharImmediatelyPostReturn || !isLegalNameChar(previousCommandChar))-	        && previousCommandChar != '.'-	        && previousCommandChar != '\"'-	        && previousCommandChar != '\''-	        && previousCommandChar != ']');+        return true;+    }++    return ((isCharImmediatelyPostReturn || !isLegalNameChar(previousCommandChar))+            && previousCommandChar != '.'+            && previousCommandChar != '\"'+            && previousCommandChar != '\''+            && previousCommandChar != ']'); }  /**@@ -3985,12 +4358,12 @@ bool ASFormatter::isUnaryOperator() const  */ bool ASFormatter::isInSwitchStatement() const {-	assert(isInLineComment || isInComment);-	if (!preBraceHeaderStack->empty())-		for (size_t i = 1; i < preBraceHeaderStack->size(); i++)-			if (preBraceHeaderStack->at(i) == &ASResource::AS_SWITCH)-				return true;-	return false;+    assert(isInLineComment || isInComment);+    if (!preBraceHeaderStack->empty())+        for (size_t i = 1; i < preBraceHeaderStack->size(); i++)+            if (preBraceHeaderStack->at(i) == &ASResource::AS_SWITCH)+                return true;+    return false; }  /**@@ -4001,23 +4374,23 @@ bool ASFormatter::isInSwitchStatement() const  */ bool ASFormatter::isInExponent() const {-	assert(currentChar == '+' || currentChar == '-');-	std::string prevWord = getPreviousWord(currentLine, charNum, true);+    assert(currentChar == '+' || currentChar == '-');+    std::string_view prevWord = getPreviousWord(currentLine, charNum, true); -	if (charNum && isDigit(prevWord[0]))-	{-		return prevWord.find_first_not_of("0123456789.") != std::string::npos;-	}+    if (charNum && !prevWord.empty() && isDigit(prevWord[0]))+    {+        return prevWord.find_first_not_of("0123456789.") != std::string::npos;+    } -	if (charNum > 2 && prevWord.size() >= 2 && prevWord[0] == '0' && (prevWord[1] == 'x' || prevWord[1] == 'X'))-	{-		char prevPrevFormattedChar = currentLine[charNum - 2];-		char prevFormattedChar = currentLine[charNum - 1];-		//    double x = 0x1.23ffp-11;-		return ((prevFormattedChar == 'e' || prevFormattedChar == 'E' || prevFormattedChar == 'p' || prevFormattedChar == 'P')-		        && (prevPrevFormattedChar == '.' || std::isxdigit(prevPrevFormattedChar)));-	}-	return false;+    if (charNum > 2 && prevWord.size() >= 2 && prevWord[0] == '0' && (prevWord[1] == 'x' || prevWord[1] == 'X'))+    {+        char prevPrevFormattedChar = currentLine[charNum - 2];+        char prevFormattedChar = currentLine[charNum - 1];+        //    double x = 0x1.23ffp-11;+        return ((prevFormattedChar == 'e' || prevFormattedChar == 'E' || prevFormattedChar == 'p' || prevFormattedChar == 'P')+                && (prevPrevFormattedChar == '.' || std::isxdigit(prevPrevFormattedChar)));+    }+    return false; }  /**@@ -4027,24 +4400,35 @@ bool ASFormatter::isInExponent() const  */ bool ASFormatter::isNonInStatementArrayBrace() const {-	bool returnVal = false;-	char nextChar = peekNextChar();-	// if this opening brace begins the line there will be no inStatement indent-	if (currentLineBeginsWithBrace-	        && (size_t) charNum == currentLineFirstBraceNum-	        && nextChar != '}')-		returnVal = true;-	// if an opening brace ends the line there will be no inStatement indent-	if (std::isblank(nextChar)-	        || isBeforeAnyLineEndComment(charNum)-	        || nextChar == '{')-		returnVal = true;--	// Java "new Type [] {...}" IS an inStatement indent-	if (isJavaStyle() && previousNonWSChar == ']')-		returnVal = false;--	return returnVal;+    bool returnVal = false;+    char nextChar = peekNextChar();+    bool isFirstBraceOnLine = currentLineBeginsWithBrace+                              && (size_t) charNum == currentLineFirstBraceNum;+    // #308 a nested array within an argument list like 'f(a, { {' IS an inStatement indent,+    // as are its elements that begin a line+    bool isInStatementArrayArgument = parenStack->back() > 0+                                      && (isFirstBraceOnLine+                                          ? isBraceType(braceTypeStack->back(), BraceType::ARRAY_TYPE)+                                            && !isBraceType(braceTypeStack->back(), BraceType::ARRAY_NIS_TYPE)+                                          : nextChar == '{');+    // if this opening brace begins the line there will be no inStatement indent+    if (isFirstBraceOnLine+            && nextChar != '}')+        returnVal = true;+    // if an opening brace ends the line there will be no inStatement indent+    if (std::isblank(nextChar)+            || isBeforeAnyLineEndComment(charNum)+            || nextChar == '{')+        returnVal = true;++    if (isInStatementArrayArgument)+        returnVal = false;++    // Java "new Type [] {...}" IS an inStatement indent+    if (isJavaStyle() && previousNonWSChar == ']')+        returnVal = false;++    return returnVal; }  /**@@ -4059,90 +4443,90 @@ bool ASFormatter::isNonInStatementArrayBrace() const  */ int ASFormatter::isOneLineBlockReached(std::string_view line, int startChar) const {-	assert(line[startChar] == '{');--	bool isInComment_ = false;-	bool isInQuote_ = false;-	bool hasText = false;-	int braceCount = 0;-	int lineLength = line.length();-	char quoteChar_ = ' ';-	char ch = ' ';-	char prevCh = ' ';--	for (int i = startChar; i < lineLength; ++i)-	{-		ch = line[i];--		if (isInComment_)-		{-			if (line.compare(i, 2, "*/") == 0)-			{-				isInComment_ = false;-				++i;-			}-			continue;-		}--		if (isInQuote_)-		{-			if (ch == '\\')-				++i;-			else if (ch == quoteChar_)-				isInQuote_ = false;-			continue;-		}--		if (ch == '"'-		        || (ch == '\'' && !isDigitSeparator(line, i)))-		{-			isInQuote_ = true;-			quoteChar_ = ch;-			continue;-		}--		if (line.compare(i, 2, "//") == 0)-			break;--		if (line.compare(i, 2, "/*") == 0)-		{-			isInComment_ = true;-			++i;-			continue;-		}--		if (ch == '{')-		{-			++braceCount;-			continue;-		}-		if (ch == '}')-		{-			--braceCount;-			if (braceCount == 0)-			{-				// is this an array?-				if (parenStack->back() == 0 && prevCh != '}')-				{-					size_t peekNum = line.find_first_not_of(" \t", i + 1);-					if (peekNum != std::string::npos && line[peekNum] == ',')-						return 2;-				}-				if (!hasText)-					return 3;	// is an empty block-				return 1;-			}-		}-		if (ch == ';')-			continue;-		if (!std::isblank(ch))-		{-			hasText = true;-			prevCh = ch;-		}-	}--	return 0;+    assert(line[startChar] == '{');++    bool isInComment_ = false;+    bool isInQuote_ = false;+    bool hasText = false;+    int braceCount = 0;+    int lineLength = line.length();+    char quoteChar_ = ' ';+    char ch = ' ';+    char prevCh = ' ';++    for (int i = startChar; i < lineLength; ++i)+    {+        ch = line[i];++        if (isInComment_)+        {+            if (line.compare(i, 2, "*/") == 0)+            {+                isInComment_ = false;+                ++i;+            }+            continue;+        }++        if (isInQuote_)+        {+            if (ch == '\\')+                ++i;+            else if (ch == quoteChar_)+                isInQuote_ = false;+            continue;+        }++        if (ch == '"'+                || (ch == '\'' && !isDigitSeparator(line, i)))+        {+            isInQuote_ = true;+            quoteChar_ = ch;+            continue;+        }++        if (line.compare(i, 2, "//") == 0)+            break;++        if (line.compare(i, 2, "/*") == 0)+        {+            isInComment_ = true;+            ++i;+            continue;+        }++        if (ch == '{')+        {+            ++braceCount;+            continue;+        }+        if (ch == '}')+        {+            --braceCount;+            if (braceCount == 0)+            {+                // is this an array?+                if (parenStack->back() == 0 && prevCh != '}')+                {+                    size_t peekNum = line.find_first_not_of(" \t", i + 1);+                    if (peekNum != std::string::npos && line[peekNum] == ',')+                        return 2;+                }+                if (!hasText)+                    return 3;	// is an empty block+                return 1;+            }+        }+        if (ch == ';')+            continue;+        if (!std::isblank(ch))+        {+            hasText = true;+            prevCh = ch;+        }+    }++    return 0; }  /**@@ -4154,18 +4538,18 @@ int ASFormatter::isOneLineBlockReached(std::string_view line, int startChar) con  */ bool ASFormatter::isNextWordSharpNonParenHeader(int startChar) const {-	// look ahead to find the next non-comment text-	std::string nextText = peekNextText(currentLine.substr(startChar));-	if (nextText.empty())-		return false;-	if (nextText[0] == '[')-		return true;-	if (!isCharPotentialHeader(nextText, 0))-		return false;-	if (findKeyword(nextText, 0, ASResource::AS_GET) || findKeyword(nextText, 0, ASResource::AS_SET)-	        || findKeyword(nextText, 0, ASResource::AS_ADD) || findKeyword(nextText, 0, ASResource::AS_REMOVE))-		return true;-	return false;+    // look ahead to find the next non-comment text+    std::string nextText = peekNextText(currentLine.substr(startChar));+    if (nextText.empty())+        return false;+    if (nextText[0] == '[')+        return true;+    if (!isCharPotentialHeader(nextText, 0))+        return false;+    if (findKeyword(nextText, 0, ASResource::AS_GET) || findKeyword(nextText, 0, ASResource::AS_SET)+            || findKeyword(nextText, 0, ASResource::AS_ADD) || findKeyword(nextText, 0, ASResource::AS_REMOVE))+        return true;+    return false; }  /**@@ -4178,12 +4562,12 @@ bool ASFormatter::isNextWordSharpNonParenHeader(int startChar) const  */ bool ASFormatter::isNextCharOpeningBrace(int startChar) const {-	bool retVal = false;-	std::string nextText = peekNextText(currentLine.substr(startChar));-	if (!nextText.empty()-	        && nextText.compare(0, 1, "{") == 0)-		retVal = true;-	return retVal;+    bool retVal = false;+    std::string nextText = peekNextText(currentLine.substr(startChar));+    if (!nextText.empty()+            && nextText.compare(0, 1, "{") == 0)+        retVal = true;+    return retVal; }  /**@@ -4194,24 +4578,24 @@ bool ASFormatter::isNextCharOpeningBrace(int startChar) const */ bool ASFormatter::isOperatorPaddingDisabled() const {-	size_t commentStart = currentLine.find("//", charNum);-	if (commentStart == std::string::npos)-	{-		commentStart = currentLine.find("/*", charNum);-		// comment must end on this line-		if (commentStart != std::string::npos)-		{-			size_t commentEnd = currentLine.find("*/", commentStart + 2);-			if (commentEnd == std::string::npos)-				commentStart = std::string::npos;-		}-	}-	if (commentStart == std::string::npos)-		return false;-	size_t noPadStart = currentLine.find("*NOPAD*", commentStart);-	if (noPadStart == std::string::npos)-		return false;-	return true;+    size_t commentStart = currentLine.find("//", charNum);+    if (commentStart == std::string::npos)+    {+        commentStart = currentLine.find("/*", charNum);+        // comment must end on this line+        if (commentStart != std::string::npos)+        {+            size_t commentEnd = currentLine.find("*/", commentStart + 2);+            if (commentEnd == std::string::npos)+                commentStart = std::string::npos;+        }+    }+    if (commentStart == std::string::npos)+        return false;+    size_t noPadStart = currentLine.find("*NOPAD*", commentStart);+    if (noPadStart == std::string::npos)+        return false;+    return true; }  /**@@ -4220,14 +4604,111 @@ bool ASFormatter::isOperatorPaddingDisabled() const */ bool ASFormatter::isUniformInitializerBrace() const {-	if (isCStyle() && !isInEnum && !isImmediatelyPostPreprocessor)-	{-		if (isInClassInitializer-		        || isLegalNameChar(previousNonWSChar)-		        || previousNonWSChar == '(')-			return true;-	}-	return false;+    if (isCStyle() && !isInEnum && !isImmediatelyPostPreprocessor)+    {+        if (isInClassInitializer+                || isLegalNameChar(previousNonWSChar)+                || previousNonWSChar == '('+                || previousNonWSChar == '[')+            return true;+    }+    return false;+}++/**+* Determine if the current ':' starts the partition name of a C++20 module import,+* like 'import :part;' or 'export import :part;'.+* 'import' must be at the start of a statement at file scope,+* optionally preceded by 'export'.+*/+bool ASFormatter::isModuleImportColon() const+{+    assert(currentChar == ':');+    if (braceTypeStack->size() != 1+            || getPreviousWord(currentLine, charNum) != "import")+        return false;++    size_t statementStart = currentLine.rfind("import", charNum);+    if (getPreviousWord(currentLine, (int) statementStart) == "export")+        statementStart = currentLine.rfind("export", statementStart);++    size_t prevChar = statementStart == 0+                      ? std::string::npos+                      : currentLine.find_last_not_of(" \t", statementStart - 1);+    return prevChar == std::string::npos || currentLine[prevChar] == ';';+}++/**+* Determine if the current '{' opens the body of a C++ lambda with a parameter list,+* like '[&](int v) {', '[](auto x) mutable -> int {' or '[]<typename T>(T x) {'.+* The whole lambda introducer must be on the current line.+*/+bool ASFormatter::isLambdaBodyWithParamsBrace() const+{+    assert(currentChar == '{');+    if (!isCStyle() || isObjCStyle())+        return false;++    // move back over whitespace, returns -1 at the line start+    auto skipSpaceBack = [this](int pos) {+        while (pos >= 0 && (currentLine[pos] == ' ' || currentLine[pos] == '\t'))+            --pos;+        return pos;+    };+    // move back from a closing char to its matching opening char, returns -1 if not found+    auto findOpeningBack = [this](int pos, char openCh, char closeCh) {+        int depth = 0;+        for (; pos >= 0; --pos)+        {+            if (currentLine[pos] == closeCh)+                ++depth;+            else if (currentLine[pos] == openCh && --depth == 0)+                return pos;+        }+        return -1;+    };++    // specifiers and trailing return type: 'mutable', 'noexcept', '-> std::vector<int>&'+    int pos = skipSpaceBack(charNum - 1);+    while (pos >= 0 && currentLine[pos] != ')')+    {+        char ch = currentLine[pos];+        if (!(isLegalNameChar(ch) || ch == ' ' || ch == '\t' || ch == ':' || ch == '<' || ch == '>'+                || ch == '&' || ch == '*' || ch == ',' || ch == '-'))+            return false;+        --pos;+    }+    if (pos < 0)+        return false;++    // parameter list+    pos = findOpeningBack(pos, '(', ')');+    if (pos < 0)+        return false;+    pos = skipSpaceBack(pos - 1);++    // optional template parameter list of a generic lambda+    if (pos >= 0 && currentLine[pos] == '>')+    {+        pos = findOpeningBack(pos, '<', '>');+        if (pos < 0)+            return false;+        pos = skipSpaceBack(pos - 1);+    }++    // capture list+    if (pos < 0 || currentLine[pos] != ']')+        return false;+    pos = findOpeningBack(pos, '[', ']');+    if (pos < 0)+        return false;++    // a '[' following a name, ']' or ')' is a subscript or 'operator[]', '[[' is an attribute+    int prev = skipSpaceBack(pos - 1);+    if (prev < 0)+        return true;+    char prevCh = currentLine[prev];+    return !isLegalNameChar(prevCh) && prevCh != ']' && prevCh != ')' && prevCh != '['; }  /**@@ -4235,72 +4716,72 @@ bool ASFormatter::isUniformInitializerBrace() const */ bool ASFormatter::isMultiStatementLine() const {-	assert((isImmediatelyPostHeader || foundClosingHeader));-	bool isInComment_ = false;-	bool isInQuote_ = false;-	int  semiCount_ = 0;-	int  parenCount_ = 0;-	int  braceCount_ = 0;--	for (size_t i = 0; i < currentLine.length(); i++)-	{-		if (isInComment_)-		{-			if (currentLine.compare(i, 2, "*/") == 0)-			{-				isInComment_ = false;-				continue;-			}-		}-		if (currentLine.compare(i, 2, "/*") == 0)-		{-			isInComment_ = true;-			continue;-		}-		if (currentLine.compare(i, 2, "//") == 0)-			return false;-		if (isInQuote_)-		{-			if (currentLine[i] == '"' || currentLine[i] == '\'')-				isInQuote_ = false;-			continue;-		}-		if (currentLine[i] == '"' || currentLine[i] == '\'')-		{-			isInQuote_ = true;-			continue;-		}-		if (currentLine[i] == '(')-		{-			++parenCount_;-			continue;-		}-		if (currentLine[i] == ')')-		{-			--parenCount_;-			continue;-		}-		if (parenCount_ > 0)-			continue;-		if (currentLine[i] == '{')-		{-			++braceCount_;-		}-		if (currentLine[i] == '}')-		{-			--braceCount_;-		}-		if (braceCount_ > 0)-			continue;-		if (currentLine[i] == ';')-		{-			++semiCount_;-			if (semiCount_ > 1)-				return true;-			continue;-		}-	}-	return false;+    assert((isImmediatelyPostHeader || foundClosingHeader));+    bool isInComment_ = false;+    bool isInQuote_ = false;+    int  semiCount_ = 0;+    int  parenCount_ = 0;+    int  braceCount_ = 0;++    for (size_t i = 0; i < currentLine.length(); i++)+    {+        if (isInComment_)+        {+            if (currentLine.compare(i, 2, "*/") == 0)+            {+                isInComment_ = false;+                continue;+            }+        }+        if (currentLine.compare(i, 2, "/*") == 0)+        {+            isInComment_ = true;+            continue;+        }+        if (currentLine.compare(i, 2, "//") == 0)+            return false;+        if (isInQuote_)+        {+            if (currentLine[i] == '"' || currentLine[i] == '\'')+                isInQuote_ = false;+            continue;+        }+        if (currentLine[i] == '"' || currentLine[i] == '\'')+        {+            isInQuote_ = true;+            continue;+        }+        if (currentLine[i] == '(')+        {+            ++parenCount_;+            continue;+        }+        if (currentLine[i] == ')')+        {+            --parenCount_;+            continue;+        }+        if (parenCount_ > 0)+            continue;+        if (currentLine[i] == '{')+        {+            ++braceCount_;+        }+        if (currentLine[i] == '}')+        {+            --braceCount_;+        }+        if (braceCount_ > 0)+            continue;+        if (currentLine[i] == ';')+        {+            ++semiCount_;+            if (semiCount_ > 1)+                return true;+            continue;+        }+    }+    return false; }  /**@@ -4313,61 +4794,61 @@ std::string ASFormatter::peekNextText(std::string_view firstLine,                                       bool endOnEmptyLine /*false*/,                                       const std::shared_ptr<ASPeekStream>& streamArg /*nullptr*/) const {-	assert(sourceIterator->getPeekStart() == 0 || streamArg != nullptr);	// Borland may need != 0-	bool isFirstLine = true;-	std::string nextLine_(firstLine);-	size_t firstChar = std::string::npos;-	std::shared_ptr<ASPeekStream> stream = streamArg;-	if (stream == nullptr)					// Borland may need == 0-		stream = std::make_shared<ASPeekStream>(sourceIterator);--	// find the first non-blank text, bypassing all comments.-	bool isInComment_ = false;-	while (stream->hasMoreLines() || isFirstLine)-	{-		if (isFirstLine)-			isFirstLine = false;-		else-			nextLine_ = stream->peekNextLine();--		firstChar = nextLine_.find_first_not_of(" \t");-		if (firstChar == std::string::npos)-		{-			if (endOnEmptyLine && !isInComment_)-				break;-			continue;-		}--		if (nextLine_.compare(firstChar, 2, "/*") == 0)-		{-			firstChar += 2;-			isInComment_ = true;-		}--		if (isInComment_)-		{-			firstChar = nextLine_.find("*/", firstChar);-			if (firstChar == std::string::npos)-				continue;-			firstChar += 2;-			isInComment_ = false;-			firstChar = nextLine_.find_first_not_of(" \t", firstChar);-			if (firstChar == std::string::npos)-				continue;-		}--		if (nextLine_.compare(firstChar, 2, "//") == 0)-			continue;--		// found the next text-		break;-	}--	if (firstChar == std::string::npos)-		nextLine_ = "";-	else-		nextLine_ = nextLine_.substr(firstChar);-	return nextLine_;+    assert(sourceIterator->getPeekStart() == 0 || streamArg != nullptr);	// Borland may need != 0+    bool isFirstLine = true;+    std::string nextLine_(firstLine);+    size_t firstChar = std::string::npos;+    std::shared_ptr<ASPeekStream> stream = streamArg;+    if (stream == nullptr)					// Borland may need == 0+        stream = std::make_shared<ASPeekStream>(sourceIterator);++    // find the first non-blank text, bypassing all comments.+    bool isInComment_ = false;+    while (stream->hasMoreLines() || isFirstLine)+    {+        if (isFirstLine)+            isFirstLine = false;+        else+            nextLine_ = stream->peekNextLine();++        firstChar = nextLine_.find_first_not_of(" \t");+        if (firstChar == std::string::npos)+        {+            if (endOnEmptyLine && !isInComment_)+                break;+            continue;+        }++        if (nextLine_.compare(firstChar, 2, "/*") == 0)+        {+            firstChar += 2;+            isInComment_ = true;+        }++        if (isInComment_)+        {+            firstChar = nextLine_.find("*/", firstChar);+            if (firstChar == std::string::npos)+                continue;+            firstChar += 2;+            isInComment_ = false;+            firstChar = nextLine_.find_first_not_of(" \t", firstChar);+            if (firstChar == std::string::npos)+                continue;+        }++        if (nextLine_.compare(firstChar, 2, "//") == 0)+            continue;++        // found the next text+        break;+    }++    if (firstChar == std::string::npos)+        nextLine_ = "";+    else+        nextLine_ = nextLine_.substr(firstChar);+    return nextLine_; }  /**@@ -4377,49 +4858,49 @@ std::string ASFormatter::peekNextText(std::string_view firstLine,  */ void ASFormatter::adjustComments() {-	assert(spacePadNum != 0);-	assert(isSequenceReached(ASResource::AS_OPEN_LINE_COMMENT) || isSequenceReached(ASResource::AS_OPEN_COMMENT)  || isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT));--	// block comment must be closed on this line with nothing after it-	bool isCppComment = isSequenceReached(ASResource::AS_OPEN_COMMENT);-	bool isGSCComment = isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT);--	if (isCppComment || isGSCComment)-	{-		size_t endNum = currentLine.find(isCppComment ? ASResource::AS_CLOSE_COMMENT : ASResource::AS_GSC_CLOSE_COMMENT, charNum + 2);-		if (endNum == std::string::npos)-			return;-		// following line comments may be a tag from AStyleWx //[[)>-		size_t nextNum = currentLine.find_first_not_of(" \t", endNum + 2);-		if (nextNum != std::string::npos-		        && currentLine.compare(nextNum, 2, ASResource::AS_OPEN_LINE_COMMENT) != 0)-			return;-	}--	size_t len = formattedLine.length();-	// don't adjust a tab-	if (formattedLine[len - 1] == '\t')-		return;-	// if spaces were removed, need to add spaces before the comment-	if (spacePadNum < 0)-	{-		int adjust = -spacePadNum;          // make the number positive-		formattedLine.append(adjust, ' ');-	}-	// if spaces were added, need to delete extra spaces before the comment-	// if cannot be done put the comment one space after the last text-	else if (spacePadNum > 0)-	{-		int adjust = spacePadNum;-		size_t lastText = formattedLine.find_last_not_of(' ');-		if (lastText != std::string::npos-		        && lastText < len - adjust - 1)-			formattedLine.resize(len - adjust);-		else if (len > lastText + 2)-			formattedLine.resize(lastText + 2);-		else if (len < lastText + 2)-			formattedLine.append(len - lastText, ' ');-	}+    assert(spacePadNum != 0);+    assert(isSequenceReached(ASResource::AS_OPEN_LINE_COMMENT) || isSequenceReached(ASResource::AS_OPEN_COMMENT)  || isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT));++    // block comment must be closed on this line with nothing after it+    bool isCppComment = isSequenceReached(ASResource::AS_OPEN_COMMENT);+    bool isGSCComment = isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT);++    if (isCppComment || isGSCComment)+    {+        size_t endNum = currentLine.find(isCppComment ? ASResource::AS_CLOSE_COMMENT : ASResource::AS_GSC_CLOSE_COMMENT, charNum + 2);+        if (endNum == std::string::npos)+            return;+        // following line comments may be a tag from AStyleWx //[[)>+        size_t nextNum = currentLine.find_first_not_of(" \t", endNum + 2);+        if (nextNum != std::string::npos+                && currentLine.compare(nextNum, 2, ASResource::AS_OPEN_LINE_COMMENT) != 0)+            return;+    }++    size_t len = formattedLine.length();+    // don't adjust a tab+    if (formattedLine[len - 1] == '\t')+        return;+    // if spaces were removed, need to add spaces before the comment+    if (spacePadNum < 0)+    {+        int adjust = -spacePadNum;          // make the number positive+        formattedLine.append(adjust, ' ');+    }+    // if spaces were added, need to delete extra spaces before the comment+    // if cannot be done put the comment one space after the last text+    else if (spacePadNum > 0)+    {+        int adjust = spacePadNum;+        size_t lastText = formattedLine.find_last_not_of(' ');+        if (lastText != std::string::npos+                && lastText < len - adjust - 1)+            formattedLine.resize(len - adjust);+        else if (len > lastText + 2)+            formattedLine.resize(lastText + 2);+        else if (len < lastText + 2)+            formattedLine.append(len - lastText, ' ');+    } }  /**@@ -4429,37 +4910,37 @@ void ASFormatter::adjustComments()  */ void ASFormatter::appendCharInsideComments() {-	if (formattedLineCommentNum == std::string::npos     // does the comment start on the previous line?-	        || formattedLineCommentNum == 0)-	{-		appendCurrentChar();                        // don't attach-		return;-	}-	assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0-	       || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0);--	// find the previous non space char-	size_t end = formattedLineCommentNum;-	size_t beg = formattedLine.find_last_not_of(" \t", end - 1);-	if (beg == std::string::npos)-	{-		appendCurrentChar();                // don't attach-		return;-	}-	beg++;--	// insert the brace-	if (end - beg < 3)                      // is there room to insert?-		formattedLine.insert(beg, 3 - end + beg, ' ');-	if (formattedLine[beg] == '\t')         // don't pad with a tab-		formattedLine.insert(beg, 1, ' ');-	formattedLine[beg + 1] = currentChar;-	testForTimeToSplitFormattedLine();--	if (isBeforeComment())-		breakLine();-	else if (isCharImmediatelyPostLineComment)-		shouldBreakLineAtNextChar = true;+    if (formattedLineCommentNum == std::string::npos     // does the comment start on the previous line?+            || formattedLineCommentNum == 0)+    {+        appendCurrentChar();                        // don't attach+        return;+    }+    assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0+           || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0);++    // find the previous non space char+    size_t end = formattedLineCommentNum;+    size_t beg = formattedLine.find_last_not_of(" \t", end - 1);+    if (beg == std::string::npos)+    {+        appendCurrentChar();                // don't attach+        return;+    }+    beg++;++    // insert the brace+    if (end - beg < 3)                      // is there room to insert?+        formattedLine.insert(beg, 3 - end + beg, ' ');+    if (formattedLine[beg] == '\t')         // don't pad with a tab+        formattedLine.insert(beg, 1, ' ');+    formattedLine[beg + 1] = currentChar;+    testForTimeToSplitFormattedLine();++    if (isBeforeComment())+        breakLine();+    else if (isCharImmediatelyPostLineComment)+        shouldBreakLineAtNextChar = true; }  /**@@ -4471,96 +4952,96 @@ void ASFormatter::appendCharInsideComments()  */ void ASFormatter::padOperators(const std::string* newOperator) {-	assert(shouldPadOperators || negationPadMode != NEGATION_PAD_NO_CHANGE);-	assert(newOperator != nullptr);--	char nextNonWSChar = ASBase::peekNextChar(currentLine, charNum);-	std::set<char> allowedChars = {'(', '[', '=', ',', ':', '{'};--	bool isUnaryOrModOperator = (newOperator == &ASResource::AS_PLUS ||-	                             newOperator == &ASResource::AS_MINUS ||-	                             (newOperator == &ASResource::AS_MOD && isGSCStyle()));--	bool isExponentOperator = (newOperator == &ASResource::AS_MINUS && isInExponent()) ||-	                          (newOperator == &ASResource::AS_PLUS && isInExponent());--	bool isSpecialColon = (newOperator == &ASResource::AS_COLON && !foundQuestionMark &&-	                       (isInObjCMethodDefinition || isInObjCInterface || isInObjCSelector || squareBracketCount != 0));--	bool isJavaWildcard = (newOperator == &ASResource::AS_QUESTION && isJavaStyle() &&-	                       (previousNonWSChar == '<' || nextNonWSChar == '>' || nextNonWSChar == '.'));--	bool isSharpNullConditional = (newOperator == &ASResource::AS_QUESTION && isSharpStyle() &&-	                               (nextNonWSChar == '.' || nextNonWSChar == '['));--	bool isSpecialTemplateOperator = (isInTemplate || isImmediatelyPostTemplate || isSharpStyle()) &&-	                                 (newOperator == &ASResource::AS_LS || newOperator == &ASResource::AS_GR);--	std::string sBegin = currentLine.substr(0, charNum);-	std::string sEnd = currentLine.substr(charNum, currentLine.find_first_not_of(">", charNum + 1));--	auto numOfOpeningBrackets = std::count(sBegin.begin(), sBegin.end(), '<');-	auto numOfClosingBrackets = std::count(sEnd.begin(), sEnd.end(), '>');--	bool isClosingTemplateDefinition = numOfClosingBrackets >= numOfOpeningBrackets && numOfOpeningBrackets >= 2;--	bool shouldPad = (newOperator != &ASResource::AS_SCOPE_RESOLUTION &&-	                  newOperator != &ASResource::AS_PLUS_PLUS &&-	                  newOperator != &ASResource::AS_MINUS_MINUS &&-	                  (newOperator != &ASResource::AS_NOT || negationPadMode != NEGATION_PAD_NO_CHANGE) &&-	                  newOperator != &ASResource::AS_BIT_NOT &&-	                  newOperator != &ASResource::AS_ARROW &&-	                  !isSpecialColon &&-	                  !isExponentOperator &&-	                  !isClosingTemplateDefinition &&-	                  !(newOperator == &ASResource::AS_GR && previousChar == '-') &&-	                  !(isUnaryOrModOperator && (allowedChars.find(previousNonWSChar) != allowedChars.end())) &&-	                  !(newOperator == &ASResource::AS_MULT &&-	                    (previousNonWSChar == '.' || previousNonWSChar == '>')) &&-	                  !(newOperator == &ASResource::AS_MULT && peekNextChar() == '>') &&-	                  !isSpecialTemplateOperator &&-	                  !(newOperator == &ASResource::AS_GCC_MIN_ASSIGN &&-	                    ASBase::peekNextChar(currentLine, charNum + 1) == '>') &&-	                  !(newOperator == &ASResource::AS_GR && previousNonWSChar == '?') &&-	                  !isJavaWildcard &&-	                  !isSharpNullConditional &&-	                  !isCharImmediatelyPostOperator &&-	                  !isInCase &&-	                  !isInAsm &&-	                  !isInAsmOneLine &&-	                  !isInAsmBlock);--	// pad before operator-	if (shouldPad-	        && (newOperator != &ASResource::AS_NOT || (newOperator == &ASResource::AS_NOT && negationPadMode == NEGATION_PAD_BEFORE ) )-	        && !(newOperator == &ASResource::AS_COLON-	             && (!foundQuestionMark && !isInEnum) && currentHeader != &ASResource::AS_FOR)-	        && !(newOperator == &ASResource::AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)-	             && currentLine.find(':', charNum + 1) == std::string::npos)-	   )-	{-		appendSpacePad();-	}--	appendOperator(*newOperator);-	goForward(newOperator->length() - 1);--	currentChar = (*newOperator)[newOperator->length() - 1];-	// pad after operator-	// but do not pad after a '-' that is a unary-minus.-	if (shouldPad-	        && !isBeforeAnyComment()-	        && !(newOperator == &ASResource::AS_PLUS && isUnaryOperator())-	        && !(newOperator == &ASResource::AS_MINUS && isUnaryOperator())-	        && !(currentLine.compare(charNum + 1, 1, ASResource::AS_SEMICOLON) == 0)-	        && !(currentLine.compare(charNum + 1, 2, ASResource::AS_SCOPE_RESOLUTION) == 0)-	        && !(peekNextChar() == ',')-	        && !(newOperator == &ASResource::AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)-	             && peekNextChar() == '[')-	   )-	{-		appendSpaceAfter();-	}+    assert(shouldPadOperators || negationPadMode != NEGATION_PAD_NO_CHANGE);+    assert(newOperator != nullptr);++    char nextNonWSChar = ASBase::peekNextChar(currentLine, charNum);+    std::set<char> allowedChars = {'(', '[', '=', ',', ':', '{'};++    bool isUnaryOrModOperator = (newOperator == &ASResource::AS_PLUS ||+                                 newOperator == &ASResource::AS_MINUS ||+                                 (newOperator == &ASResource::AS_MOD && isGSCStyle()));++    bool isExponentOperator = (newOperator == &ASResource::AS_MINUS && isInExponent()) ||+                              (newOperator == &ASResource::AS_PLUS && isInExponent());++    bool isSpecialColon = (newOperator == &ASResource::AS_COLON && !foundQuestionMark &&+                           (isInObjCMethodDefinition || isInObjCInterface || isInObjCSelector || squareBracketCount != 0));++    bool isJavaWildcard = (newOperator == &ASResource::AS_QUESTION && isJavaStyle() &&+                           (previousNonWSChar == '<' || nextNonWSChar == '>' || nextNonWSChar == '.'));++    bool isSharpNullConditional = (newOperator == &ASResource::AS_QUESTION && isSharpStyle() &&+                                   (nextNonWSChar == '.' || nextNonWSChar == '['));++    bool isSpecialTemplateOperator = (isInTemplate || isImmediatelyPostTemplate || isSharpStyle()) &&+                                     (newOperator == &ASResource::AS_LS || newOperator == &ASResource::AS_GR);++    std::string sBegin = currentLine.substr(0, charNum);+    std::string sEnd = currentLine.substr(charNum, currentLine.find_first_not_of(">", charNum + 1));++    auto numOfOpeningBrackets = std::count(sBegin.begin(), sBegin.end(), '<');+    auto numOfClosingBrackets = std::count(sEnd.begin(), sEnd.end(), '>');++    bool isClosingTemplateDefinition = numOfClosingBrackets >= numOfOpeningBrackets && numOfOpeningBrackets >= 2;++    bool shouldPad = (newOperator != &ASResource::AS_SCOPE_RESOLUTION &&+                      newOperator != &ASResource::AS_PLUS_PLUS &&+                      newOperator != &ASResource::AS_MINUS_MINUS &&+                      (newOperator != &ASResource::AS_NOT || negationPadMode != NEGATION_PAD_NO_CHANGE) &&+                      newOperator != &ASResource::AS_BIT_NOT &&+                      newOperator != &ASResource::AS_ARROW &&+                      !isSpecialColon &&+                      !isExponentOperator &&+                      !isClosingTemplateDefinition &&+                      !(newOperator == &ASResource::AS_GR && previousChar == '-') &&+                      !(isUnaryOrModOperator && (allowedChars.find(previousNonWSChar) != allowedChars.end())) &&+                      !(newOperator == &ASResource::AS_MULT &&+                        (previousNonWSChar == '.' || previousNonWSChar == '>')) &&+                      !(newOperator == &ASResource::AS_MULT && peekNextChar() == '>') &&+                      !isSpecialTemplateOperator &&+                      !(newOperator == &ASResource::AS_GCC_MIN_ASSIGN &&+                        ASBase::peekNextChar(currentLine, charNum + 1) == '>') &&+                      !(newOperator == &ASResource::AS_GR && previousNonWSChar == '?') &&+                      !isJavaWildcard &&+                      !isSharpNullConditional &&+                      !isCharImmediatelyPostOperator &&+                      !isInCase &&+                      !isInAsm &&+                      !isInAsmOneLine &&+                      !isInAsmBlock);++    // pad before operator+    if (shouldPad+            && (newOperator != &ASResource::AS_NOT || (newOperator == &ASResource::AS_NOT && negationPadMode == NEGATION_PAD_BEFORE ) )+            && !(newOperator == &ASResource::AS_COLON+                 && (!foundQuestionMark && !isInEnum) && currentHeader != &ASResource::AS_FOR)+            && !(newOperator == &ASResource::AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)+                 && currentLine.find(':', charNum + 1) == std::string::npos)+       )+    {+        appendSpacePad();+    }++    appendOperator(*newOperator);+    goForward(newOperator->length() - 1);++    currentChar = (*newOperator)[newOperator->length() - 1];+    // pad after operator+    // but do not pad after a '-' that is a unary-minus.+    if (shouldPad+            && !isBeforeAnyComment()+            && !(newOperator == &ASResource::AS_PLUS && isUnaryOperator())+            && !(newOperator == &ASResource::AS_MINUS && isUnaryOperator())+            && !(currentLine.compare(charNum + 1, 1, ASResource::AS_SEMICOLON) == 0)+            && !(currentLine.compare(charNum + 1, 2, ASResource::AS_SCOPE_RESOLUTION) == 0)+            && !(peekNextChar() == ',')+            && !(newOperator == &ASResource::AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)+                 && peekNextChar() == '[')+       )+    {+        appendSpaceAfter();+    } }  /**@@ -4574,77 +5055,77 @@ void ASFormatter::padOperators(const std::string* newOperator)  */ void ASFormatter::formatPointerOrReference() {-	assert(currentChar == '*' || currentChar == '&' || currentChar == '^');-	assert(!isJavaStyle());--	int pa = pointerAlignment;-	int ra = referenceAlignment;-	int itemAlignment = (currentChar == '*' || currentChar == '^')-	                    ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);--	// handle operator char*() {};-	if (currentChar == '*' && isCStyle() && currentLine.find("operator") != std::string::npos)-	{-		formattedLine.append("*");-		return;-	}--	// check for ** and &&-	int ptrLength = 1;-	char peekedChar = peekNextChar();-	if ((currentChar == '*' && peekedChar == '*')-	        || (currentChar == '&' && peekedChar == '&'))-	{-		ptrLength = 2;--		//TODO check-		size_t nextChar = currentLine.find_first_not_of(" \t", charNum + 2);-		if (nextChar == std::string::npos)-			peekedChar = ' ';-		else-			peekedChar = currentLine[nextChar];--		//https://sourceforge.net/p/astyle/bugs/543/-		if (currentChar == '&' /*&& itemAlignment == PTR_ALIGN_NAME*/)-		{-			itemAlignment = PTR_ALIGN_NONE;-		}-	}-	// check for cast-	if (peekedChar == ')' || peekedChar == '>' || peekedChar == ',')-	{-		formatPointerOrReferenceCast();-		return;-	}--	// check for a padded space and remove it-	if (charNum > 0-	        && !std::isblank(currentLine[charNum - 1])-	        && !formattedLine.empty()-	        && std::isblank(formattedLine[formattedLine.length() - 1]))-	{-		formattedLine.erase(formattedLine.length() - 1);-		spacePadNum--;-	}--	if (itemAlignment == PTR_ALIGN_TYPE)-	{-		formatPointerOrReferenceToType();-	}-	else if (itemAlignment == PTR_ALIGN_MIDDLE)-	{-		formatPointerOrReferenceToMiddle();-	}-	else if (itemAlignment == PTR_ALIGN_NAME)-	{-		formatPointerOrReferenceToName();-	}-	else	// pointerAlignment == PTR_ALIGN_NONE-	{-		formattedLine.append(currentLine.substr(charNum, ptrLength));-		if (ptrLength > 1)-			goForward(ptrLength - 1);-	}+    assert(currentChar == '*' || currentChar == '&' || currentChar == '^');+    assert(!isJavaStyle());++    int pa = pointerAlignment;+    int ra = referenceAlignment;+    int itemAlignment = (currentChar == '*' || currentChar == '^')+                        ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);++    // handle operator char*() {};+    if (currentChar == '*' && isCStyle() && currentLine.find("operator") != std::string::npos)+    {+        formattedLine.append("*");+        return;+    }++    // check for ** and &&+    int ptrLength = 1;+    char peekedChar = peekNextChar();+    if ((currentChar == '*' && peekedChar == '*')+            || (currentChar == '&' && peekedChar == '&'))+    {+        ptrLength = 2;++        //TODO check+        size_t nextChar = currentLine.find_first_not_of(" \t", charNum + 2);+        if (nextChar == std::string::npos)+            peekedChar = ' ';+        else+            peekedChar = currentLine[nextChar];++        //https://sourceforge.net/p/astyle/bugs/543/+        if (currentChar == '&' /*&& itemAlignment == PTR_ALIGN_NAME*/)+        {+            itemAlignment = PTR_ALIGN_NONE;+        }+    }+    // check for cast+    if (peekedChar == ')' || peekedChar == '>' || peekedChar == ',')+    {+        formatPointerOrReferenceCast();+        return;+    }++    // check for a padded space and remove it+    if (charNum > 0+            && !std::isblank(currentLine[charNum - 1])+            && !formattedLine.empty()+            && std::isblank(formattedLine[formattedLine.length() - 1]))+    {+        formattedLine.erase(formattedLine.length() - 1);+        spacePadNum--;+    }++    if (itemAlignment == PTR_ALIGN_TYPE)+    {+        formatPointerOrReferenceToType();+    }+    else if (itemAlignment == PTR_ALIGN_MIDDLE)+    {+        formatPointerOrReferenceToMiddle();+    }+    else if (itemAlignment == PTR_ALIGN_NAME)+    {+        formatPointerOrReferenceToName();+    }+    else	// pointerAlignment == PTR_ALIGN_NONE+    {+        formattedLine.append(currentLine.substr(charNum, ptrLength));+        if (ptrLength > 1)+            goForward(ptrLength - 1);+    } }  /**@@ -4652,69 +5133,69 @@ void ASFormatter::formatPointerOrReference()  */ void ASFormatter::formatPointerOrReferenceToType() {-	assert(currentChar == '*' || currentChar == '&' || currentChar == '^');-	assert(!isJavaStyle());--	// do this before bumping charNum-	bool isOldPRCentered = isPointerOrReferenceCentered();-	std::string sequenceToInsert(1, currentChar);-	// get the sequence-	if (currentChar == peekNextChar())-	{-		for (size_t i = charNum + 1; currentLine.length() > i; i++)-		{-			if (currentLine[i] == sequenceToInsert[0])-			{-				sequenceToInsert.append(1, currentLine[i]);-				goForward(1);-				continue;-			}-			break;-		}-	}-	// append the sequence-	std::string charSave;-	size_t prevCh = formattedLine.find_last_not_of(" \t");-	if (prevCh < formattedLine.length())-	{-		charSave = formattedLine.substr(prevCh + 1);-		formattedLine.resize(prevCh + 1);-	}--	// https://sourceforge.net/p/astyle/bugs/537/-	// TODO check-	if ((previousNonWSChar == ',' || previousNonWSChar == '[') && currentChar != ' ')-		appendSpacePad();--	formattedLine.append(sequenceToInsert);-	if (peekNextChar() != ')')-		formattedLine.append(charSave);-	else-		spacePadNum -= charSave.length();-	// if no space after then add one-	if (charNum < (int) currentLine.length() - 1-	        && !std::isblank(currentLine[charNum + 1])-	        && currentLine[charNum + 1] != ')'-		    && peekNextChar() != '&')-		appendSpacePad();--	// if old pointer or reference is centered, remove a space-	if (isOldPRCentered-	        && std::isblank(formattedLine[formattedLine.length() - 1]))-	{-		formattedLine.erase(formattedLine.length() - 1, 1);-		spacePadNum--;-	}-	// update the formattedLine split point-	if (maxCodeLength != std::string::npos && !formattedLine.empty())-	{-		size_t index = formattedLine.length() - 1;-		if (std::isblank(formattedLine[index]))-		{-			updateFormattedLineSplitPointsPointerOrReference(index);-			testForTimeToSplitFormattedLine();-		}-	}+    assert(currentChar == '*' || currentChar == '&' || currentChar == '^');+    assert(!isJavaStyle());++    // do this before bumping charNum+    bool isOldPRCentered = isPointerOrReferenceCentered();+    std::string sequenceToInsert(1, currentChar);+    // get the sequence+    if (currentChar == peekNextChar())+    {+        for (size_t i = charNum + 1; currentLine.length() > i; i++)+        {+            if (currentLine[i] == sequenceToInsert[0])+            {+                sequenceToInsert.append(1, currentLine[i]);+                goForward(1);+                continue;+            }+            break;+        }+    }+    // append the sequence+    std::string charSave;+    size_t prevCh = formattedLine.find_last_not_of(" \t");+    if (prevCh < formattedLine.length())+    {+        charSave = formattedLine.substr(prevCh + 1);+        formattedLine.resize(prevCh + 1);+    }++    // https://sourceforge.net/p/astyle/bugs/537/+    // TODO check+    if ((previousNonWSChar == ',' || previousNonWSChar == '[') && currentChar != ' ')+        appendSpacePad();++    formattedLine.append(sequenceToInsert);+    if (peekNextChar() != ')')+        formattedLine.append(charSave);+    else+        spacePadNum -= charSave.length();+    // if no space after then add one+    if (charNum < (int) currentLine.length() - 1+            && !std::isblank(currentLine[charNum + 1])+            && currentLine[charNum + 1] != ')'+            && peekNextChar() != '&')+        appendSpacePad();++    // if old pointer or reference is centered, remove a space+    if (isOldPRCentered+            && std::isblank(formattedLine[formattedLine.length() - 1]))+    {+        formattedLine.erase(formattedLine.length() - 1, 1);+        spacePadNum--;+    }+    // update the formattedLine split point+    if (maxCodeLength != std::string::npos && !formattedLine.empty())+    {+        size_t index = formattedLine.length() - 1;+        if (std::isblank(formattedLine[index]))+        {+            updateFormattedLineSplitPointsPointerOrReference(index);+            testForTimeToSplitFormattedLine();+        }+    } }  /**@@ -4722,136 +5203,136 @@ void ASFormatter::formatPointerOrReferenceToType()  */ void ASFormatter::formatPointerOrReferenceToMiddle() {-	assert(currentChar == '*' || currentChar == '&' || currentChar == '^');-	assert(!isJavaStyle());--	if (currentLine.size() > (size_t)charNum + 1 &&-	        std::isblank(currentLine[charNum - 1]) &&-	        std::isblank(currentLine[charNum + 1]))-	{--		std::string seq = {currentChar, currentLine[charNum + 1]};-		appendSequence(seq);-		goForward(1);-		return;-	}--	// compute current whitespace before-	size_t wsBefore = currentLine.find_last_not_of(" \t", charNum - 1);-	if (wsBefore == std::string::npos)-		wsBefore = 0;-	else-		wsBefore = charNum - wsBefore - 1;-	std::string sequenceToInsert(1, currentChar);--	if (currentChar == peekNextChar())-	{-		for (size_t i = charNum + 1; currentLine.length() > i; i++)-		{-			if (currentLine[i] == sequenceToInsert[0])-			{-				sequenceToInsert.append(1, currentLine[i]);-				goForward(1);-				continue;-			}-			break;-		}-	}-	// if reference to a pointer check for conflicting alignment-	else if (currentChar == '*' && peekNextChar() == '&'-	         && ASBeautifier::peekNextChar(currentLine, charNum + 1) != '&'-	         && (referenceAlignment == REF_ALIGN_TYPE-	             || referenceAlignment == REF_ALIGN_MIDDLE-	             || referenceAlignment == REF_SAME_AS_PTR))-	{-		sequenceToInsert = "*&";-		goForward(1);-		for (size_t i = charNum; i < currentLine.length() - 1 && std::isblank(currentLine[i]); i++)-			goForward(1);-	}-	// if a comment follows don't align, just space pad-	if (isBeforeAnyComment())-	{-		appendSpacePad();-		formattedLine.append(sequenceToInsert);-		appendSpaceAfter();-		return;-	}-	// do this before goForward()-	bool isAfterScopeResolution = previousNonWSChar == ':';-	size_t charNumSave = charNum;-	// if this is the last thing on the line-	if (currentLine.find_first_not_of(" \t", charNum + 1) == std::string::npos)-	{-		if (wsBefore == 0 && !isAfterScopeResolution)-			formattedLine.append(1, ' ');-		formattedLine.append(sequenceToInsert);-		return;-	}-	// goForward() to convert tabs to spaces, if necessary,-	// and move following characters to preceding characters-	// this may not work every time with tab characters-	for (size_t i = charNum + 1; i < currentLine.length() && std::isblank(currentLine[i]); i++)-	{-		goForward(1);-		if (!formattedLine.empty())-			formattedLine.append(1, currentLine[i]);-		else-			spacePadNum--;-	}-	// find space padding after-	size_t wsAfter = currentLine.find_first_not_of(" \t", charNumSave + 1);-	if (wsAfter == std::string::npos || isBeforeAnyComment())-		wsAfter = 0;-	else-		wsAfter = wsAfter - charNumSave - 1;-	// don't pad before scope resolution operator, but pad after-	if (isAfterScopeResolution)-	{-		size_t lastText = formattedLine.find_last_not_of(" \t");-		formattedLine.insert(lastText + 1, sequenceToInsert);-		appendSpacePad();-	}-	else if (!formattedLine.empty())-	{-		// whitespace should be at least 2 chars to center-		if (wsBefore + wsAfter < 2)-		{-			size_t charsToAppend = (2 - (wsBefore + wsAfter));-			formattedLine.append(charsToAppend, ' ');-			spacePadNum += charsToAppend;-			if (wsBefore == 0)-				wsBefore++;-			if (wsAfter == 0)-				wsAfter++;-		}-		// insert the pointer or reference char-		size_t padAfter = (wsBefore + wsAfter) / 2;-		size_t index = formattedLine.length() - padAfter;-		if (index < formattedLine.length())-			formattedLine.insert(index, sequenceToInsert);-		else-			formattedLine.append(sequenceToInsert);-	}-	else	// formattedLine.length() == 0-	{-		formattedLine.append(sequenceToInsert);-		if (wsAfter == 0)-			wsAfter++;-		formattedLine.append(wsAfter, ' ');-		spacePadNum += wsAfter;-	}-	// update the formattedLine split point after the pointer-	if (maxCodeLength != std::string::npos && !formattedLine.empty())-	{-		size_t index = formattedLine.find_last_not_of(" \t");-		if (index != std::string::npos && (index < formattedLine.length() - 1))-		{-			index++;-			updateFormattedLineSplitPointsPointerOrReference(index);-			testForTimeToSplitFormattedLine();-		}-	}+    assert(currentChar == '*' || currentChar == '&' || currentChar == '^');+    assert(!isJavaStyle());++    if (currentLine.size() > (size_t)charNum + 1 &&+            std::isblank(currentLine[charNum - 1]) &&+            std::isblank(currentLine[charNum + 1]))+    {++        std::string seq = {currentChar, currentLine[charNum + 1]};+        appendSequence(seq);+        goForward(1);+        return;+    }++    // compute current whitespace before+    size_t wsBefore = currentLine.find_last_not_of(" \t", charNum - 1);+    if (wsBefore == std::string::npos)+        wsBefore = 0;+    else+        wsBefore = charNum - wsBefore - 1;+    std::string sequenceToInsert(1, currentChar);++    if (currentChar == peekNextChar())+    {+        for (size_t i = charNum + 1; currentLine.length() > i; i++)+        {+            if (currentLine[i] == sequenceToInsert[0])+            {+                sequenceToInsert.append(1, currentLine[i]);+                goForward(1);+                continue;+            }+            break;+        }+    }+    // if reference to a pointer check for conflicting alignment+    else if (currentChar == '*' && peekNextChar() == '&'+             && ASBeautifier::peekNextChar(currentLine, charNum + 1) != '&'+             && (referenceAlignment == REF_ALIGN_TYPE+                 || referenceAlignment == REF_ALIGN_MIDDLE+                 || referenceAlignment == REF_SAME_AS_PTR))+    {+        sequenceToInsert = "*&";+        goForward(1);+        for (size_t i = charNum; i < currentLine.length() - 1 && std::isblank(currentLine[i]); i++)+            goForward(1);+    }+    // if a comment follows don't align, just space pad+    if (isBeforeAnyComment())+    {+        appendSpacePad();+        formattedLine.append(sequenceToInsert);+        appendSpaceAfter();+        return;+    }+    // do this before goForward()+    bool isAfterScopeResolution = previousNonWSChar == ':';+    size_t charNumSave = charNum;+    // if this is the last thing on the line+    if (currentLine.find_first_not_of(" \t", charNum + 1) == std::string::npos)+    {+        if (wsBefore == 0 && !isAfterScopeResolution)+            formattedLine.append(1, ' ');+        formattedLine.append(sequenceToInsert);+        return;+    }+    // goForward() to convert tabs to spaces, if necessary,+    // and move following characters to preceding characters+    // this may not work every time with tab characters+    for (size_t i = charNum + 1; i < currentLine.length() && std::isblank(currentLine[i]); i++)+    {+        goForward(1);+        if (!formattedLine.empty())+            formattedLine.append(1, currentLine[i]);+        else+            spacePadNum--;+    }+    // find space padding after+    size_t wsAfter = currentLine.find_first_not_of(" \t", charNumSave + 1);+    if (wsAfter == std::string::npos || isBeforeAnyComment())+        wsAfter = 0;+    else+        wsAfter = wsAfter - charNumSave - 1;+    // don't pad before scope resolution operator, but pad after+    if (isAfterScopeResolution)+    {+        size_t lastText = formattedLine.find_last_not_of(" \t");+        formattedLine.insert(lastText + 1, sequenceToInsert);+        appendSpacePad();+    }+    else if (!formattedLine.empty())+    {+        // whitespace should be at least 2 chars to center+        if (wsBefore + wsAfter < 2)+        {+            size_t charsToAppend = (2 - (wsBefore + wsAfter));+            formattedLine.append(charsToAppend, ' ');+            spacePadNum += charsToAppend;+            if (wsBefore == 0)+                wsBefore++;+            if (wsAfter == 0)+                wsAfter++;+        }+        // insert the pointer or reference char+        size_t padAfter = (wsBefore + wsAfter) / 2;+        size_t index = formattedLine.length() - padAfter;+        if (index < formattedLine.length())+            formattedLine.insert(index, sequenceToInsert);+        else+            formattedLine.append(sequenceToInsert);+    }+    else	// formattedLine.length() == 0+    {+        formattedLine.append(sequenceToInsert);+        if (wsAfter == 0)+            wsAfter++;+        formattedLine.append(wsAfter, ' ');+        spacePadNum += wsAfter;+    }+    // update the formattedLine split point after the pointer+    if (maxCodeLength != std::string::npos && !formattedLine.empty())+    {+        size_t index = formattedLine.find_last_not_of(" \t");+        if (index != std::string::npos && (index < formattedLine.length() - 1))+        {+            index++;+            updateFormattedLineSplitPointsPointerOrReference(index);+            testForTimeToSplitFormattedLine();+        }+    } }  /**@@ -4859,123 +5340,123 @@ void ASFormatter::formatPointerOrReferenceToMiddle()  */ void ASFormatter::formatPointerOrReferenceToName() {-	assert(currentChar == '*' || currentChar == '&' || currentChar == '^');-	assert(!isJavaStyle());--	// do this before bumping charNum-	bool isOldPRCentered = isPointerOrReferenceCentered();-	size_t startNum = formattedLine.find_last_not_of(" \t");-	if (startNum == std::string::npos)-		startNum = 0;-	std::string sequenceToInsert(1, currentChar);-	if (currentChar == peekNextChar())-	{-		for (size_t i = charNum + 1; currentLine.length() > i; i++)-		{-			if (currentLine[i] == sequenceToInsert[0])-			{-				sequenceToInsert.append(1, currentLine[i]);-				goForward(1);-				continue;-			}-			break;-		}-	}--	// if reference to a pointer align both to name--	else if (currentChar == '*' && peekNextChar() == '&' && ASBeautifier::peekNextChar(currentLine, charNum + 1) != '&')-	{-		sequenceToInsert = "*&";-		goForward(1);-		for (size_t i = charNum; i < currentLine.length() - 1 && std::isblank(currentLine[i]); i++)-			goForward(1);-	}---	char peekedChar = peekNextChar();-	bool isAfterScopeResolution = previousNonWSChar == ':';		// check for ::-	// if this is not the last thing on the line-	if ((isLegalNameChar(peekedChar) || peekedChar == '(' || peekedChar == '[' || peekedChar == '=')-	        && (int) currentLine.find_first_not_of(" \t", charNum + 1) > charNum)-	{-		// goForward() to convert tabs to spaces, if necessary,-		// and move following characters to preceding characters-		// this may not work every time with tab characters-		for (size_t i = charNum + 1; i < currentLine.length() && std::isblank(currentLine[i]); i++)-		{-			// if a padded paren follows don't move-			if (shouldPadParensOutside && peekedChar == '(' && !isOldPRCentered)-			{-				// empty parens don't count-				size_t start = currentLine.find_first_not_of("( \t", i);-				if (start != std::string::npos && currentLine[start] != ')')-					break;-			}-			goForward(1);-			if (!formattedLine.empty())-				formattedLine.append(1, currentLine[charNum]);-			else-				spacePadNum--;-		}-	}-	// don't pad before scope resolution operator-	if (isAfterScopeResolution)-	{-		size_t lastText = formattedLine.find_last_not_of(" \t");-		if (lastText != std::string::npos && lastText + 1 < formattedLine.length())-			formattedLine.erase(lastText + 1);-	}-	// if no space before * then add one-	else if (!formattedLine.empty()-			&& (currentLine[startNum + 1] != '&')-			&& (formattedLine.length() <= startNum + 1-				|| !std::isblank(formattedLine[startNum + 1])))-	{-		formattedLine.insert(startNum + 1, 1, ' ');-		spacePadNum++;-	}-	appendSequence(sequenceToInsert, false);--	// if old pointer or reference is centered, remove a space-	if (isOldPRCentered-	        && formattedLine.length() > startNum + 1-	        && std::isblank(formattedLine[startNum + 1])-	        && peekedChar != '*'		// check for '* *'-	        && !isBeforeAnyComment()-	        && ((isLegalNameChar(peekedChar) || peekedChar == '(') && pointerAlignment == PTR_ALIGN_NAME) //https://sourceforge.net/p/astyle/bugs/546/ + #527-	   )-	{-		formattedLine.erase(startNum + 1, 1);-		spacePadNum--;-	}-	// don't convert to *= or &=-	if (peekedChar == '=')-	{-		appendSpaceAfter();-		// if more than one space before, delete one-		if (formattedLine.length() > startNum-		        && std::isblank(formattedLine[startNum + 1])-		        && std::isblank(formattedLine[startNum + 2]))-		{-			formattedLine.erase(startNum + 1, 1);-			spacePadNum--;-		}-	}-	// update the formattedLine split point-	if (maxCodeLength != std::string::npos)-	{-		size_t index = formattedLine.find_last_of(" \t");-		if (index != std::string::npos-		        && index < formattedLine.length() - 1-		        && (formattedLine[index + 1] == '*'-		            || formattedLine[index + 1] == '&'-		            || formattedLine[index + 1] == '^'))-		{-			updateFormattedLineSplitPointsPointerOrReference(index);-			testForTimeToSplitFormattedLine();-		}-	}+    assert(currentChar == '*' || currentChar == '&' || currentChar == '^');+    assert(!isJavaStyle());++    // do this before bumping charNum+    bool isOldPRCentered = isPointerOrReferenceCentered();+    size_t startNum = formattedLine.find_last_not_of(" \t");+    if (startNum == std::string::npos)+        startNum = 0;+    std::string sequenceToInsert(1, currentChar);+    if (currentChar == peekNextChar())+    {+        for (size_t i = charNum + 1; currentLine.length() > i; i++)+        {+            if (currentLine[i] == sequenceToInsert[0])+            {+                sequenceToInsert.append(1, currentLine[i]);+                goForward(1);+                continue;+            }+            break;+        }+    }++    // if reference to a pointer align both to name++    else if (currentChar == '*' && peekNextChar() == '&' && ASBeautifier::peekNextChar(currentLine, charNum + 1) != '&')+    {+        sequenceToInsert = "*&";+        goForward(1);+        for (size_t i = charNum; i < currentLine.length() - 1 && std::isblank(currentLine[i]); i++)+            goForward(1);+    }+++    char peekedChar = peekNextChar();+    bool isAfterScopeResolution = previousNonWSChar == ':';		// check for ::+    // if this is not the last thing on the line+    if ((isLegalNameChar(peekedChar) || peekedChar == '(' || peekedChar == '[' || peekedChar == '=')+            && (int) currentLine.find_first_not_of(" \t", charNum + 1) > charNum)+    {+        // goForward() to convert tabs to spaces, if necessary,+        // and move following characters to preceding characters+        // this may not work every time with tab characters+        for (size_t i = charNum + 1; i < currentLine.length() && std::isblank(currentLine[i]); i++)+        {+            // if a padded paren follows don't move+            if (shouldPadParensOutside && peekedChar == '(' && !isOldPRCentered)+            {+                // empty parens don't count+                size_t start = currentLine.find_first_not_of("( \t", i);+                if (start != std::string::npos && currentLine[start] != ')')+                    break;+            }+            goForward(1);+            if (!formattedLine.empty())+                formattedLine.append(1, currentLine[charNum]);+            else+                spacePadNum--;+        }+    }+    // don't pad before scope resolution operator+    if (isAfterScopeResolution)+    {+        size_t lastText = formattedLine.find_last_not_of(" \t");+        if (lastText != std::string::npos && lastText + 1 < formattedLine.length())+            formattedLine.erase(lastText + 1);+    }+    // if no space before * then add one+    else if (!formattedLine.empty()+             && (currentLine[startNum + 1] != '&')+             && (formattedLine.length() <= startNum + 1+                 || !std::isblank(formattedLine[startNum + 1])))+    {+        formattedLine.insert(startNum + 1, 1, ' ');+        spacePadNum++;+    }+    appendSequence(sequenceToInsert, false);++    // if old pointer or reference is centered, remove a space+    if (isOldPRCentered+            && formattedLine.length() > startNum + 1+            && std::isblank(formattedLine[startNum + 1])+            && peekedChar != '*'		// check for '* *'+            && !isBeforeAnyComment()+            && ((isLegalNameChar(peekedChar) || peekedChar == '(') && pointerAlignment == PTR_ALIGN_NAME) //https://sourceforge.net/p/astyle/bugs/546/ + #527+       )+    {+        formattedLine.erase(startNum + 1, 1);+        spacePadNum--;+    }+    // don't convert to *= or &=+    if (peekedChar == '=')+    {+        appendSpaceAfter();+        // if more than one space before, delete one+        if (formattedLine.length() > startNum+                && std::isblank(formattedLine[startNum + 1])+                && std::isblank(formattedLine[startNum + 2]))+        {+            formattedLine.erase(startNum + 1, 1);+            spacePadNum--;+        }+    }+    // update the formattedLine split point+    if (maxCodeLength != std::string::npos)+    {+        size_t index = formattedLine.find_last_of(" \t");+        if (index != std::string::npos+                && index < formattedLine.length() - 1+                && (formattedLine[index + 1] == '*'+                    || formattedLine[index + 1] == '&'+                    || formattedLine[index + 1] == '^'))+        {+            updateFormattedLineSplitPointsPointerOrReference(index);+            testForTimeToSplitFormattedLine();+        }+    } }  /**@@ -4987,62 +5468,62 @@ void ASFormatter::formatPointerOrReferenceToName()  */ void ASFormatter::formatPointerOrReferenceCast() {-	assert(currentChar == '*' || currentChar == '&' || currentChar == '^');-	assert(!isJavaStyle());--	int pa = pointerAlignment;-	int ra = referenceAlignment;-	int itemAlignment = (currentChar == '*' || currentChar == '^')-	                    ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);--	std::string sequenceToInsert(1, currentChar);-	if (isSequenceReached("**") || isSequenceReached(ASResource::AS_AND))-	{-		goForward(1);-		sequenceToInsert.append(1, currentLine[charNum]);-	}-	if (itemAlignment == PTR_ALIGN_NONE)-	{-		appendSequence(sequenceToInsert, false);-		return;-	}-	// remove preceding whitespace-	char prevCh = ' ';-	size_t prevNum = formattedLine.find_last_not_of(" \t");-	if (prevNum != std::string::npos)-	{-		prevCh = formattedLine[prevNum];-		if (itemAlignment == PTR_ALIGN_TYPE && currentChar == '*' && prevCh == '*')-		{-			// '* *' may be a multiply followed by a dereference-			if (prevNum + 2 < formattedLine.length()-			        && std::isblank(formattedLine[prevNum + 2]))-			{-				spacePadNum -= (formattedLine.length() - 2 - prevNum);-				formattedLine.erase(prevNum + 2);-			}-		}-		else if (prevNum + 1 < formattedLine.length()-		         && std::isblank(formattedLine[prevNum + 1])-		         && prevCh != '(')-		{-			spacePadNum -= (formattedLine.length() - 1 - prevNum);-			formattedLine.erase(prevNum + 1);-		}-	}--	bool isAfterScopeResolution = previousNonWSChar == ':';-	if ((itemAlignment == PTR_ALIGN_MIDDLE || itemAlignment == PTR_ALIGN_NAME)-	        && !isAfterScopeResolution && prevCh != '(')-	{-		appendSpacePad();-		// in this case appendSpacePad may or may not update the split point-		if (maxCodeLength != std::string::npos && !formattedLine.empty())-			updateFormattedLineSplitPointsPointerOrReference(formattedLine.length() - 1);-		appendSequence(sequenceToInsert, false);-	}-	else-		appendSequence(sequenceToInsert, false);+    assert(currentChar == '*' || currentChar == '&' || currentChar == '^');+    assert(!isJavaStyle());++    int pa = pointerAlignment;+    int ra = referenceAlignment;+    int itemAlignment = (currentChar == '*' || currentChar == '^')+                        ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);++    std::string sequenceToInsert(1, currentChar);+    if (isSequenceReached("**") || isSequenceReached(ASResource::AS_AND))+    {+        goForward(1);+        sequenceToInsert.append(1, currentLine[charNum]);+    }+    if (itemAlignment == PTR_ALIGN_NONE)+    {+        appendSequence(sequenceToInsert, false);+        return;+    }+    // remove preceding whitespace+    char prevCh = ' ';+    size_t prevNum = formattedLine.find_last_not_of(" \t");+    if (prevNum != std::string::npos)+    {+        prevCh = formattedLine[prevNum];+        if (itemAlignment == PTR_ALIGN_TYPE && currentChar == '*' && prevCh == '*')+        {+            // '* *' may be a multiply followed by a dereference+            if (prevNum + 2 < formattedLine.length()+                    && std::isblank(formattedLine[prevNum + 2]))+            {+                spacePadNum -= (formattedLine.length() - 2 - prevNum);+                formattedLine.erase(prevNum + 2);+            }+        }+        else if (prevNum + 1 < formattedLine.length()+                 && std::isblank(formattedLine[prevNum + 1])+                 && prevCh != '(')+        {+            spacePadNum -= (formattedLine.length() - 1 - prevNum);+            formattedLine.erase(prevNum + 1);+        }+    }++    bool isAfterScopeResolution = previousNonWSChar == ':';+    if ((itemAlignment == PTR_ALIGN_MIDDLE || itemAlignment == PTR_ALIGN_NAME)+            && !isAfterScopeResolution && prevCh != '(')+    {+        appendSpacePad();+        // in this case appendSpacePad may or may not update the split point+        if (maxCodeLength != std::string::npos && !formattedLine.empty())+            updateFormattedLineSplitPointsPointerOrReference(formattedLine.length() - 1);+        appendSequence(sequenceToInsert, false);+    }+    else+        appendSequence(sequenceToInsert, false); }  /**@@ -5053,161 +5534,161 @@ void ASFormatter::formatPointerOrReferenceCast()  */ void ASFormatter::padParensOrBrackets(char openDelim, char closeDelim, bool padFirstParen) {-	assert(currentChar == openDelim || currentChar == closeDelim);--	int spacesOutsideToDelete = 0;-	int spacesInsideToDelete = 0;--	bool shouldPadOutside = shouldPadParensOutside || shouldPadBracketsOutside;-	bool shouldPadInside = shouldPadParensInside || shouldPadBracketsInside;-	bool shouldUnPad = shouldUnPadParens || shouldUnPadBrackets;--	if (currentChar == openDelim)-	{-		spacesOutsideToDelete = formattedLine.length() - 1;-		spacesInsideToDelete = 0;--		// compute spaces outside the opening paren to delete-		if (shouldUnPad && !isInStruct)-		{-			char lastChar = ' ';-			bool prevIsParenHeader = false;-			size_t i = formattedLine.find_last_not_of(" \t");-			if (i != std::string::npos)-			{-				// if last char is a brace the previous whitespace is an indent-				if (formattedLine[i] == '{')-					spacesOutsideToDelete = 0;-				else if (isCharImmediatelyPostPointerOrReference)-					spacesOutsideToDelete = 0;-				else-				{-					spacesOutsideToDelete -= i;-					lastChar = formattedLine[i];-					// if previous word is a header, it will be a paren header-					std::string prevWord = getPreviousWord(formattedLine, formattedLine.length());-					const std::string* prevWordH = nullptr;-					if (shouldPadHeader-					        && !prevWord.empty()-					        && isCharPotentialHeader(prevWord, 0))-						prevWordH = ASBase::findHeader(prevWord, 0, headers);--					if (prevWordH != nullptr)-						prevIsParenHeader = true;    // don't unpad-					else if (prevWord == ASResource::AS_RETURN)-						prevIsParenHeader = true;    // don't unpad-					else if ((prevWord == ASResource::AS_NEW || prevWord == ASResource::AS_DELETE)-					         && shouldPadHeader)-						prevIsParenHeader = true;    // don't unpad-					else if (isCStyle() && prevWord == ASResource::AS_THROW && shouldPadHeader)-						prevIsParenHeader = true;    // don't unpad-					else if (prevWord == "and" || prevWord == "or" || prevWord == "in")-						prevIsParenHeader = true;    // don't unpad-					// don't unpad variables-					else if (isNumericVariable(prevWord))-						prevIsParenHeader = true;    // don't unpad-				}-			}-			// do not unpad operators, but leave them if already padded-			if (shouldPadOutside || prevIsParenHeader)-			{-				spacesOutsideToDelete--;-			}-			else-			{-				static const std::string operatorList = "|&<>,?:;=+-*/%^";-				if (operatorList.find(lastChar) != std::string::npos ||-				        (lastChar == openDelim && shouldPadInside) ||-				        (lastChar == '>' && !foundCastOperator))-				{-					spacesOutsideToDelete--;-				}-			}--			if (spacesOutsideToDelete > 0)-			{-				formattedLine.erase(i + 1, spacesOutsideToDelete);-				spacePadNum -= spacesOutsideToDelete;-			}-		}--		// pad open paren outside-		char peekedCharOutside = peekNextChar();-		if (padFirstParen && ( (previousChar != openDelim && peekedCharOutside != closeDelim)  || shouldPadEmptyParens ) )-			appendSpacePad();-		else if (shouldPadOutside)-		{-			// GH19-			if (!(currentChar == openDelim && peekedCharOutside == closeDelim) || shouldPadEmptyParens)-				appendSpacePad();-		}--		appendCurrentChar();--		// unpad open paren inside-		if (shouldUnPad)-		{-			size_t j = currentLine.find_first_not_of(" \t", charNum + 1);-			if (j != std::string::npos)-				spacesInsideToDelete = j - charNum - 1;-			if (shouldPadInside)-				spacesInsideToDelete--;-			if (spacesInsideToDelete > 0)-			{-				currentLine.erase(charNum + 1, spacesInsideToDelete);-				spacePadNum -= spacesInsideToDelete;-			}-			// convert tab to space if requested-			if (shouldConvertTabs-			        && (int) currentLine.length() > charNum + 1-			        && currentLine[charNum + 1] == '\t')-				currentLine[charNum + 1] = ' ';-		}--		// pad open paren inside-		char peekedCharInside = peekNextChar();-		if (shouldPadInside)-			if (!(currentChar == openDelim && peekedCharInside == closeDelim))-				appendSpaceAfter();-	}-	else if (currentChar == closeDelim)-	{-		// unpad close paren inside-		if (shouldUnPad)-		{-			spacesInsideToDelete = formattedLine.length();-			size_t i = formattedLine.find_last_not_of(" \t");-			if (i != std::string::npos)-				spacesInsideToDelete = formattedLine.length() - 1 - i;-			if (shouldPadInside)-				spacesInsideToDelete--;-			if (spacesInsideToDelete > 0)-			{-				formattedLine.erase(i + 1, spacesInsideToDelete);-				spacePadNum -= spacesInsideToDelete;-			}-		}--		// pad close paren inside-		if (shouldPadInside)-			if (!(previousChar == openDelim && currentChar == closeDelim))-				appendSpacePad();--		appendCurrentChar();--		// pad close paren outside-		char peekedCharOutside = peekNextChar();-		if (shouldPadOutside)-			if (peekedCharOutside != ';'-			        && peekedCharOutside != ','-			        && peekedCharOutside != '.'-			        && peekedCharOutside != '+'    // check for ++-			        && peekedCharOutside != '-'    // check for ---			        && peekedCharOutside != ']')-			{-				appendSpaceAfter();-			}-	}+    assert(currentChar == openDelim || currentChar == closeDelim);++    int spacesOutsideToDelete = 0;+    int spacesInsideToDelete = 0;++    bool shouldPadOutside = shouldPadParensOutside || shouldPadBracketsOutside;+    bool shouldPadInside = shouldPadParensInside || shouldPadBracketsInside;+    bool shouldUnPad = shouldUnPadParens || shouldUnPadBrackets;++    if (currentChar == openDelim)+    {+        spacesOutsideToDelete = formattedLine.length() - 1;+        spacesInsideToDelete = 0;++        // compute spaces outside the opening paren to delete+        if (shouldUnPad && !isInStruct)+        {+            char lastChar = ' ';+            bool prevIsParenHeader = false;+            size_t i = formattedLine.find_last_not_of(" \t");+            if (i != std::string::npos)+            {+                // if last char is a brace the previous whitespace is an indent+                if (formattedLine[i] == '{')+                    spacesOutsideToDelete = 0;+                else if (isCharImmediatelyPostPointerOrReference)+                    spacesOutsideToDelete = 0;+                else+                {+                    spacesOutsideToDelete -= i;+                    lastChar = formattedLine[i];+                    // if previous word is a header, it will be a paren header+                    std::string_view prevWord = getPreviousWord(formattedLine, formattedLine.length());+                    const std::string* prevWordH = nullptr;+                    if (shouldPadHeader+                            && !prevWord.empty()+                            && isCharPotentialHeader(prevWord, 0))+                        prevWordH = ASBase::findHeader(prevWord, 0, headers.get());++                    if (prevWordH != nullptr)+                        prevIsParenHeader = true;    // don't unpad+                    else if (prevWord == ASResource::AS_RETURN)+                        prevIsParenHeader = true;    // don't unpad+                    else if ((prevWord == ASResource::AS_NEW || prevWord == ASResource::AS_DELETE)+                             && shouldPadHeader)+                        prevIsParenHeader = true;    // don't unpad+                    else if (isCStyle() && prevWord == ASResource::AS_THROW && shouldPadHeader)+                        prevIsParenHeader = true;    // don't unpad+                    else if (prevWord == "and" || prevWord == "or" || prevWord == "in")+                        prevIsParenHeader = true;    // don't unpad+                    // don't unpad variables+                    else if (isNumericVariable(prevWord))+                        prevIsParenHeader = true;    // don't unpad+                }+            }+            // do not unpad operators, but leave them if already padded+            if (shouldPadOutside || prevIsParenHeader)+            {+                spacesOutsideToDelete--;+            }+            else+            {+                static const std::string operatorList = "|&<>,?:;=+-*/%^";+                if (operatorList.find(lastChar) != std::string::npos ||+                        (lastChar == openDelim && shouldPadInside) ||+                        (lastChar == '>' && !foundCastOperator))+                {+                    spacesOutsideToDelete--;+                }+            }++            if (spacesOutsideToDelete > 0)+            {+                formattedLine.erase(i + 1, spacesOutsideToDelete);+                spacePadNum -= spacesOutsideToDelete;+            }+        }++        // pad open paren outside+        char peekedCharOutside = peekNextChar();+        if (padFirstParen && ( (previousChar != openDelim && peekedCharOutside != closeDelim)  || shouldPadEmptyParens ) )+            appendSpacePad();+        else if (shouldPadOutside)+        {+            // GH19+            if (!(currentChar == openDelim && peekedCharOutside == closeDelim) || shouldPadEmptyParens)+                appendSpacePad();+        }++        appendCurrentChar();++        // unpad open paren inside+        if (shouldUnPad)+        {+            size_t j = currentLine.find_first_not_of(" \t", charNum + 1);+            if (j != std::string::npos)+                spacesInsideToDelete = j - charNum - 1;+            if (shouldPadInside)+                spacesInsideToDelete--;+            if (spacesInsideToDelete > 0)+            {+                currentLine.erase(charNum + 1, spacesInsideToDelete);+                spacePadNum -= spacesInsideToDelete;+            }+            // convert tab to space if requested+            if (shouldConvertTabs+                    && (int) currentLine.length() > charNum + 1+                    && currentLine[charNum + 1] == '\t')+                currentLine[charNum + 1] = ' ';+        }++        // pad open paren inside+        char peekedCharInside = peekNextChar();+        if (shouldPadInside)+            if (!(currentChar == openDelim && peekedCharInside == closeDelim))+                appendSpaceAfter();+    }+    else if (currentChar == closeDelim)+    {+        // unpad close paren inside+        if (shouldUnPad)+        {+            spacesInsideToDelete = formattedLine.length();+            size_t i = formattedLine.find_last_not_of(" \t");+            if (i != std::string::npos)+                spacesInsideToDelete = formattedLine.length() - 1 - i;+            if (shouldPadInside)+                spacesInsideToDelete--;+            if (spacesInsideToDelete > 0)+            {+                formattedLine.erase(i + 1, spacesInsideToDelete);+                spacePadNum -= spacesInsideToDelete;+            }+        }++        // pad close paren inside+        if (shouldPadInside)+            if (!(previousChar == openDelim && currentChar == closeDelim))+                appendSpacePad();++        appendCurrentChar();++        // pad close paren outside+        char peekedCharOutside = peekNextChar();+        if (shouldPadOutside)+            if (peekedCharOutside != ';'+                    && peekedCharOutside != ','+                    && peekedCharOutside != '.'+                    && peekedCharOutside != '+'    // check for +++                    && peekedCharOutside != '-'    // check for --+                    && peekedCharOutside != ']')+            {+                appendSpaceAfter();+            }+    } }  /**@@ -5218,40 +5699,40 @@ void ASFormatter::padParensOrBrackets(char openDelim, char closeDelim, bool padF */ void ASFormatter::padObjCMethodPrefix() {-	assert(isInObjCMethodDefinition && isImmediatelyPostObjCMethodPrefix);-	assert(shouldPadMethodPrefix || shouldUnPadMethodPrefix);--	size_t prefix = formattedLine.find_first_of("+-");-	if (prefix == std::string::npos)-		return;-	size_t firstChar = formattedLine.find_first_not_of(" \t", prefix + 1);-	if (firstChar == std::string::npos)-		firstChar = formattedLine.length();-	int spaces = firstChar - prefix - 1;--	if (shouldPadMethodPrefix)-	{-		if (spaces == 0)-		{-			formattedLine.insert(prefix + 1, 1, ' ');-			spacePadNum += 1;-		}-		else if (spaces > 1)-		{-			formattedLine.erase(prefix + 1, spaces - 1);-			formattedLine[prefix + 1] = ' ';  // convert any tab to space-			spacePadNum -= spaces - 1;-		}-	}-	// this option will be ignored if used with pad-method-prefix-	else if (shouldUnPadMethodPrefix)-	{-		if (spaces > 0)-		{-			formattedLine.erase(prefix + 1, spaces);-			spacePadNum -= spaces;-		}-	}+    assert(isInObjCMethodDefinition && isImmediatelyPostObjCMethodPrefix);+    assert(shouldPadMethodPrefix || shouldUnPadMethodPrefix);++    size_t prefix = formattedLine.find_first_of("+-");+    if (prefix == std::string::npos)+        return;+    size_t firstChar = formattedLine.find_first_not_of(" \t", prefix + 1);+    if (firstChar == std::string::npos)+        firstChar = formattedLine.length();+    int spaces = firstChar - prefix - 1;++    if (shouldPadMethodPrefix)+    {+        if (spaces == 0)+        {+            formattedLine.insert(prefix + 1, 1, ' ');+            spacePadNum += 1;+        }+        else if (spaces > 1)+        {+            formattedLine.erase(prefix + 1, spaces - 1);+            formattedLine[prefix + 1] = ' ';  // convert any tab to space+            spacePadNum -= spaces - 1;+        }+    }+    // this option will be ignored if used with pad-method-prefix+    else if (shouldUnPadMethodPrefix)+    {+        if (spaces > 0)+        {+            formattedLine.erase(prefix + 1, spaces);+            spacePadNum -= spaces;+        }+    } }  /**@@ -5261,47 +5742,47 @@ void ASFormatter::padObjCMethodPrefix() */ void ASFormatter::padObjCReturnType() {-	assert(currentChar == ')' && isInObjCReturnType);-	assert(shouldPadReturnType || shouldUnPadReturnType);--	size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);-	if (nextText == std::string::npos)-		return;-	int spaces = nextText - charNum - 1;--	if (shouldPadReturnType)-	{-		if (spaces == 0)-		{-			// this will already be padded if pad-paren is used-			if (formattedLine[formattedLine.length() - 1] != ' ')-			{-				formattedLine.append(" ");-				spacePadNum += 1;-			}-		}-		else if (spaces > 1)-		{-			// do not use goForward here-			currentLine.erase(charNum + 1, spaces - 1);-			currentLine[charNum + 1] = ' ';  // convert any tab to space-			spacePadNum -= spaces - 1;-		}-	}-	// this option will be ignored if used with pad-return-type-	else if (shouldUnPadReturnType)-	{-		// this will already be padded if pad-paren is used-		if (formattedLine[formattedLine.length() - 1] == ' ')-		{-			int lastText = formattedLine.find_last_not_of(" \t");-			spacePadNum -= formattedLine.length() - lastText - 1;-			formattedLine.resize(lastText + 1);-		}-		// do not use goForward here-		currentLine.erase(charNum + 1, spaces);-		spacePadNum -= spaces;-	}+    assert(currentChar == ')' && isInObjCReturnType);+    assert(shouldPadReturnType || shouldUnPadReturnType);++    size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);+    if (nextText == std::string::npos)+        return;+    int spaces = nextText - charNum - 1;++    if (shouldPadReturnType)+    {+        if (spaces == 0)+        {+            // this will already be padded if pad-paren is used+            if (formattedLine[formattedLine.length() - 1] != ' ')+            {+                formattedLine.append(" ");+                spacePadNum += 1;+            }+        }+        else if (spaces > 1)+        {+            // do not use goForward here+            currentLine.erase(charNum + 1, spaces - 1);+            currentLine[charNum + 1] = ' ';  // convert any tab to space+            spacePadNum -= spaces - 1;+        }+    }+    // this option will be ignored if used with pad-return-type+    else if (shouldUnPadReturnType)+    {+        // this will already be padded if pad-paren is used+        if (formattedLine[formattedLine.length() - 1] == ' ')+        {+            int lastText = formattedLine.find_last_not_of(" \t");+            spacePadNum -= formattedLine.length() - lastText - 1;+            formattedLine.resize(lastText + 1);+        }+        // do not use goForward here+        currentLine.erase(charNum + 1, spaces);+        spacePadNum -= spaces;+    } }  /**@@ -5311,92 +5792,92 @@ void ASFormatter::padObjCReturnType() */ void ASFormatter::padObjCParamType() {-	assert((currentChar == '(' || currentChar == ')') && isInObjCMethodDefinition);-	assert(!isImmediatelyPostObjCMethodPrefix && !isInObjCReturnType);-	assert(shouldPadParamType || shouldUnPadParamType);--	if (currentChar == '(')-	{-		// open paren has already been attached to formattedLine by padParen-		size_t paramOpen = formattedLine.rfind('(');-		assert(paramOpen != std::string::npos);-		size_t prevText = formattedLine.find_last_not_of(" \t", paramOpen - 1);-		if (prevText == std::string::npos)-			return;-		int spaces = paramOpen - prevText - 1;--		if (shouldPadParamType-		        || objCColonPadMode == COLON_PAD_ALL-		        || objCColonPadMode == COLON_PAD_AFTER)-		{-			if (spaces == 0)-			{-				formattedLine.insert(paramOpen, 1, ' ');-				spacePadNum += 1;-			}-			if (spaces > 1)-			{-				formattedLine.erase(prevText + 1, spaces - 1);-				formattedLine[prevText + 1] = ' ';  // convert any tab to space-				spacePadNum -= spaces - 1;-			}-		}-		// this option will be ignored if used with pad-param-type-		else if (shouldUnPadParamType-		         || objCColonPadMode == COLON_PAD_NONE-		         || objCColonPadMode == COLON_PAD_BEFORE)-		{-			if (spaces > 0)-			{-				formattedLine.erase(prevText + 1, spaces);-				spacePadNum -= spaces;-			}-		}-	}-	else if (currentChar == ')')-	{-		size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);-		if (nextText == std::string::npos)-			return;-		int spaces = nextText - charNum - 1;--		if (shouldPadParamType)-		{-			if (spaces == 0)-			{-				// this will already be padded if pad-paren is used-				if (formattedLine[formattedLine.length() - 1] != ' ')-				{-					formattedLine.append(" ");-					spacePadNum += 1;-				}-			}-			else if (spaces > 1)-			{-				// do not use goForward here-				currentLine.erase(charNum + 1, spaces - 1);-				currentLine[charNum + 1] = ' ';  // convert any tab to space-				spacePadNum -= spaces - 1;-			}-		}-		// this option will be ignored if used with pad-param-type-		else if (shouldUnPadParamType)-		{-			// this will already be padded if pad-paren is used-			if (formattedLine[formattedLine.length() - 1] == ' ')-			{-				spacePadNum -= 1;-				int lastText = formattedLine.find_last_not_of(" \t");-				formattedLine.resize(lastText + 1);-			}-			if (spaces > 0)-			{-				// do not use goForward here-				currentLine.erase(charNum + 1, spaces);-				spacePadNum -= spaces;-			}-		}-	}+    assert((currentChar == '(' || currentChar == ')') && isInObjCMethodDefinition);+    assert(!isImmediatelyPostObjCMethodPrefix && !isInObjCReturnType);+    assert(shouldPadParamType || shouldUnPadParamType);++    if (currentChar == '(')+    {+        // open paren has already been attached to formattedLine by padParen+        size_t paramOpen = formattedLine.rfind('(');+        assert(paramOpen != std::string::npos);+        size_t prevText = formattedLine.find_last_not_of(" \t", paramOpen - 1);+        if (prevText == std::string::npos)+            return;+        int spaces = paramOpen - prevText - 1;++        if (shouldPadParamType+                || objCColonPadMode == COLON_PAD_ALL+                || objCColonPadMode == COLON_PAD_AFTER)+        {+            if (spaces == 0)+            {+                formattedLine.insert(paramOpen, 1, ' ');+                spacePadNum += 1;+            }+            if (spaces > 1)+            {+                formattedLine.erase(prevText + 1, spaces - 1);+                formattedLine[prevText + 1] = ' ';  // convert any tab to space+                spacePadNum -= spaces - 1;+            }+        }+        // this option will be ignored if used with pad-param-type+        else if (shouldUnPadParamType+                 || objCColonPadMode == COLON_PAD_NONE+                 || objCColonPadMode == COLON_PAD_BEFORE)+        {+            if (spaces > 0)+            {+                formattedLine.erase(prevText + 1, spaces);+                spacePadNum -= spaces;+            }+        }+    }+    else if (currentChar == ')')+    {+        size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);+        if (nextText == std::string::npos)+            return;+        int spaces = nextText - charNum - 1;++        if (shouldPadParamType)+        {+            if (spaces == 0)+            {+                // this will already be padded if pad-paren is used+                if (formattedLine[formattedLine.length() - 1] != ' ')+                {+                    formattedLine.append(" ");+                    spacePadNum += 1;+                }+            }+            else if (spaces > 1)+            {+                // do not use goForward here+                currentLine.erase(charNum + 1, spaces - 1);+                currentLine[charNum + 1] = ' ';  // convert any tab to space+                spacePadNum -= spaces - 1;+            }+        }+        // this option will be ignored if used with pad-param-type+        else if (shouldUnPadParamType)+        {+            // this will already be padded if pad-paren is used+            if (formattedLine[formattedLine.length() - 1] == ' ')+            {+                spacePadNum -= 1;+                int lastText = formattedLine.find_last_not_of(" \t");+                formattedLine.resize(lastText + 1);+            }+            if (spaces > 0)+            {+                // do not use goForward here+                currentLine.erase(charNum + 1, spaces);+                spacePadNum -= spaces;+            }+        }+    } }  /**@@ -5409,133 +5890,139 @@ void ASFormatter::padObjCParamType()  */ void ASFormatter::formatOpeningBrace(BraceType braceType) {-	assert(!isBraceType(braceType, ARRAY_TYPE));-	assert(currentChar == '{');--	parenStack->emplace_back(0);--	bool breakBrace = isCurrentBraceBroken();--	//478--	if (breakBrace)-	{-		if (isBeforeAnyComment() && isOkToBreakBlock(braceType) && sourceIterator->hasMoreLines())-		{-			// if comment is at line end leave the comment on this line-			if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)-			{-				currentChar = ' ';              // remove brace from current line-				if (parenStack->size() > 1)-					parenStack->pop_back();-				currentLine[charNum] = currentChar;-				appendOpeningBrace = true;      // append brace to following line-			}-			// else put comment after the brace-			else if (!isBeforeMultipleLineEndComments(charNum))-				breakLine();-		}-		else if (!isBraceType(braceType, SINGLE_LINE_TYPE))-		{-			formattedLine = rtrim(formattedLine);-			breakLine();-		}-		else if ((shouldBreakOneLineBlocks || isBraceType(braceType, BREAK_BLOCK_TYPE))-		         && !isBraceType(braceType, EMPTY_BLOCK_TYPE))-			breakLine();-		else if (!isInLineBreak)-			appendSpacePad();--		appendCurrentChar();--		// should a following comment break from the brace?-		// must break the line AFTER the brace-		if (isBeforeComment()-		        && !formattedLine.empty()-		        && formattedLine[0] == '{'-		        && isOkToBreakBlock(braceType)-		        && (braceFormatMode == BREAK_MODE-		            || braceFormatMode == LINUX_MODE))-		{-			shouldBreakLineAtNextChar = true;-		}-	}-	else    // attach brace-	{-		// are there comments before the brace?-		if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)-		{-			if (isOkToBreakBlock(braceType)-			        && !(isCharImmediatelyPostComment && isCharImmediatelyPostLineComment)	// don't attach if two comments on the line-			        && !isImmediatelyPostPreprocessor-			        && previousCommandChar != '{'	// don't attach { {-			        && previousCommandChar != '}'	// don't attach } {-			        && previousCommandChar != ';')	// don't attach ; {-			{-				appendCharInsideComments();-			}-			else-			{-				appendCurrentChar();				// don't attach-			}-		}-		else if (previousCommandChar == '{'-		         || (previousCommandChar == '}' && !isInClassInitializer)-		         || previousCommandChar == ';')		// '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'-		{-			appendCurrentChar();					// don't attach-		}-		else-		{-			// if a blank line precedes this don't attach-			if (isEmptyLine(formattedLine))-				appendCurrentChar();				// don't attach-			else if (isOkToBreakBlock(braceType)-			         && !(isImmediatelyPostPreprocessor-			              && currentLineBeginsWithBrace))-			{-				if (!isBraceType(braceType, EMPTY_BLOCK_TYPE))-				{-					appendSpacePad();-					appendCurrentChar(false);				// OK to attach-					testForTimeToSplitFormattedLine();		// line length will have changed-					// should a following comment attach with the brace?-					// insert spaces to reposition the comment-					if (isBeforeComment()-					        && !isBeforeMultipleLineEndComments(charNum)-					        && (!isBeforeAnyLineEndComment(charNum)	|| currentLineBeginsWithBrace))-					{-						shouldBreakLineAtNextChar = true;-						currentLine.insert(charNum + 1, charNum + 1, ' ');-					}-					else if (!isBeforeAnyComment())		// added in release 2.03-					{-						shouldBreakLineAtNextChar = true;-					}-				}-				else-				{-					if (currentLineBeginsWithBrace && (size_t) charNum == currentLineFirstBraceNum)-					{-						appendSpacePad();-						appendCurrentChar(false);		// attach-						shouldBreakLineAtNextChar = true;-					}-					else-					{-						appendSpacePad();-						appendCurrentChar();		// don't attach-					}-				}-			}-			else-			{-				if (!isInLineBreak)-					appendSpacePad();-				appendCurrentChar();				// don't attach-			}-		}-	}+    assert(!isBraceType(braceType, BraceType::ARRAY_TYPE));+    assert(currentChar == '{');++    parenStack->emplace_back(0);++    if (shouldPreserveBraceFormat)+    {+        appendCurrentChar();+        return;+    }++    bool breakBrace = isCurrentBraceBroken();++    //478++    if (breakBrace)+    {+        if (isBeforeAnyComment() && isOkToBreakBlock(braceType) && sourceIterator->hasMoreLines())+        {+            // if comment is at line end leave the comment on this line+            if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)+            {+                currentChar = ' ';              // remove brace from current line+                if (parenStack->size() > 1)+                    parenStack->pop_back();+                currentLine[charNum] = currentChar;+                appendOpeningBrace = true;      // append brace to following line+            }+            // else put comment after the brace+            else if (!isBeforeMultipleLineEndComments(charNum))+                breakLine();+        }+        else if (!isBraceType(braceType, BraceType::SINGLE_LINE_TYPE))+        {+            formattedLine = rtrim(formattedLine);+            breakLine();+        }+        else if ((shouldBreakOneLineBlocks || isBraceType(braceType, BraceType::BREAK_BLOCK_TYPE))+                 && !isBraceType(braceType, BraceType::EMPTY_BLOCK_TYPE))+            breakLine();+        else if (!isInLineBreak)+            appendSpacePad();++        appendCurrentChar();++        // should a following comment break from the brace?+        // must break the line AFTER the brace+        if (isBeforeComment()+                && !formattedLine.empty()+                && formattedLine[0] == '{'+                && isOkToBreakBlock(braceType)+                && (braceFormatMode == BREAK_MODE+                    || braceFormatMode == LINUX_MODE))+        {+            shouldBreakLineAtNextChar = true;+        }+    }+    else    // attach brace+    {+        // are there comments before the brace?+        if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)+        {+            if (isOkToBreakBlock(braceType)+                    && !(isCharImmediatelyPostComment && isCharImmediatelyPostLineComment)	// don't attach if two comments on the line+                    && !isImmediatelyPostPreprocessor+                    && previousCommandChar != '{'	// don't attach { {+                    && previousCommandChar != '}'	// don't attach } {+                    && previousCommandChar != ';')	// don't attach ; {+            {+                appendCharInsideComments();+            }+            else+            {+                appendCurrentChar();				// don't attach+            }+        }+        else if (previousCommandChar == '{'+                 || (previousCommandChar == '}' && !isInClassInitializer)+                 || previousCommandChar == ';')		// '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'+        {+            appendCurrentChar();					// don't attach+        }+        else+        {+            // if a blank line precedes this don't attach+            if (isEmptyLine(formattedLine))+                appendCurrentChar();				// don't attach+            else if (isOkToBreakBlock(braceType)+                     && !(isImmediatelyPostPreprocessor+                          && currentLineBeginsWithBrace))+            {+                if (!isBraceType(braceType, BraceType::EMPTY_BLOCK_TYPE))+                {+                    appendSpacePad();+                    appendCurrentChar(false);				// OK to attach+                    testForTimeToSplitFormattedLine();		// line length will have changed+                    // should a following comment attach with the brace?+                    // insert spaces to reposition the comment+                    if (isBeforeComment()+                            && !isBeforeMultipleLineEndComments(charNum)+                            && (!isBeforeAnyLineEndComment(charNum)	|| currentLineBeginsWithBrace))+                    {+                        shouldBreakLineAtNextChar = true;+                        currentLine.insert(charNum + 1, charNum + 1, ' ');+                    }+                    else if (!isBeforeAnyComment())		// added in release 2.03+                    {+                        shouldBreakLineAtNextChar = true;+                    }+                }+                else+                {+                    if (currentLineBeginsWithBrace && (size_t) charNum == currentLineFirstBraceNum)+                    {+                        appendSpacePad();+                        appendCurrentChar(false);		// attach+                        shouldBreakLineAtNextChar = true;+                    }+                    else+                    {+                        appendSpacePad();+                        appendCurrentChar();		// don't attach+                    }+                }+            }+            else+            {+                if (!isInLineBreak)+                    appendSpacePad();+                appendCurrentChar();				// don't attach+            }+        }+    } }  /**@@ -5547,83 +6034,124 @@ void ASFormatter::formatOpeningBrace(BraceType braceType)  */ void ASFormatter::formatClosingBrace(BraceType braceType) {-	assert(!isBraceType(braceType, ARRAY_TYPE));-	assert(currentChar == '}');--	// parenStack must contain one entry-	if (parenStack->size() > 1)-		parenStack->pop_back();--	// mark state of immediately after empty block-	// this state will be used for locating braces that appear immediately AFTER an empty block (e.g. '{} \n}').-	if (previousCommandChar == '{')-		isImmediatelyPostEmptyBlock = true;--	if (attachClosingBraceMode)-	{-		// for now, namespaces and classes will be attached. Uncomment the lines below to break.-		if ((isEmptyLine(formattedLine)			// if a blank line precedes this-		        || isCharImmediatelyPostLineComment-		        || isCharImmediatelyPostComment-		        || (isImmediatelyPostPreprocessor && (int) currentLine.find_first_not_of(" \t") == charNum)-		    )-		        && (!isBraceType(braceType, SINGLE_LINE_TYPE) || isOkToBreakBlock(braceType)))-		{-			breakLine();-			appendCurrentChar();				// don't attach-		}-		else-		{-			if (previousNonWSChar != '{'-			        && (!isBraceType(braceType, SINGLE_LINE_TYPE)-			            || isOkToBreakBlock(braceType)))-				appendSpacePad();-			appendCurrentChar(false);			// attach-		}-	}-	else if (!isBraceType(braceType, EMPTY_BLOCK_TYPE)-	         && (isBraceType(braceType, BREAK_BLOCK_TYPE)-	             || isOkToBreakBlock(braceType)))-	{-		breakLine();-		appendCurrentChar();-	}-	else-	{-		appendCurrentChar();-	}--	// if a declaration follows a definition, space pad-	if (isLegalNameChar(peekNextChar()))-		appendSpaceAfter();--	if (shouldBreakBlocks-	        && currentHeader != nullptr-	        && !isHeaderInMultiStatementLine-	        && parenStack->back() == 0)-	{-		if (currentHeader == &ASResource::AS_CASE || currentHeader == &ASResource::AS_DEFAULT)-		{-			// do not yet insert a line if "break" statement is outside the braces-			std::string nextText = peekNextText(currentLine.substr(charNum + 1));-			if (!nextText.empty()-			        && nextText.substr(0, 5) != "break")-				isAppendPostBlockEmptyLineRequested = true;-		}-		else-		{-			// GH18-			// #569-			isAppendPostBlockEmptyLineRequested = !(shouldBreakBlocks && shouldAttachClosingWhile)-			                                      || currentHeader != &ASResource::AS_DO;-		}--	}-	// new option for break-blocks for classes and fcts? GL83-	else if (shouldBreakClosingHeaderBlocks)-	{-		isAppendPostBlockEmptyLineRequested = !currentHeader && shouldBreakBlocks;-	}+    assert(!isBraceType(braceType, BraceType::ARRAY_TYPE));+    assert(currentChar == '}');++    // parenStack must contain one entry+    if (parenStack->size() > 1)+        parenStack->pop_back();++    if (shouldPreserveBraceFormat)+    {+        appendCurrentChar();+        return;+    }++    // suppress pending blank before class/struct closing brace (e.g. from =all field)+    if (isBraceType(braceType, BraceType::DEFINITION_TYPE)+            && !isBraceType(braceType, BraceType::NAMESPACE_TYPE))+    {+        // Only clear iPrepend when formattedLine has no pending content.+        // If formattedLine already holds a member (e.g. "int x;"), the blank+        // belongs BEFORE that member, not before the class brace — preserve it.+        if (trim(formattedLine).empty())+            isPrependPostBlockEmptyLineRequested = false;+        needBlankBeforeNextMember = false;+        // Signal that the class scope has closed. The output section uses this to avoid+        // arming lineBetweenMembersDoBlank for the last field before '}' — that would+        // produce an unwanted blank before '}'.+        // We do NOT clear lineBetweenMembersDoBlank here because formatClosingBrace()+        // is called (line 862) BEFORE breakLine() fires (line 2030) in the same loop+        // iteration, so the blank for the previous member line hasn't been output yet.+        lineBetweenMembersPassedClassClose = true;+    }++    // mark state of immediately after empty block+    // this state will be used for locating braces that appear immediately AFTER an empty block (e.g. '{} \n}').+    if (previousCommandChar == '{')+        isImmediatelyPostEmptyBlock = true;++    if (attachClosingBraceMode)+    {+        // for now, namespaces and classes will be attached. Uncomment the lines below to break.+        if ((isEmptyLine(formattedLine)			// if a blank line precedes this+                || isCharImmediatelyPostLineComment+                || isCharImmediatelyPostComment+                || (isImmediatelyPostPreprocessor && (int) currentLine.find_first_not_of(" \t") == charNum)+            )+                && (!isBraceType(braceType, BraceType::SINGLE_LINE_TYPE) || isOkToBreakBlock(braceType)))+        {+            breakLine();+            appendCurrentChar();				// don't attach+        }+        else+        {+            if (previousNonWSChar != '{'+                    && (!isBraceType(braceType, BraceType::SINGLE_LINE_TYPE)+                        || isOkToBreakBlock(braceType)))+                appendSpacePad();+            appendCurrentChar(false);			// attach+        }+    }+    else if (!isBraceType(braceType, BraceType::EMPTY_BLOCK_TYPE)+             && (isBraceType(braceType, BraceType::BREAK_BLOCK_TYPE)+                 || isOkToBreakBlock(braceType)))+    {+        breakLine();+        appendCurrentChar();+    }+    else+    {+        appendCurrentChar();+    }++    // if a declaration follows a definition, space pad+    if (isLegalNameChar(peekNextChar()))+        appendSpaceAfter();++    if (shouldBreakBlocks+            && currentHeader != nullptr+            && !isHeaderInMultiStatementLine+            && parenStack->back() == 0)+    {+        if (currentHeader == &ASResource::AS_CASE || currentHeader == &ASResource::AS_DEFAULT)+        {+            // do not yet insert a line if "break" statement is outside the braces+            std::string nextText = peekNextText(currentLine.substr(charNum + 1));+            if (!nextText.empty()+                    && nextText.substr(0, 5) != "break")+                isAppendPostBlockEmptyLineRequested = true;+        }+        else+        {+            // GH18+            // #569+            isAppendPostBlockEmptyLineRequested = !(shouldBreakBlocks && shouldAttachClosingWhile)+                                                  || currentHeader != &ASResource::AS_DO;+        }++    }+    // new option for break-blocks for classes and fcts? GL83+    else if (shouldBreakClosingHeaderBlocks)+    {+        isAppendPostBlockEmptyLineRequested = !currentHeader && shouldBreakBlocks;+    }++    // line-between-members: insert blank after method/property close at class scope+    if (shouldLineBetweenMembers+            && isBraceType(braceTypeStack->back(), BraceType::DEFINITION_TYPE))+    {+        isAppendPostBlockEmptyLineRequested = true;+    }+    // line-between-members: insert blank after top-level function close+    else if (shouldLineBetweenMembers+             && (isBraceType(braceTypeStack->back(), BraceType::NULL_TYPE)+                 || isBraceType(braceTypeStack->back(), BraceType::NAMESPACE_TYPE))+             && !isBraceType(braceType, BraceType::DEFINITION_TYPE)+             && !isBraceType(braceType, BraceType::NAMESPACE_TYPE))+    {+        isAppendPostBlockEmptyLineRequested = true;+    } }  /**@@ -5633,30 +6161,30 @@ void ASFormatter::formatClosingBrace(BraceType braceType)  * the braces will be appended to the current formattedLine or a new formattedLine as necessary  * the calling function should have a continue statement after calling this method  *- * @param braceType            the type of brace to be formatted, must be an ARRAY_TYPE.+ * @param braceType            the type of brace to be formatted, must be an BraceType::ARRAY_TYPE.  * @param isOpeningArrayBrace  indicates if this is the opening brace for the array block.  */ void ASFormatter::formatArrayBraces(BraceType braceType, bool isOpeningArrayBrace) {-	assert(isBraceType(braceType, ARRAY_TYPE));-	assert(currentChar == '{' || currentChar == '}');+    assert(isBraceType(braceType, BraceType::ARRAY_TYPE));+    assert(currentChar == '{' || currentChar == '}'); -	if (currentChar == '{')-	{-		// is this the first opening brace in the array?-		if (isOpeningArrayBrace)-		{-			formatFirstOpenBrace(braceType);-		}-		else	     // not the first opening brace-		{-			formatOpenBrace();-		}-	}-	else if (currentChar == '}')-	{-		formatCloseBrace(braceType);-	}+    if (currentChar == '{')+    {+        // is this the first opening brace in the array?+        if (isOpeningArrayBrace)+        {+            formatFirstOpenBrace(braceType);+        }+        else	     // not the first opening brace+        {+            formatOpenBrace();+        }+    }+    else if (currentChar == '}')+    {+        formatCloseBrace(braceType);+    } }  /**@@ -5665,115 +6193,118 @@ void ASFormatter::formatArrayBraces(BraceType braceType, bool isOpeningArrayBrac  */ void ASFormatter::formatRunIn() {-	assert(braceFormatMode == RUN_IN_MODE || braceFormatMode == NONE_MODE);--	// keep one line blocks returns true without indenting the run-in-	if (formattingStyle != STYLE_PICO-	        && !isOkToBreakBlock(braceTypeStack->back()))-		return; // true;--	// make sure the line begins with a brace-	size_t lastText = formattedLine.find_last_not_of(" \t");-	if (lastText == std::string::npos || formattedLine[lastText] != '{')-		return; // false;--	// make sure the brace is broken-	if (formattedLine.find_first_not_of(" \t{") != std::string::npos)-		return; // false;--	if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))-		return; // false;--	bool extraIndent = false;-	bool extraHalfIndent = false;-	isInLineBreak = true;--	// cannot attach a class modifier without indent-classes-	if (isCStyle()-	        && isCharPotentialHeader(currentLine, charNum)-	        && (isBraceType(braceTypeStack->back(), CLASS_TYPE)-	            || (isBraceType(braceTypeStack->back(), STRUCT_TYPE)-	                && isInIndentableStruct)))-	{-		if (findKeyword(currentLine, charNum, ASResource::AS_PUBLIC)-		        || findKeyword(currentLine, charNum, ASResource::AS_PRIVATE)-		        || findKeyword(currentLine, charNum, ASResource::AS_PROTECTED))-		{-			if (getModifierIndent())-				extraHalfIndent = true;-			else if (!getClassIndent())-				return; // false;-		}-		else if (getClassIndent())-			extraIndent = true;-	}--	// cannot attach a 'case' statement without indent-switches-	if (!getSwitchIndent()-	        && isCharPotentialHeader(currentLine, charNum)-	        && (findKeyword(currentLine, charNum, ASResource::AS_CASE)-	            || findKeyword(currentLine, charNum, ASResource::AS_DEFAULT)))-		return; // false;--	// extra indent for switch statements-	if (getSwitchIndent()-	        && !preBraceHeaderStack->empty()-	        && preBraceHeaderStack->back() == &ASResource::AS_SWITCH-	        && (isLegalNameChar(currentChar)-	            && !findKeyword(currentLine, charNum, ASResource::AS_CASE)))-		extraIndent = true;--	isInLineBreak = false;-	// remove for extra whitespace-	if (formattedLine.length() > lastText + 1-	        && formattedLine.find_first_not_of(" \t", lastText + 1) == std::string::npos)-		formattedLine.erase(lastText + 1);--	if (extraHalfIndent)-	{-		int indentLength_ = getIndentLength();-		runInIndentChars = indentLength_ / 2;-		formattedLine.append(runInIndentChars - 1, ' ');-	}-	else if (getForceTabIndentation() && getIndentLength() != getTabLength())-	{-		// insert the space indents-		std::string indent;-		int indentLength_ = getIndentLength();-		int tabLength_ = getTabLength();-		indent.append(indentLength_, ' ');-		if (extraIndent)-			indent.append(indentLength_, ' ');-		// replace spaces indents with tab indents-		size_t tabCount = indent.length() / tabLength_;		// truncate extra spaces-		indent.replace(0U, tabCount * tabLength_, tabCount, '\t');-		runInIndentChars = indentLength_;-		if (indent[0] == ' ')			// allow for brace-			indent.erase(0, 1);-		formattedLine.append(indent);-	}-	else if (getIndentString() == "\t")-	{-		appendChar('\t', false);-		runInIndentChars = 2;	// one for { and one for tab-		if (extraIndent)-		{-			appendChar('\t', false);-			runInIndentChars++;-		}-	}-	else // spaces-	{-		int indentLength_ = getIndentLength();-		formattedLine.append(indentLength_ - 1, ' ');-		runInIndentChars = indentLength_;-		if (extraIndent)-		{-			formattedLine.append(indentLength_, ' ');-			runInIndentChars += indentLength_;-		}-	}-	isInBraceRunIn = true;+    if (shouldPreserveBraceFormat)+        return;++    assert(braceFormatMode == RUN_IN_MODE || braceFormatMode == NONE_MODE);++    // keep one line blocks returns true without indenting the run-in+    if (formattingStyle != STYLE_PICO+            && !isOkToBreakBlock(braceTypeStack->back()))+        return; // true;++    // make sure the line begins with a brace+    size_t lastText = formattedLine.find_last_not_of(" \t");+    if (lastText == std::string::npos || formattedLine[lastText] != '{')+        return; // false;++    // make sure the brace is broken+    if (formattedLine.find_first_not_of(" \t{") != std::string::npos)+        return; // false;++    if (isBraceType(braceTypeStack->back(), BraceType::NAMESPACE_TYPE))+        return; // false;++    bool extraIndent = false;+    bool extraHalfIndent = false;+    isInLineBreak = true;++    // cannot attach a class modifier without indent-classes+    if (isCStyle()+            && isCharPotentialHeader(currentLine, charNum)+            && (isBraceType(braceTypeStack->back(), BraceType::CLASS_TYPE)+                || (isBraceType(braceTypeStack->back(), BraceType::STRUCT_TYPE)+                    && isInIndentableStruct)))+    {+        if (findKeyword(currentLine, charNum, ASResource::AS_PUBLIC)+                || findKeyword(currentLine, charNum, ASResource::AS_PRIVATE)+                || findKeyword(currentLine, charNum, ASResource::AS_PROTECTED))+        {+            if (getModifierIndent())+                extraHalfIndent = true;+            else if (!getClassIndent())+                return; // false;+        }+        else if (getClassIndent())+            extraIndent = true;+    }++    // cannot attach a 'case' statement without indent-switches+    if (!getSwitchIndent()+            && isCharPotentialHeader(currentLine, charNum)+            && (findKeyword(currentLine, charNum, ASResource::AS_CASE)+                || findKeyword(currentLine, charNum, ASResource::AS_DEFAULT)))+        return; // false;++    // extra indent for switch statements+    if (getSwitchIndent()+            && !preBraceHeaderStack->empty()+            && preBraceHeaderStack->back() == &ASResource::AS_SWITCH+            && (isLegalNameChar(currentChar)+                && !findKeyword(currentLine, charNum, ASResource::AS_CASE)))+        extraIndent = true;++    isInLineBreak = false;+    // remove for extra whitespace+    if (formattedLine.length() > lastText + 1+            && formattedLine.find_first_not_of(" \t", lastText + 1) == std::string::npos)+        formattedLine.erase(lastText + 1);++    if (extraHalfIndent)+    {+        int indentLength_ = getIndentLength();+        runInIndentChars = indentLength_ / 2;+        formattedLine.append(runInIndentChars - 1, ' ');+    }+    else if (getForceTabIndentation() && getIndentLength() != getTabLength())+    {+        // insert the space indents+        std::string indent;+        int indentLength_ = getIndentLength();+        int tabLength_ = getTabLength();+        indent.append(indentLength_, ' ');+        if (extraIndent)+            indent.append(indentLength_, ' ');+        // replace spaces indents with tab indents+        size_t tabCount = indent.length() / tabLength_;		// truncate extra spaces+        indent.replace(0U, tabCount * tabLength_, tabCount, '\t');+        runInIndentChars = indentLength_;+        if (indent[0] == ' ')			// allow for brace+            indent.erase(0, 1);+        formattedLine.append(indent);+    }+    else if (getIndentString() == "\t")+    {+        appendChar('\t', false);+        runInIndentChars = 2;	// one for { and one for tab+        if (extraIndent)+        {+            appendChar('\t', false);+            runInIndentChars++;+        }+    }+    else // spaces+    {+        int indentLength_ = getIndentLength();+        formattedLine.append(indentLength_ - 1, ' ');+        runInIndentChars = indentLength_;+        if (extraIndent)+        {+            formattedLine.append(indentLength_, ' ');+            runInIndentChars += indentLength_;+        }+    }+    isInBraceRunIn = true; }  /**@@ -5781,90 +6312,34 @@ void ASFormatter::formatRunIn()  */ void ASFormatter::formatArrayRunIn() {-	assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE));--	// make sure the brace is broken-	if (formattedLine.find_first_not_of(" \t{") != std::string::npos)-		return;+    assert(isBraceType(braceTypeStack->back(), BraceType::ARRAY_TYPE)); -	size_t lastText = formattedLine.find_last_not_of(" \t");-	if (lastText == std::string::npos || formattedLine[lastText] != '{')-		return;+    // make sure the brace is broken+    if (formattedLine.find_first_not_of(" \t{") != std::string::npos)+        return; -	// check for extra whitespace-	if (formattedLine.length() > lastText + 1-	        && formattedLine.find_first_not_of(" \t", lastText + 1) == std::string::npos)-		formattedLine.erase(lastText + 1);--	if (getIndentString() == "\t")-	{-		appendChar('\t', false);-		runInIndentChars = 2;	// one for { and one for tab-	}-	else-	{-		int indent = getIndentLength();-		formattedLine.append(indent - 1, ' ');-		runInIndentChars = indent;-	}-	isInBraceRunIn = true;-	isInLineBreak = false;-}--/**- * delete a braceTypeStack std::vector object- * BraceTypeStack did not work with the DeleteContainer template- */-void ASFormatter::deleteContainer(std::vector<BraceType>*& container)-{-	if (container != nullptr)-	{-		container->clear();-		delete (container);-		container = nullptr;-	}-}--/**- * delete a std::vector object- * T is the type of std::vector- * used for all std::vectors except braceTypeStack- */-template<typename T>-void ASFormatter::deleteContainer(T& container)-{-	if (container != nullptr)-	{-		container->clear();-		delete (container);-		container = nullptr;-	}-}+    size_t lastText = formattedLine.find_last_not_of(" \t");+    if (lastText == std::string::npos || formattedLine[lastText] != '{')+        return; -/**- * initialize a braceType std::vector object- * braceType did not work with the DeleteContainer template- */-void ASFormatter::initContainer(std::vector<BraceType>*& container, std::vector<BraceType>* value)-{-	if (container != nullptr)-		deleteContainer(container);-	container = value;-}+    // check for extra whitespace+    if (formattedLine.length() > lastText + 1+            && formattedLine.find_first_not_of(" \t", lastText + 1) == std::string::npos)+        formattedLine.erase(lastText + 1); -/**- * initialize a std::vector object- * T is the type of std::vector- * used for all std::vectors except braceTypeStack- */-template<typename T>-void ASFormatter::initContainer(T& container, T value)-{-	// since the ASFormatter object is never deleted,-	// the existing std::vectors must be deleted before creating new ones-	if (container != nullptr)-		deleteContainer(container);-	container = value;+    if (getIndentString() == "\t")+    {+        appendChar('\t', false);+        runInIndentChars = 2;	// one for { and one for tab+    }+    else+    {+        int indent = getIndentLength();+        formattedLine.append(indent - 1, ' ');+        runInIndentChars = indent;+    }+    isInBraceRunIn = true;+    isInLineBreak = false; }  /**@@ -5877,16 +6352,16 @@ void ASFormatter::initContainer(T& container, T value)  */ void ASFormatter::convertTabToSpaces() {-	assert(currentChar == '\t');+    assert(currentChar == '\t'); -	// do NOT replace if in quotes-	if (isInQuote || isInQuoteContinuation)-		return;+    // do NOT replace if in quotes+    if (isInQuote || isInQuoteContinuation)+        return; -	size_t tabSize = getTabLength();-	size_t numSpaces = tabSize - ((tabIncrementIn + charNum) % tabSize);-	currentLine.replace(charNum, 1, numSpaces, ' ');-	currentChar = currentLine[charNum];+    size_t tabSize = getTabLength();+    size_t numSpaces = tabSize - ((tabIncrementIn + charNum) % tabSize);+    currentLine.replace(charNum, 1, numSpaces, ' ');+    currentChar = currentLine[charNum]; }  /**@@ -5894,20 +6369,20 @@ void ASFormatter::convertTabToSpaces() */ bool ASFormatter::isOkToBreakBlock(BraceType braceType) const {-	// Actually, there should not be an ARRAY_TYPE brace here.-	// But this will avoid breaking a one line block when there is.-	// Otherwise they will be formatted differently on consecutive runs.-	if (isBraceType(braceType, ARRAY_TYPE)-	        && isBraceType(braceType, SINGLE_LINE_TYPE))-		return false;-	if (isBraceType(braceType, COMMAND_TYPE)-	        && isBraceType(braceType, EMPTY_BLOCK_TYPE))-		return false;-	if (!isBraceType(braceType, SINGLE_LINE_TYPE)-	        || isBraceType(braceType, BREAK_BLOCK_TYPE)-	        || shouldBreakOneLineBlocks)-		return true;-	return false;+    // Actually, there should not be an BraceType::ARRAY_TYPE brace here.+    // But this will avoid breaking a one line block when there is.+    // Otherwise they will be formatted differently on consecutive runs.+    if (isBraceType(braceType, BraceType::ARRAY_TYPE)+            && isBraceType(braceType, BraceType::SINGLE_LINE_TYPE))+        return false;+    if (isBraceType(braceType, BraceType::COMMAND_TYPE)+            && isBraceType(braceType, BraceType::EMPTY_BLOCK_TYPE))+        return false;+    if (!isBraceType(braceType, BraceType::SINGLE_LINE_TYPE)+            || isBraceType(braceType, BraceType::BREAK_BLOCK_TYPE)+            || shouldBreakOneLineBlocks)+        return true;+    return false; }  /**@@ -5915,9 +6390,9 @@ bool ASFormatter::isOkToBreakBlock(BraceType braceType) const */ bool ASFormatter::isSharpStyleWithParen(const std::string* header) const {-	return (isSharpStyle() && peekNextChar() == '('-	        && (header == &ASResource::AS_CATCH-	            || header == &ASResource::AS_DELEGATE));+    return (isSharpStyle() && peekNextChar() == '('+            && (header == &ASResource::AS_CATCH+                || header == &ASResource::AS_DELEGATE)); }  /**@@ -5927,18 +6402,18 @@ bool ASFormatter::isSharpStyleWithParen(const std::string* header) const  */ const std::string* ASFormatter::checkForHeaderFollowingComment(std::string_view firstLine) const {-	assert(isInComment || isInLineComment);-	assert(shouldBreakElseIfs || shouldBreakBlocks || isInSwitchStatement());-	// look ahead to find the next non-comment text-	bool endOnEmptyLine = (currentHeader == nullptr);-	if (isInSwitchStatement())-		endOnEmptyLine = false;-	std::string nextText = peekNextText(firstLine, endOnEmptyLine);+    assert(isInComment || isInLineComment);+    assert(shouldBreakElseIfs || shouldBreakBlocks || isInSwitchStatement());+    // look ahead to find the next non-comment text+    bool endOnEmptyLine = (currentHeader == nullptr);+    if (isInSwitchStatement())+        endOnEmptyLine = false;+    std::string nextText = peekNextText(firstLine, endOnEmptyLine); -	if (nextText.empty() || !isCharPotentialHeader(nextText, 0))-		return nullptr;+    if (nextText.empty() || !isCharPotentialHeader(nextText, 0))+        return nullptr; -	return ASBase::findHeader(nextText, 0, headers);+    return ASBase::findHeader(nextText, 0, headers.get()); }  /**@@ -5950,85 +6425,85 @@ const std::string* ASFormatter::checkForHeaderFollowingComment(std::string_view  */ void ASFormatter::processPreprocessor() {-	assert(currentChar == '#');--	const size_t preproc = currentLine.find_first_not_of(" \t", charNum + 1);-	if (preproc == std::string::npos)-		return;--	if (currentLine.compare(preproc, 2, "if") == 0)-	{-		preprocBraceTypeStackSize = braceTypeStack->size();-	}-	else if (currentLine.compare(preproc, 4, "else") == 0)-	{-		// delete stack entries added in #if-		// should be replaced by #else-		if (preprocBraceTypeStackSize > 0)-		{-			int addedPreproc = braceTypeStack->size() - preprocBraceTypeStackSize;-			for (int i = 0; i < addedPreproc; i++)-				braceTypeStack->pop_back();-		}-	}-	else if (currentLine.compare(preproc, 6, "define") == 0)-		isInPreprocessorDefineDef = true;---	//https://sourceforge.net/p/astyle/tickets/117/-	const size_t preprocPos = currentLine.find_first_not_of(" \t", charNum + 1);--	if (includeDirectivePaddingMode != INCLUDE_PAD_NO_CHANGE-	        && currentLine.compare(preprocPos, 7, "include") == 0)-	{-		size_t firstChar = currentLine.find_first_not_of(" \t", preprocPos + 7);-		if (firstChar != std::string::npos && (currentLine[firstChar] == '<' || currentLine[firstChar] == '"'))-		{-			currentLine.erase (preprocPos + 7, firstChar - (preprocPos + 7));-		}--		if (includeDirectivePaddingMode == INCLUDE_PAD_AFTER &&-		        (currentLine[preprocPos + 7] == '<' || currentLine[preprocPos + 7] == '"' || std::isalpha(currentLine[preprocPos + 7]))-		   )-		{-			currentLine.insert(preprocPos + 7, 1, ' ');-		}-	}--	// if top level it is potentially indentable-	if (shouldIndentPreprocBlock-	        && (isBraceType(braceTypeStack->back(), NULL_TYPE) || isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))-	        && !foundClassHeader-	        && !isInClassInitializer-	        && sourceIterator->tellg() > preprocBlockEnd)-	{-		std::string preprocessor = ASBeautifier::extractPreprocessorStatement(currentLine);--		// indent the #if preprocessor blocks-		if (preprocessor.length() >= 2 && preprocessor.substr(0, 2) == "if") // #if, #ifdef, #ifndef-		{-			if (isImmediatelyPostPreprocessor)-				breakLine();-			isIndentablePreprocessorBlck = isIndentablePreprocessorBlock(currentLine, charNum);-			isIndentablePreprocessor = isIndentablePreprocessorBlck;-		}-	}--	if (isIndentablePreprocessorBlck-	        && charNum < (int) currentLine.length() - 1-	        && std::isblank(currentLine[charNum + 1]))-	{-		size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);-		if (nextText != std::string::npos)-		{-			currentLine.erase(charNum + 1, nextText - charNum - 1);-		}-	}--	if (isIndentablePreprocessorBlck-	        && sourceIterator->tellg() >= preprocBlockEnd)-		isIndentablePreprocessorBlck = false;-	//  need to fall thru here to reset the variables+    assert(currentChar == '#');++    const size_t preproc = currentLine.find_first_not_of(" \t", charNum + 1);+    if (preproc == std::string::npos)+        return;++    if (currentLine.compare(preproc, 2, "if") == 0)+    {+        preprocBraceTypeStackSize = braceTypeStack->size();+    }+    else if (currentLine.compare(preproc, 4, "else") == 0)+    {+        // delete stack entries added in #if+        // should be replaced by #else+        if (preprocBraceTypeStackSize > 0)+        {+            int addedPreproc = braceTypeStack->size() - preprocBraceTypeStackSize;+            for (int i = 0; i < addedPreproc; i++)+                braceTypeStack->pop_back();+        }+    }+    else if (currentLine.compare(preproc, 6, "define") == 0)+        isInPreprocessorDefineDef = true;+++    //https://sourceforge.net/p/astyle/tickets/117/+    const size_t preprocPos = currentLine.find_first_not_of(" \t", charNum + 1);++    if (includeDirectivePaddingMode != INCLUDE_PAD_NO_CHANGE+            && currentLine.compare(preprocPos, 7, "include") == 0)+    {+        size_t firstChar = currentLine.find_first_not_of(" \t", preprocPos + 7);+        if (firstChar != std::string::npos && (currentLine[firstChar] == '<' || currentLine[firstChar] == '"'))+        {+            currentLine.erase (preprocPos + 7, firstChar - (preprocPos + 7));+        }++        if (includeDirectivePaddingMode == INCLUDE_PAD_AFTER &&+                (currentLine[preprocPos + 7] == '<' || currentLine[preprocPos + 7] == '"' || std::isalpha(currentLine[preprocPos + 7]))+           )+        {+            currentLine.insert(preprocPos + 7, 1, ' ');+        }+    }++    // if top level it is potentially indentable+    if (shouldIndentPreprocBlock+            && (isBraceType(braceTypeStack->back(), BraceType::NULL_TYPE) || isBraceType(braceTypeStack->back(), BraceType::NAMESPACE_TYPE))+            && !foundClassHeader+            && !isInClassInitializer+            && sourceIterator->tellg() > preprocBlockEnd)+    {+        std::string preprocessor = ASBeautifier::extractPreprocessorStatement(currentLine);++        // indent the #if preprocessor blocks+        if (preprocessor.length() >= 2 && preprocessor.substr(0, 2) == "if") // #if, #ifdef, #ifndef+        {+            if (isImmediatelyPostPreprocessor)+                breakLine();+            isIndentablePreprocessorBlck = isIndentablePreprocessorBlock(currentLine, charNum);+            isIndentablePreprocessor = isIndentablePreprocessorBlck;+        }+    }++    if (isIndentablePreprocessorBlck+            && charNum < (int) currentLine.length() - 1+            && std::isblank(currentLine[charNum + 1]))+    {+        size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);+        if (nextText != std::string::npos)+        {+            currentLine.erase(charNum + 1, nextText - charNum - 1);+        }+    }++    if (isIndentablePreprocessorBlck+            && sourceIterator->tellg() >= preprocBlockEnd)+        isIndentablePreprocessorBlck = false;+    //  need to fall thru here to reset the variables }  /**@@ -6037,38 +6512,38 @@ void ASFormatter::processPreprocessor()  */ bool ASFormatter::commentAndHeaderFollows() {-	// called ONLY IF shouldDeleteEmptyLines and shouldBreakBlocks are TRUE.-	assert(shouldDeleteEmptyLines && shouldBreakBlocks);+    // called ONLY IF shouldDeleteEmptyLines and shouldBreakBlocks are TRUE.+    assert(shouldDeleteEmptyLines && shouldBreakBlocks); -	// is the next line a comment-	auto stream = std::make_shared<ASPeekStream>(sourceIterator);-	if (!stream->hasMoreLines())-		return false;-	std::string nextLine_ = stream->peekNextLine();-	size_t firstChar = nextLine_.find_first_not_of(" \t");-	if (firstChar == std::string::npos-	        || !(nextLine_.compare(firstChar, 2, "//") == 0-	             || nextLine_.compare(firstChar, 2, "/*") == 0))-		return false;+    // is the next line a comment+    auto stream = std::make_shared<ASPeekStream>(sourceIterator);+    if (!stream->hasMoreLines())+        return false;+    std::string nextLine_ = stream->peekNextLine();+    size_t firstChar = nextLine_.find_first_not_of(" \t");+    if (firstChar == std::string::npos+            || !(nextLine_.compare(firstChar, 2, "//") == 0+                 || nextLine_.compare(firstChar, 2, "/*") == 0))+        return false; -	// find the next non-comment text, and reset-	std::string nextText = peekNextText(nextLine_, false, stream);-	if (nextText.empty() || !isCharPotentialHeader(nextText, 0))-		return false;+    // find the next non-comment text, and reset+    std::string nextText = peekNextText(nextLine_, false, stream);+    if (nextText.empty() || !isCharPotentialHeader(nextText, 0))+        return false; -	const std::string* newHeader = ASBase::findHeader(nextText, 0, headers);+    const std::string* newHeader = ASBase::findHeader(nextText, 0, headers.get()); -	if (newHeader == nullptr)-		return false;+    if (newHeader == nullptr)+        return false; -	// if a closing header, reset break unless break is requested-	if (isClosingHeader(newHeader) && !shouldBreakClosingHeaderBlocks)-	{-		isAppendPostBlockEmptyLineRequested = false;-		return false;-	}+    // if a closing header, reset break unless break is requested+    if (isClosingHeader(newHeader) && !shouldBreakClosingHeaderBlocks)+    {+        isAppendPostBlockEmptyLineRequested = false;+        return false;+    } -	return true;+    return true; }  /**@@ -6079,116 +6554,119 @@ bool ASFormatter::commentAndHeaderFollows()  */ bool ASFormatter::isCurrentBraceBroken() const {-	assert(braceTypeStack->size() > 1);--	bool breakBrace = false;-	size_t stackEnd = braceTypeStack->size() - 1;--	// check brace modifiers-	if (shouldAttachExternC-	        && isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE))-	{-		return false;-	}-	if (shouldAttachNamespace-	        && isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE))-	{-		return false;-	}-	if (shouldAttachClass-	        && (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE)-	            || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE)))-	{-		return false;-	}-	if (shouldAttachInline-	        && isCStyle()			// for C++ only-	        && braceFormatMode != RUN_IN_MODE-	        && !(currentLineBeginsWithBrace && peekNextChar() == '/')-	        && isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE))-	{-		size_t i;-		for (i = 1; i < braceTypeStack->size(); i++)-			if (isBraceType((*braceTypeStack)[i], CLASS_TYPE)-			        || isBraceType((*braceTypeStack)[i], STRUCT_TYPE))-				return false;-	}--	// check braces-	if (isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE))-	{-		if (currentLineBeginsWithBrace || braceFormatMode == RUN_IN_MODE)-		{-			breakBrace = true;-		}-	}-	else if (braceFormatMode == NONE_MODE)-	{-		if (currentLineBeginsWithBrace-		        && currentLineFirstBraceNum == (size_t) charNum)-		{-			breakBrace = true;-		}-	}-	else if (braceFormatMode == BREAK_MODE || braceFormatMode == RUN_IN_MODE)-	{-		breakBrace = true;-	}-	else if (braceFormatMode == LINUX_MODE)-	{-		// break a namespace-		if (isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE))-		{-			if (formattingStyle != STYLE_STROUSTRUP-			        && formattingStyle != STYLE_MOZILLA-			        && formattingStyle != STYLE_WEBKIT)-			{-				breakBrace = true;-			}-		}-		// break a class or interface-		else if (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE)-		         || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE))-		{-			if (formattingStyle != STYLE_STROUSTRUP-			        && formattingStyle != STYLE_WEBKIT)-			{-				breakBrace = true;-			}-		}-		// break a struct if mozilla - an enum is processed as an array brace-		else if (isBraceType((*braceTypeStack)[stackEnd], STRUCT_TYPE))-		{-			if (formattingStyle == STYLE_MOZILLA)-			{-				breakBrace = true;-			}-		}-		// break the first brace if a function-		else if (isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE))-		{-			if (stackEnd == 1)-			{-				breakBrace = true;-			}-			else if (stackEnd > 1)-			{-				// break the first brace after these if a function-				if (isBraceType((*braceTypeStack)[stackEnd - 1], NAMESPACE_TYPE)-				        || isBraceType((*braceTypeStack)[stackEnd - 1], CLASS_TYPE)-				        || (isBraceType((*braceTypeStack)[stackEnd - 1], ARRAY_TYPE) && !lambdaIndicator)-				        || isBraceType((*braceTypeStack)[stackEnd - 1], STRUCT_TYPE)-				        || isBraceType((*braceTypeStack)[stackEnd - 1], EXTERN_TYPE)-				   )-				{-					breakBrace = true;-				}-			}-		}-	}--	//breakBrace = false;-	return breakBrace;+    assert(braceTypeStack->size() > 1);++    if (shouldPreserveBraceFormat)+        return currentLineBeginsWithBrace;++    bool breakBrace = false;+    size_t stackEnd = braceTypeStack->size() - 1;++    // check brace modifiers+    if (shouldAttachExternC+            && isBraceType((*braceTypeStack)[stackEnd], BraceType::EXTERN_TYPE))+    {+        return false;+    }+    if (shouldAttachNamespace+            && isBraceType((*braceTypeStack)[stackEnd], BraceType::NAMESPACE_TYPE))+    {+        return false;+    }+    if (shouldAttachClass+            && (isBraceType((*braceTypeStack)[stackEnd], BraceType::CLASS_TYPE)+                || isBraceType((*braceTypeStack)[stackEnd], BraceType::INTERFACE_TYPE)))+    {+        return false;+    }+    if (shouldAttachInline+            && isCStyle()			// for C++ only+            && braceFormatMode != RUN_IN_MODE+            && !(currentLineBeginsWithBrace && peekNextChar() == '/')+            && isBraceType((*braceTypeStack)[stackEnd], BraceType::COMMAND_TYPE))+    {+        size_t i;+        for (i = 1; i < braceTypeStack->size(); i++)+            if (isBraceType((*braceTypeStack)[i], BraceType::CLASS_TYPE)+                    || isBraceType((*braceTypeStack)[i], BraceType::STRUCT_TYPE))+                return false;+    }++    // check braces+    if (isBraceType((*braceTypeStack)[stackEnd], BraceType::EXTERN_TYPE))+    {+        if (currentLineBeginsWithBrace || braceFormatMode == RUN_IN_MODE)+        {+            breakBrace = true;+        }+    }+    else if (braceFormatMode == NONE_MODE)+    {+        if (currentLineBeginsWithBrace+                && currentLineFirstBraceNum == (size_t) charNum)+        {+            breakBrace = true;+        }+    }+    else if (braceFormatMode == BREAK_MODE || braceFormatMode == RUN_IN_MODE)+    {+        breakBrace = true;+    }+    else if (braceFormatMode == LINUX_MODE)+    {+        // break a namespace+        if (isBraceType((*braceTypeStack)[stackEnd], BraceType::NAMESPACE_TYPE))+        {+            if (formattingStyle != STYLE_STROUSTRUP+                    && formattingStyle != STYLE_MOZILLA+                    && formattingStyle != STYLE_WEBKIT)+            {+                breakBrace = true;+            }+        }+        // break a class or interface+        else if (isBraceType((*braceTypeStack)[stackEnd], BraceType::CLASS_TYPE)+                 || isBraceType((*braceTypeStack)[stackEnd], BraceType::INTERFACE_TYPE))+        {+            if (formattingStyle != STYLE_STROUSTRUP+                    && formattingStyle != STYLE_WEBKIT)+            {+                breakBrace = true;+            }+        }+        // break a struct if mozilla - an enum is processed as an array brace+        else if (isBraceType((*braceTypeStack)[stackEnd], BraceType::STRUCT_TYPE))+        {+            if (formattingStyle == STYLE_MOZILLA)+            {+                breakBrace = true;+            }+        }+        // break the first brace if a function+        else if (isBraceType((*braceTypeStack)[stackEnd], BraceType::COMMAND_TYPE))+        {+            if (stackEnd == 1)+            {+                breakBrace = true;+            }+            else if (stackEnd > 1)+            {+                // break the first brace after these if a function+                if (isBraceType((*braceTypeStack)[stackEnd - 1], BraceType::NAMESPACE_TYPE)+                        || isBraceType((*braceTypeStack)[stackEnd - 1], BraceType::CLASS_TYPE)+                        || (isBraceType((*braceTypeStack)[stackEnd - 1], BraceType::ARRAY_TYPE) && !lambdaIndicator)+                        || isBraceType((*braceTypeStack)[stackEnd - 1], BraceType::STRUCT_TYPE)+                        || isBraceType((*braceTypeStack)[stackEnd - 1], BraceType::EXTERN_TYPE)+                   )+                {+                    breakBrace = true;+                }+            }+        }+    }++    //breakBrace = false;+    return breakBrace; }  /**@@ -6197,24 +6675,24 @@ bool ASFormatter::isCurrentBraceBroken() const  */ void ASFormatter::formatCommentBody() {-	assert(isInComment);+    assert(isInComment); -	// append the comment-	while (charNum < (int) currentLine.length())-	{-		currentChar = currentLine[charNum];-		if (isSequenceReached(ASResource::AS_CLOSE_COMMENT) || (isGSCStyle() && isSequenceReached(ASResource::AS_GSC_CLOSE_COMMENT)) )-		{-			formatCommentCloser();-			break;-		}-		if (currentChar == '\t' && shouldConvertTabs)-			convertTabToSpaces();-		appendCurrentChar();-		++charNum;-	}-	if (shouldStripCommentPrefix)-		stripCommentPrefix();+    // append the comment+    while (charNum < (int) currentLine.length())+    {+        currentChar = currentLine[charNum];+        if (isSequenceReached(ASResource::AS_CLOSE_COMMENT) || (isGSCStyle() && isSequenceReached(ASResource::AS_GSC_CLOSE_COMMENT)) )+        {+            formatCommentCloser();+            break;+        }+        if (currentChar == '\t' && shouldConvertTabs)+            convertTabToSpaces();+        appendCurrentChar();+        ++charNum;+    }+    if (shouldStripCommentPrefix)+        stripCommentPrefix(); }  /**@@ -6224,97 +6702,97 @@ void ASFormatter::formatCommentBody()  */ void ASFormatter::formatCommentOpener() {-	assert(isSequenceReached(ASResource::AS_OPEN_COMMENT) || isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT));--	bool isCppComment = isSequenceReached(ASResource::AS_OPEN_COMMENT);--	isInComment = isInCommentStartLine = true;-	isImmediatelyPostLineComment = false;-	if (previousNonWSChar == '}')-		resetEndOfStatement();--	// Check for a following header.-	// For speed do not check multiple comment lines more than once.-	// For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.-	const std::string* followingHeader = nullptr;-	if ((doesLineStartComment-	        && !isImmediatelyPostCommentOnly-	        && isBraceType(braceTypeStack->back(), COMMAND_TYPE))-	        && (shouldBreakElseIfs-	            || isInSwitchStatement()-	            || (shouldBreakBlocks-	                && !isImmediatelyPostEmptyLine-	                && previousCommandChar != '{')))-		followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));--	if (spacePadNum != 0 && !isInLineBreak)-		adjustComments();-	formattedLineCommentNum = formattedLine.length();--	// must be done BEFORE appendSequence-	if (previousCommandChar == '{'-	        && !isImmediatelyPostComment-	        && !isImmediatelyPostLineComment)-	{-		if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))-		{-			// namespace run-in is always broken.-			isInLineBreak = true;-		}-		else if (braceFormatMode == NONE_MODE)-		{-			// should a run-in statement be attached?-			if (currentLineBeginsWithBrace)-				formatRunIn();-		}-		else if (braceFormatMode == ATTACH_MODE)-		{-			// if the brace was not attached?-			if (!formattedLine.empty() && formattedLine[0] == '{'-			        && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))-				isInLineBreak = true;-		}-		else if (braceFormatMode == RUN_IN_MODE)-		{-			// should a run-in statement be attached?-			if (!formattedLine.empty() && formattedLine[0] == '{')-				formatRunIn();-		}-	}-	else if (!doesLineStartComment)-		noTrimCommentContinuation = true;--	// ASBeautifier needs to know the following statements-	if (shouldBreakElseIfs && followingHeader == &ASResource::AS_ELSE)-		elseHeaderFollowsComments = true;-	if (followingHeader == &ASResource::AS_CASE || followingHeader == &ASResource::AS_DEFAULT)-		caseHeaderFollowsComments = true;--	// appendSequence will write the previous line-	appendSequence(isCppComment ? ASResource::AS_OPEN_COMMENT : ASResource::AS_GSC_OPEN_COMMENT);-	goForward(1);--	// must be done AFTER appendSequence--	// Break before the comment if a header follows the line comment.-	// But not break if previous line is empty, a comment, or a '{'.-	if (shouldBreakBlocks-	        && followingHeader != nullptr-	        && !isImmediatelyPostEmptyLine-	        && previousCommandChar != '{')-	{-		if (isClosingHeader(followingHeader))-		{-			if (!shouldBreakClosingHeaderBlocks)-				isPrependPostBlockEmptyLineRequested = false;-		}-		// if an opening header, break before the comment-		else-			isPrependPostBlockEmptyLineRequested = true;-	}--	if (previousCommandChar == '}')-		currentHeader = nullptr;+    assert(isSequenceReached(ASResource::AS_OPEN_COMMENT) || isSequenceReached(ASResource::AS_GSC_OPEN_COMMENT));++    bool isCppComment = isSequenceReached(ASResource::AS_OPEN_COMMENT);++    isInComment = isInCommentStartLine = true;+    isImmediatelyPostLineComment = false;+    if (previousNonWSChar == '}')+        resetEndOfStatement();++    // Check for a following header.+    // For speed do not check multiple comment lines more than once.+    // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.+    const std::string* followingHeader = nullptr;+    if ((doesLineStartComment+            && !isImmediatelyPostCommentOnly+            && isBraceType(braceTypeStack->back(), BraceType::COMMAND_TYPE))+            && (shouldBreakElseIfs+                || isInSwitchStatement()+                || (shouldBreakBlocks+                    && !isImmediatelyPostEmptyLine+                    && previousCommandChar != '{')))+        followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));++    if (spacePadNum != 0 && !isInLineBreak)+        adjustComments();+    formattedLineCommentNum = formattedLine.length();++    // must be done BEFORE appendSequence+    if (previousCommandChar == '{'+            && !isImmediatelyPostComment+            && !isImmediatelyPostLineComment)+    {+        if (isBraceType(braceTypeStack->back(), BraceType::NAMESPACE_TYPE))+        {+            // namespace run-in is always broken.+            isInLineBreak = true;+        }+        else if (braceFormatMode == NONE_MODE)+        {+            // should a run-in statement be attached?+            if (currentLineBeginsWithBrace)+                formatRunIn();+        }+        else if (braceFormatMode == ATTACH_MODE)+        {+            // if the brace was not attached?+            if (!formattedLine.empty() && formattedLine[0] == '{'+                    && !isBraceType(braceTypeStack->back(), BraceType::SINGLE_LINE_TYPE))+                isInLineBreak = true;+        }+        else if (braceFormatMode == RUN_IN_MODE)+        {+            // should a run-in statement be attached?+            if (!formattedLine.empty() && formattedLine[0] == '{')+                formatRunIn();+        }+    }+    else if (!doesLineStartComment)+        noTrimCommentContinuation = true;++    // ASBeautifier needs to know the following statements+    if (shouldBreakElseIfs && followingHeader == &ASResource::AS_ELSE)+        elseHeaderFollowsComments = true;+    if (followingHeader == &ASResource::AS_CASE || followingHeader == &ASResource::AS_DEFAULT)+        caseHeaderFollowsComments = true;++    // appendSequence will write the previous line+    appendSequence(isCppComment ? ASResource::AS_OPEN_COMMENT : ASResource::AS_GSC_OPEN_COMMENT);+    goForward(1);++    // must be done AFTER appendSequence++    // Break before the comment if a header follows the line comment.+    // But not break if previous line is empty, a comment, or a '{'.+    if (shouldBreakBlocks+            && followingHeader != nullptr+            && !isImmediatelyPostEmptyLine+            && previousCommandChar != '{')+    {+        if (isClosingHeader(followingHeader))+        {+            if (!shouldBreakClosingHeaderBlocks)+                isPrependPostBlockEmptyLineRequested = false;+        }+        // if an opening header, break before the comment+        else+            isPrependPostBlockEmptyLineRequested = true;+    }++    if (previousCommandChar == '}')+        currentHeader = nullptr; }  /**@@ -6323,24 +6801,24 @@ void ASFormatter::formatCommentOpener()  */ void ASFormatter::formatCommentCloser() {-	assert(isSequenceReached(ASResource::AS_CLOSE_COMMENT) || (isGSCStyle() && isSequenceReached(ASResource::AS_GSC_CLOSE_COMMENT)) );-	isInComment = false;-	noTrimCommentContinuation = false;-	isImmediatelyPostComment = true;-	appendSequence(isSequenceReached(ASResource::AS_CLOSE_COMMENT) ? ASResource::AS_CLOSE_COMMENT : ASResource::AS_GSC_CLOSE_COMMENT);-	goForward(1);-	if (doesLineStartComment-	        && (currentLine.find_first_not_of(" \t", charNum + 1) == std::string::npos))-		lineEndsInCommentOnly = true;-	if (peekNextChar() == '}'-	        && previousCommandChar != ';'-	        && !isBraceType(braceTypeStack->back(), ARRAY_TYPE)-	        && !isInPreprocessor-	        && isOkToBreakBlock(braceTypeStack->back()))-	{-		isInLineBreak = true;-		shouldBreakLineAtNextChar = true;-	}+    assert(isSequenceReached(ASResource::AS_CLOSE_COMMENT) || (isGSCStyle() && isSequenceReached(ASResource::AS_GSC_CLOSE_COMMENT)) );+    isInComment = false;+    noTrimCommentContinuation = false;+    isImmediatelyPostComment = true;+    appendSequence(isSequenceReached(ASResource::AS_CLOSE_COMMENT) ? ASResource::AS_CLOSE_COMMENT : ASResource::AS_GSC_CLOSE_COMMENT);+    goForward(1);+    if (doesLineStartComment+            && (currentLine.find_first_not_of(" \t", charNum + 1) == std::string::npos))+        lineEndsInCommentOnly = true;+    if (peekNextChar() == '}'+            && previousCommandChar != ';'+            && !isBraceType(braceTypeStack->back(), BraceType::ARRAY_TYPE)+            && !isInPreprocessor+            && isOkToBreakBlock(braceTypeStack->back()))+    {+        isInLineBreak = true;+        shouldBreakLineAtNextChar = true;+    } }  /**@@ -6349,27 +6827,27 @@ void ASFormatter::formatCommentCloser()  */ void ASFormatter::formatLineCommentBody() {-	assert(isInLineComment);+    assert(isInLineComment); -	// append the comment-	while (charNum < (int) currentLine.length())+    // append the comment+    while (charNum < (int) currentLine.length()) //	        && !isLineReady	// commented out in release 2.04, unnecessary-	{-		currentChar = currentLine[charNum];-		if (currentChar == '\t' && shouldConvertTabs)-			convertTabToSpaces();-		appendCurrentChar();-		++charNum;-	}+    {+        currentChar = currentLine[charNum];+        if (currentChar == '\t' && shouldConvertTabs)+            convertTabToSpaces();+        appendCurrentChar();+        ++charNum;+    } -	// explicitly break a line when a line comment's end is found.-	if (charNum == (int) currentLine.length())-	{-		isInLineBreak = true;-		isInLineComment = false;-		isImmediatelyPostLineComment = true;-		currentChar = 0;  //make sure it is a neutral char.-	}+    // explicitly break a line when a line comment's end is found.+    if (charNum == (int) currentLine.length())+    {+        isInLineBreak = true;+        isInLineComment = false;+        isImmediatelyPostLineComment = true;+        currentChar = 0;  //make sure it is a neutral char.+    } }  /**@@ -6379,127 +6857,127 @@ void ASFormatter::formatLineCommentBody()  */ void ASFormatter::formatLineCommentOpener() {-	assert(isSequenceReached(ASResource::AS_OPEN_LINE_COMMENT));--	if ((int) currentLine.length() > charNum + 2-	        && currentLine[charNum + 2] == '\xf2')     // check for windows line marker-		isAppendPostBlockEmptyLineRequested = false;--	isInLineComment = true;-	isCharImmediatelyPostComment = false;-	if (previousNonWSChar == '}')-		resetEndOfStatement();--	// Check for a following header.-	// For speed do not check multiple comment lines more than once.-	// For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.-	const std::string* followingHeader = nullptr;-	if ((lineIsLineCommentOnly-	        && !isImmediatelyPostCommentOnly-	        && isBraceType(braceTypeStack->back(), COMMAND_TYPE))-	        && (shouldBreakElseIfs-	            || isInSwitchStatement()-	            || (shouldBreakBlocks-	                && !isImmediatelyPostEmptyLine-	                && previousCommandChar != '{')))-		followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));--	// do not indent if in column 1 or 2-	// or in a namespace before the opening brace-	if ((!shouldIndentCol1Comments && !lineCommentNoIndent)-	        || foundNamespaceHeader)-	{-		if (charNum == 0)-			lineCommentNoIndent = true;-		else if (charNum == 1 && currentLine[0] == ' ')-			lineCommentNoIndent = true;-	}-	// move comment if spaces were added or deleted-	if (!lineCommentNoIndent && spacePadNum != 0 && !isInLineBreak)-		adjustComments();-	formattedLineCommentNum = formattedLine.length();--	// must be done BEFORE appendSequence-	// check for run-in statement-	if (previousCommandChar == '{'-	        && !isImmediatelyPostComment-	        && !isImmediatelyPostLineComment)-	{-		if (braceFormatMode == NONE_MODE)-		{-			if (currentLineBeginsWithBrace)-				formatRunIn();-		}-		else if (braceFormatMode == RUN_IN_MODE)-		{-			if (!lineCommentNoIndent)-				formatRunIn();-			else-				isInLineBreak = true;-		}-		else if (braceFormatMode == BREAK_MODE)-		{-			if (!formattedLine.empty() && formattedLine[0] == '{')-				isInLineBreak = true;-		}-		else-		{-			if (currentLineBeginsWithBrace)-				isInLineBreak = true;-		}-	}--	// ASBeautifier needs to know the following statements-	if (shouldBreakElseIfs && followingHeader == &ASResource::AS_ELSE)-		elseHeaderFollowsComments = true;-	if (followingHeader == &ASResource::AS_CASE || followingHeader == &ASResource::AS_DEFAULT)-		caseHeaderFollowsComments = true;--	// appendSequence will write the previous line-	appendSequence(ASResource::AS_OPEN_LINE_COMMENT);-	goForward(1);--	// must be done AFTER appendSequence--	// Break before the comment if a header follows the line comment.-	// But do not break if previous line is empty, a comment, or a '{'.-	if (shouldBreakBlocks-	        && followingHeader != nullptr-	        && !isImmediatelyPostEmptyLine-	        && previousCommandChar != '{')-	{-		if (isClosingHeader(followingHeader))-		{-			if (!shouldBreakClosingHeaderBlocks)-				isPrependPostBlockEmptyLineRequested = false;-		}-		// if an opening header, break before the comment-		else-			isPrependPostBlockEmptyLineRequested = true;-	}--	if (previousCommandChar == '}')-		currentHeader = nullptr;--	// if tabbed input don't convert the immediately following tabs to spaces-	if (getIndentString() == "\t" && lineCommentNoIndent)-	{-		while (charNum + 1 < (int) currentLine.length()-		        && currentLine[charNum + 1] == '\t')-		{-			currentChar = currentLine[++charNum];-			appendCurrentChar();-		}-	}--	// explicitly break a line when a line comment's end is found.-	if (charNum + 1 == (int) currentLine.length())-	{-		isInLineBreak = true;-		isInLineComment = false;-		isImmediatelyPostLineComment = true;-		currentChar = 0;  //make sure it is a neutral char.-	}+    assert(isSequenceReached(ASResource::AS_OPEN_LINE_COMMENT));++    if ((int) currentLine.length() > charNum + 2+            && currentLine[charNum + 2] == '\xf2')     // check for windows line marker+        isAppendPostBlockEmptyLineRequested = false;++    isInLineComment = true;+    isCharImmediatelyPostComment = false;+    if (previousNonWSChar == '}')+        resetEndOfStatement();++    // Check for a following header.+    // For speed do not check multiple comment lines more than once.+    // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.+    const std::string* followingHeader = nullptr;+    if ((lineIsLineCommentOnly+            && !isImmediatelyPostCommentOnly+            && isBraceType(braceTypeStack->back(), BraceType::COMMAND_TYPE))+            && (shouldBreakElseIfs+                || isInSwitchStatement()+                || (shouldBreakBlocks+                    && !isImmediatelyPostEmptyLine+                    && previousCommandChar != '{')))+        followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));++    // do not indent if in column 1 or 2+    // or in a namespace before the opening brace+    if ((!shouldIndentCol1Comments && !lineCommentNoIndent)+            || foundNamespaceHeader)+    {+        if (charNum == 0)+            lineCommentNoIndent = true;+        else if (charNum == 1 && currentLine[0] == ' ')+            lineCommentNoIndent = true;+    }+    // move comment if spaces were added or deleted+    if (!lineCommentNoIndent && spacePadNum != 0 && !isInLineBreak)+        adjustComments();+    formattedLineCommentNum = formattedLine.length();++    // must be done BEFORE appendSequence+    // check for run-in statement+    if (previousCommandChar == '{'+            && !isImmediatelyPostComment+            && !isImmediatelyPostLineComment)+    {+        if (braceFormatMode == NONE_MODE)+        {+            if (currentLineBeginsWithBrace)+                formatRunIn();+        }+        else if (braceFormatMode == RUN_IN_MODE)+        {+            if (!lineCommentNoIndent)+                formatRunIn();+            else+                isInLineBreak = true;+        }+        else if (braceFormatMode == BREAK_MODE)+        {+            if (!formattedLine.empty() && formattedLine[0] == '{')+                isInLineBreak = true;+        }+        else+        {+            if (currentLineBeginsWithBrace)+                isInLineBreak = true;+        }+    }++    // ASBeautifier needs to know the following statements+    if (shouldBreakElseIfs && followingHeader == &ASResource::AS_ELSE)+        elseHeaderFollowsComments = true;+    if (followingHeader == &ASResource::AS_CASE || followingHeader == &ASResource::AS_DEFAULT)+        caseHeaderFollowsComments = true;++    // appendSequence will write the previous line+    appendSequence(ASResource::AS_OPEN_LINE_COMMENT);+    goForward(1);++    // must be done AFTER appendSequence++    // Break before the comment if a header follows the line comment.+    // But do not break if previous line is empty, a comment, or a '{'.+    if (shouldBreakBlocks+            && followingHeader != nullptr+            && !isImmediatelyPostEmptyLine+            && previousCommandChar != '{')+    {+        if (isClosingHeader(followingHeader))+        {+            if (!shouldBreakClosingHeaderBlocks)+                isPrependPostBlockEmptyLineRequested = false;+        }+        // if an opening header, break before the comment+        else+            isPrependPostBlockEmptyLineRequested = true;+    }++    if (previousCommandChar == '}')+        currentHeader = nullptr;++    // if tabbed input don't convert the immediately following tabs to spaces+    if (getIndentString() == "\t" && lineCommentNoIndent)+    {+        while (charNum + 1 < (int) currentLine.length()+                && currentLine[charNum + 1] == '\t')+        {+            currentChar = currentLine[++charNum];+            appendCurrentChar();+        }+    }++    // explicitly break a line when a line comment's end is found.+    if (charNum + 1 == (int) currentLine.length())+    {+        isInLineBreak = true;+        isInLineComment = false;+        isImmediatelyPostLineComment = true;+        currentChar = 0;  //make sure it is a neutral char.+    } }  /**@@ -6508,93 +6986,93 @@ void ASFormatter::formatLineCommentOpener()  */ void ASFormatter::formatQuoteBody() {-	assert(isInQuote);--	int _braceCount = 0;--	if (checkInterpolation && currentChar == '{')-	{-		++_braceCount;-	}--	if (isSpecialChar)-	{-		isSpecialChar = false;-	}-	else if (currentChar == '\\' && !isInVerbatimQuote)-	{-		if (peekNextChar() == ' ')              // is this '\' at end of line-			haveLineContinuationChar = true;-		else-			isSpecialChar = true;-	}-	else if (isInVerbatimQuote && currentChar == '"' )-	{-		if (isCStyle())-		{-			std::string delim = ')' + verbatimDelimiter;-			int delimStart = charNum - delim.length();-			if (delimStart >= 0 && currentLine.substr(delimStart, delim.length()) == delim)-			{-				isInQuote = false;-				isInVerbatimQuote = false;-				checkInterpolation = false;-			}-		}-		else if (isSharpStyle() )       // GH16-		{-			if ((int) currentLine.length() > charNum + 1-			        && currentLine[charNum + 1] == '"')			// check consecutive quotes-			{-				appendSequence("\"\"");-				goForward(1);-				return;-			}--			//if ( charNum>0 && currentLine[charNum - 1] != '\\')-			isInQuote = false;--			if (checkInterpolation)-				isInVerbatimQuote = false;--			checkInterpolation = false;-		}-	}-	else if (quoteChar == currentChar)-	{-		////do not quit if we have CS std::string with interpolation-		isInQuote = false;-	}--	appendCurrentChar();--	// append the text to the ending quoteChar or an escape sequence-	// tabs in quotes are NOT changed by convert-tabs-	if (isInQuote && currentChar != '\\')-	{-		while (charNum + 1 < (int) currentLine.length()-		        && ( currentLine[charNum + 1] != quoteChar || _braceCount > 0 )-		        && currentLine[charNum + 1] != '\\')-		{-			currentChar = currentLine[++charNum];--			if (checkInterpolation)-			{-				if (currentChar == '{')-					++_braceCount;--				if (currentChar == '}')-					--_braceCount;-			}-			appendCurrentChar();-		}-	}-	if (charNum + 1 >= (int) currentLine.length()-	        && currentChar != '\\'-	        && !isInVerbatimQuote)-	{-		isInQuote = false;				// missing closing quote-	}+    assert(isInQuote);++    int _braceCount = 0;++    if (checkInterpolation && currentChar == '{')+    {+        ++_braceCount;+    }++    if (isSpecialChar)+    {+        isSpecialChar = false;+    }+    else if (currentChar == '\\' && !isInVerbatimQuote)+    {+        if (peekNextChar() == ' ')              // is this '\' at end of line+            haveLineContinuationChar = true;+        else+            isSpecialChar = true;+    }+    else if (isInVerbatimQuote && currentChar == '"' )+    {+        if (isCStyle())+        {+            std::string delim = ')' + verbatimDelimiter;+            int delimStart = charNum - delim.length();+            if (delimStart >= 0 && currentLine.substr(delimStart, delim.length()) == delim)+            {+                isInQuote = false;+                isInVerbatimQuote = false;+                checkInterpolation = false;+            }+        }+        else if (isSharpStyle() )       // GH16+        {+            if ((int) currentLine.length() > charNum + 1+                    && currentLine[charNum + 1] == '"')			// check consecutive quotes+            {+                appendSequence("\"\"");+                goForward(1);+                return;+            }++            //if ( charNum>0 && currentLine[charNum - 1] != '\\')+            isInQuote = false;++            if (checkInterpolation)+                isInVerbatimQuote = false;++            checkInterpolation = false;+        }+    }+    else if (quoteChar == currentChar)+    {+        ////do not quit if we have CS std::string with interpolation+        isInQuote = false;+    }++    appendCurrentChar();++    // append the text to the ending quoteChar or an escape sequence+    // tabs in quotes are NOT changed by convert-tabs+    if (isInQuote && currentChar != '\\')+    {+        while (charNum + 1 < (int) currentLine.length()+                && ( currentLine[charNum + 1] != quoteChar || _braceCount > 0 )+                && currentLine[charNum + 1] != '\\')+        {+            currentChar = currentLine[++charNum];++            if (checkInterpolation)+            {+                if (currentChar == '{')+                    ++_braceCount;++                if (currentChar == '}')+                    --_braceCount;+            }+            appendCurrentChar();+        }+    }+    if (charNum + 1 >= (int) currentLine.length()+            && currentChar != '\\'+            && !isInVerbatimQuote)+    {+        isInQuote = false;				// missing closing quote+    }  } @@ -6605,59 +7083,59 @@ void ASFormatter::formatQuoteBody()  */ void ASFormatter::formatQuoteOpener() {-	assert(currentChar == '"'-	       || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)));--	isInQuote = true;-	quoteChar = currentChar;--	char prevPrevCh = charNum > 2 ? currentLine[charNum - 2] : ' '; // GL39-	if (isCStyle() && previousChar == 'R' && !isalpha(prevPrevCh))-	{-		int parenPos = currentLine.find('(', charNum);-		if (parenPos != -1)-		{-			isInVerbatimQuote = true;-			verbatimDelimiter = currentLine.substr(charNum + 1, parenPos - charNum - 1);-		}-	}-	else if (isSharpStyle() && (previousChar == '@' ))-	{-		isInVerbatimQuote = true;-		checkInterpolation = true;-	}---	// a quote following a brace is an array-	if (previousCommandChar == '{'-	        && !isImmediatelyPostComment-	        && !isImmediatelyPostLineComment-	        && isNonInStatementArray-	        && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)-	        && !std::isblank(peekNextChar()))-	{-		if (braceFormatMode == NONE_MODE)-		{-			if (currentLineBeginsWithBrace)-				formatRunIn();-		}-		else if (braceFormatMode == RUN_IN_MODE)-		{-			formatRunIn();-		}-		else if (braceFormatMode == BREAK_MODE)-		{-			if (!formattedLine.empty() && formattedLine[0] == '{')-				isInLineBreak = true;-		}-		else-		{-			if (currentLineBeginsWithBrace)-				isInLineBreak = true;-		}-	}-	previousCommandChar = ' ';-	appendCurrentChar();+    assert(currentChar == '"'+           || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)));++    isInQuote = true;+    quoteChar = currentChar;++    char prevPrevCh = charNum > 2 ? currentLine[charNum - 2] : ' '; // GL39+    if (isCStyle() && previousChar == 'R' && !isalpha(prevPrevCh))+    {+        int parenPos = currentLine.find('(', charNum);+        if (parenPos != -1)+        {+            isInVerbatimQuote = true;+            verbatimDelimiter = currentLine.substr(charNum + 1, parenPos - charNum - 1);+        }+    }+    else if (isSharpStyle() && (previousChar == '@' ))+    {+        isInVerbatimQuote = true;+        checkInterpolation = true;+    }+++    // a quote following a brace is an array+    if (previousCommandChar == '{'+            && !isImmediatelyPostComment+            && !isImmediatelyPostLineComment+            && isNonInStatementArray+            && !isBraceType(braceTypeStack->back(), BraceType::SINGLE_LINE_TYPE)+            && !std::isblank(peekNextChar()))+    {+        if (braceFormatMode == NONE_MODE)+        {+            if (currentLineBeginsWithBrace)+                formatRunIn();+        }+        else if (braceFormatMode == RUN_IN_MODE)+        {+            formatRunIn();+        }+        else if (braceFormatMode == BREAK_MODE)+        {+            if (!formattedLine.empty() && formattedLine[0] == '{')+                isInLineBreak = true;+        }+        else+        {+            if (currentLineBeginsWithBrace)+                isInLineBreak = true;+        }+    }+    previousCommandChar = ' ';+    appendCurrentChar(); }  /**@@ -6667,19 +7145,24 @@ void ASFormatter::formatQuoteOpener()  */ int ASFormatter::getNextLineCommentAdjustment() {-	assert(foundClosingHeader && previousNonWSChar == '}');-	if (charNum < 1)			// "else" is in column 1-		return 0;-	size_t lastBrace = currentLine.rfind('}', charNum - 1);-	if (lastBrace != std::string::npos)-		return (lastBrace - charNum);	// return a negative number-	return 0;+    assert(foundClosingHeader && previousNonWSChar == '}');+    if (charNum < 1)			// "else" is in column 1+        return 0;+    size_t lastBrace = currentLine.rfind('}', charNum - 1);+    if (lastBrace != std::string::npos)+        return (lastBrace - charNum);	// return a negative number+    return 0; }  // for console build only LineEndFormat ASFormatter::getLineEndFormat() const {-	return lineEnd;+    return lineEnd;+}++bool ASFormatter::getEOFNewlineMode() const+{+    return shouldEndWithSingleNewline; }  /**@@ -6691,13 +7174,13 @@ LineEndFormat ASFormatter::getLineEndFormat() const  */ int ASFormatter::getCurrentLineCommentAdjustment() {-	assert(foundClosingHeader && previousNonWSChar == '}');-	if (charNum < 1)-		return 2;-	size_t lastBrace = currentLine.rfind('}', charNum - 1);-	if (lastBrace == std::string::npos)-		return 2;-	return 0;+    assert(foundClosingHeader && previousNonWSChar == '}');+    if (charNum < 1)+        return 2;+    size_t lastBrace = currentLine.rfind('}', charNum - 1);+    if (lastBrace == std::string::npos)+        return 2;+    return 0; }  /**@@ -6706,25 +7189,25 @@ int ASFormatter::getCurrentLineCommentAdjustment()  *  * @return is the previous word or an empty std::string if none found.  */-std::string ASFormatter::getPreviousWord(const std::string& line, int currPos, bool allowDots) const+std::string_view ASFormatter::getPreviousWord(const std::string& line, int currPos, bool allowDots) const {-	// get the last legal word (may be a number)-	if (currPos == 0)-		return std::string();+    // get the last legal word (may be a number)+    if (currPos == 0)+        return std::string_view(); -	size_t end = line.find_last_not_of(" \t", currPos - 1);-	if (end == std::string::npos || !isLegalNameChar(line[end]))-		return std::string();+    size_t end = line.find_last_not_of(" \t", currPos - 1);+    if (end == std::string::npos || !isLegalNameChar(line[end]))+        return std::string_view(); -	int start;          // start of the previous word-	for (start = end; start > -1; start--)-	{-		if (!isLegalNameChar(line[start]) || (!allowDots && line[start] == '.') )-			break;-	}-	start++;+    int start;          // start of the previous word+    for (start = end; start > -1; start--)+    {+        if (!isLegalNameChar(line[start]) || (!allowDots && line[start] == '.') )+            break;+    }+    start++; -	return (line.substr(start, end - start + 1));+    return std::string_view(line).substr(start, end - start + 1); }  /**@@ -6734,54 +7217,57 @@ std::string ASFormatter::getPreviousWord(const std::string& line, int currPos, b  */ void ASFormatter::isLineBreakBeforeClosingHeader() {-	assert(foundClosingHeader && previousNonWSChar == '}');--	if (currentHeader == &ASResource::AS_WHILE && shouldAttachClosingWhile)-	{-		appendClosingHeader();-		return;-	}--	if (braceFormatMode == BREAK_MODE-	        || braceFormatMode == RUN_IN_MODE-	        || attachClosingBraceMode)-	{-		isInLineBreak = true;-	}-	else if (braceFormatMode == NONE_MODE)-	{-		if (shouldBreakClosingHeaderBraces-		        || getBraceIndent() || getBlockIndent())-		{-			isInLineBreak = true;-		}-		else-		{-			appendSpacePad();-			// is closing brace broken?-			size_t i = currentLine.find_first_not_of(" \t");-			if (i != std::string::npos && currentLine[i] == '}')-				isInLineBreak = false;--			if (shouldBreakBlocks)-				isAppendPostBlockEmptyLineRequested = false;-		}-	}-	// braceFormatMode == ATTACH_MODE, LINUX_MODE-	else-	{-		if (shouldBreakClosingHeaderBraces-		        || getBraceIndent() || getBlockIndent())-		{-			isInLineBreak = true;-		}-		else-		{-			appendClosingHeader();-			if (shouldBreakBlocks)-				isAppendPostBlockEmptyLineRequested = false;-		}-	}+    assert(foundClosingHeader && previousNonWSChar == '}');++    if (shouldPreserveBraceFormat)+        return;++    if (currentHeader == &ASResource::AS_WHILE && shouldAttachClosingWhile)+    {+        appendClosingHeader();+        return;+    }++    if (braceFormatMode == BREAK_MODE+            || braceFormatMode == RUN_IN_MODE+            || attachClosingBraceMode)+    {+        isInLineBreak = true;+    }+    else if (braceFormatMode == NONE_MODE)+    {+        if (shouldBreakClosingHeaderBraces+                || getBraceIndent() || getBlockIndent())+        {+            isInLineBreak = true;+        }+        else+        {+            appendSpacePad();+            // is closing brace broken?+            size_t i = currentLine.find_first_not_of(" \t");+            if (i != std::string::npos && currentLine[i] == '}')+                isInLineBreak = false;++            if (shouldBreakBlocks)+                isAppendPostBlockEmptyLineRequested = false;+        }+    }+    // braceFormatMode == ATTACH_MODE, LINUX_MODE+    else+    {+        if (shouldBreakClosingHeaderBraces+                || getBraceIndent() || getBlockIndent())+        {+            isInLineBreak = true;+        }+        else+        {+            appendClosingHeader();+            if (shouldBreakBlocks)+                isAppendPostBlockEmptyLineRequested = false;+        }+    } }  /**@@ -6789,20 +7275,20 @@ void ASFormatter::isLineBreakBeforeClosingHeader()  */ void ASFormatter::appendClosingHeader() {-	// if a blank line does not precede this-	// or last line is not a one line block, attach header-	bool previousLineIsEmpty = isEmptyLine(formattedLine);-	int previousLineIsOneLineBlock = 0;-	size_t firstBrace = findNextChar(formattedLine, '{');-	if (firstBrace != std::string::npos)-		previousLineIsOneLineBlock = isOneLineBlockReached(formattedLine, firstBrace);-	if (!previousLineIsEmpty-	        && previousLineIsOneLineBlock == 0)-	{-		isInLineBreak = false;-		appendSpacePad();-		spacePadNum = 0;	// don't count as comment padding-	}+    // if a blank line does not precede this+    // or last line is not a one line block, attach header+    bool previousLineIsEmpty = isEmptyLine(formattedLine);+    int previousLineIsOneLineBlock = 0;+    size_t firstBrace = findNextChar(formattedLine, '{');+    if (firstBrace != std::string::npos)+        previousLineIsOneLineBlock = isOneLineBlockReached(formattedLine, firstBrace);+    if (!previousLineIsEmpty+            && previousLineIsOneLineBlock == 0)+    {+        isInLineBreak = false;+        appendSpacePad();+        spacePadNum = 0;	// don't count as comment padding+    } }  /**@@ -6812,64 +7298,165 @@ void ASFormatter::appendClosingHeader()  */ bool ASFormatter::addBracesToStatement() {-	assert(isImmediatelyPostHeader);--	if (currentHeader != &ASResource::AS_IF-	        && currentHeader != &ASResource::AS_ELSE-	        && currentHeader != &ASResource::AS_FOR-	        && currentHeader != &ASResource::AS_WHILE-	        && currentHeader != &ASResource::AS_DO-	        && currentHeader != &ASResource::AS_FOREACH-	        && currentHeader != &ASResource::AS_QFOREACH-	        && currentHeader != &ASResource::AS_QFOREVER-	        && currentHeader != &ASResource::AS_FOREVER)-		return false;--	if (currentHeader == &ASResource::AS_WHILE && foundClosingHeader)	// do-while-		return false;--	// do not brace an empty statement-	if (currentChar == ';')-		return false;---	// old behavior-	if (shouldAddBraces)-	{--		// do not add if a header follows-		if (isCharPotentialHeader(currentLine, charNum))-			if (findHeader(headers) != nullptr)-				return false;--		// find the next semi-colon-		size_t nextSemiColon = charNum;-		if (currentChar != ';')-			nextSemiColon = findNextChar(currentLine, ';', charNum + 1);-		if (nextSemiColon == std::string::npos)-			return false;--		// add closing brace before changing the line length-		if (nextSemiColon == currentLine.length() - 1)-			currentLine.append(" }");-		else-			currentLine.insert(nextSemiColon + 1, " }");-	}--	// add opening brace-	currentLine.insert(charNum, "{ ");-	assert(computeChecksumIn("{}"));-	currentChar = '{';-	if ((int) currentLine.find_first_not_of(" \t") == charNum)-		currentLineBeginsWithBrace = true;-	// remove extra spaces-	if (!shouldAddOneLineBraces)-	{-		size_t lastText = formattedLine.find_last_not_of(" \t");-		if ((formattedLine.length() - 1) - lastText > 1)-			formattedLine.erase(lastText + 1);-	}-	return true;+    assert(isImmediatelyPostHeader);++    if (currentHeader != &ASResource::AS_IF+            && currentHeader != &ASResource::AS_ELSE+            && currentHeader != &ASResource::AS_FOR+            && currentHeader != &ASResource::AS_WHILE+            && currentHeader != &ASResource::AS_DO+            && currentHeader != &ASResource::AS_FOREACH+            && currentHeader != &ASResource::AS_QFOREACH+            && currentHeader != &ASResource::AS_QFOREVER+            && currentHeader != &ASResource::AS_FOREVER)+        return false;++    if (currentHeader == &ASResource::AS_WHILE && foundClosingHeader)	// do-while+        return false;++    // do not brace an empty statement+    if (currentChar == ';')+        return false;+++    // old behavior+    if (shouldAddBraces)+    {++        // do not add if a header follows+        if (isCharPotentialHeader(currentLine, charNum))+            if (findHeader(headers.get()) != nullptr)+                return false;++        // find the next semi-colon+        size_t nextSemiColon = charNum;+        if (currentChar != ';')+            nextSemiColon = findNextChar(currentLine, ';', charNum + 1);+        if (nextSemiColon == std::string::npos)+        {+            // a statement continued on the following lines gets the closing brace+            // when its terminating semi-colon is reached (not for one-line braces)+            if (shouldAddOneLineBraces || !isMultiLineStatementEndFound())+                return false;+            shouldAddClosingBraceAtStatementEnd = true;+            addedBraceStatementParenDepth = 0;+        }+        // add closing brace before changing the line length+        else if (nextSemiColon == currentLine.length() - 1)+            currentLine.append(" }");+        else+            currentLine.insert(nextSemiColon + 1, " }");+    }++    // add opening brace+    currentLine.insert(charNum, "{ ");+    assert(computeChecksumIn(shouldAddClosingBraceAtStatementEnd ? "{" : "{}"));+    currentChar = '{';+    if ((int) currentLine.find_first_not_of(" \t") == charNum)+        currentLineBeginsWithBrace = true;+    // remove extra spaces+    if (!shouldAddOneLineBraces)+    {+        size_t lastText = formattedLine.find_last_not_of(" \t");+        if ((formattedLine.length() - 1) - lastText > 1)+            formattedLine.erase(lastText + 1);+    }+    return true;+}++/**+ * Check if a statement starting at charNum of the currentLine and continued+ * on the following lines is terminated by a semi-colon that is not within+ * parens or square brackets.+ * The statement must not contain braces or preprocessor directives.+ * Comments and quotes are skipped.+ *+ * @return true if the terminating semi-colon was found.+ */+bool ASFormatter::isMultiLineStatementEndFound() const+{+    constexpr int maxLinesToCheck = 100;+    int parenDepth = 0;+    int linesChecked = 0;+    bool isInComment_ = false;+    bool isFirstLine = true;+    std::string line = currentLine;++    ASPeekStream stream(sourceIterator);+    while (isFirstLine || stream.hasMoreLines())+    {+        size_t i = 0;+        if (isFirstLine)+        {+            isFirstLine = false;+            i = charNum;+        }+        else+        {+            if (++linesChecked > maxLinesToCheck)+                return false;+            line = stream.peekNextLine();+            size_t firstChar = line.find_first_not_of(" \t");+            if (firstChar == std::string::npos)+                continue;+            if (!isInComment_ && line[firstChar] == '#')+                return false;+        }++        for (; i < line.length(); i++)+        {+            if (isInComment_)+            {+                size_t endComment = line.find("*/", i);+                if (endComment == std::string::npos)+                    break;+                isInComment_ = false;+                i = endComment + 1;+                continue;+            }+            if (line.compare(i, 2, "//") == 0)+                break;+            if (line.compare(i, 2, "/*") == 0)+            {+                isInComment_ = true;+                ++i;+                continue;+            }+            const char ch = line[i];+            if (ch == '"' || (ch == '\'' && !isDigitSeparator(line, i)))+            {+                // don't try to parse raw, verbatim or text block strings+                if (ch == '"'+                        && ((i > 0 && (line[i - 1] == 'R' || line[i - 1] == '@'))+                            || line.compare(i, 3, "\"\"\"") == 0))+                    return false;+                // find the end of the quote, it must be on the same line+                size_t j = i + 1;+                while (j < line.length() && line[j] != ch)+                {+                    if (line[j] == '\\')+                        ++j;+                    ++j;+                }+                if (j >= line.length())+                    return false;+                i = j;+                continue;+            }+            if (ch == '{' || ch == '}')+                return false;+            if (ch == '(' || ch == '[')+                ++parenDepth;+            else if (ch == ')' || ch == ']')+            {+                if (--parenDepth < 0)+                    return false;+            }+            else if (ch == ';' && parenDepth == 0)+                return true;+        }+    }+    return false; }  /**@@ -6879,82 +7466,82 @@ bool ASFormatter::addBracesToStatement()  */ bool ASFormatter::removeBracesFromStatement() {-	assert(isImmediatelyPostHeader);-	assert(currentChar == '{');--	if (currentHeader != &ASResource::AS_IF-	        && currentHeader != &ASResource::AS_ELSE-	        && currentHeader != &ASResource::AS_FOR-	        && currentHeader != &ASResource::AS_WHILE-	        && currentHeader != &ASResource::AS_FOREACH)-		return false;--	if (currentHeader == &ASResource::AS_WHILE && foundClosingHeader)	// do-while-		return false;--	bool isFirstLine = true;-	std::string nextLine_;-	// leave nextLine_ empty if end of line comment follows-	if (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace)-		nextLine_ = currentLine.substr(charNum + 1);-	size_t nextChar = 0;--	// find the first non-blank text-	ASPeekStream stream(sourceIterator);-	while (stream.hasMoreLines() || isFirstLine)-	{-		if (isFirstLine)-			isFirstLine = false;-		else-		{-			nextLine_ = stream.peekNextLine();-			nextChar = 0;-		}--		nextChar = nextLine_.find_first_not_of(" \t", nextChar);-		if (nextChar != std::string::npos)-			break;-	}-	if (!stream.hasMoreLines())-		return false;--	// don't remove if comments or a header follow the brace-	if ((nextLine_.compare(nextChar, 2, "/*") == 0)-	        || (nextLine_.compare(nextChar, 2, "//") == 0)-	        || (isCharPotentialHeader(nextLine_, nextChar)-	            && ASBase::findHeader(nextLine_, nextChar, headers) != nullptr))-		return false;--	// find the next semi-colon-	size_t nextSemiColon = nextChar;-	if (nextLine_[nextChar] != ';')-		nextSemiColon = findNextChar(nextLine_, ';', nextChar + 1);-	if (nextSemiColon == std::string::npos)-		return false;--	// find the closing brace-	isFirstLine = true;-	nextChar = nextSemiColon + 1;-	while (stream.hasMoreLines() || isFirstLine)-	{-		if (isFirstLine)-			isFirstLine = false;-		else-		{-			nextLine_ = stream.peekNextLine();-			nextChar = 0;-		}-		nextChar = nextLine_.find_first_not_of(" \t", nextChar);-		if (nextChar != std::string::npos)-			break;-	}-	if (nextLine_.empty() || nextLine_[nextChar] != '}')-		return false;--	// remove opening brace-	currentLine[charNum] = currentChar = ' ';-	assert(adjustChecksumIn(-'{'));-	return true;+    assert(isImmediatelyPostHeader);+    assert(currentChar == '{');++    if (currentHeader != &ASResource::AS_IF+            && currentHeader != &ASResource::AS_ELSE+            && currentHeader != &ASResource::AS_FOR+            && currentHeader != &ASResource::AS_WHILE+            && currentHeader != &ASResource::AS_FOREACH)+        return false;++    if (currentHeader == &ASResource::AS_WHILE && foundClosingHeader)	// do-while+        return false;++    bool isFirstLine = true;+    std::string nextLine_;+    // leave nextLine_ empty if end of line comment follows+    if (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace)+        nextLine_ = currentLine.substr(charNum + 1);+    size_t nextChar = 0;++    // find the first non-blank text+    ASPeekStream stream(sourceIterator);+    while (stream.hasMoreLines() || isFirstLine)+    {+        if (isFirstLine)+            isFirstLine = false;+        else+        {+            nextLine_ = stream.peekNextLine();+            nextChar = 0;+        }++        nextChar = nextLine_.find_first_not_of(" \t", nextChar);+        if (nextChar != std::string::npos)+            break;+    }+    if (!stream.hasMoreLines())+        return false;++    // don't remove if comments or a header follow the brace+    if ((nextLine_.compare(nextChar, 2, "/*") == 0)+            || (nextLine_.compare(nextChar, 2, "//") == 0)+            || (isCharPotentialHeader(nextLine_, nextChar)+                && ASBase::findHeader(nextLine_, nextChar, headers.get()) != nullptr))+        return false;++    // find the next semi-colon+    size_t nextSemiColon = nextChar;+    if (nextLine_[nextChar] != ';')+        nextSemiColon = findNextChar(nextLine_, ';', nextChar + 1);+    if (nextSemiColon == std::string::npos)+        return false;++    // find the closing brace+    isFirstLine = true;+    nextChar = nextSemiColon + 1;+    while (stream.hasMoreLines() || isFirstLine)+    {+        if (isFirstLine)+            isFirstLine = false;+        else+        {+            nextLine_ = stream.peekNextLine();+            nextChar = 0;+        }+        nextChar = nextLine_.find_first_not_of(" \t", nextChar);+        if (nextChar != std::string::npos)+            break;+    }+    if (nextLine_.empty() || nextLine_[nextChar] != '}')+        return false;++    // remove opening brace+    currentLine[charNum] = currentChar = ' ';+    assert(adjustChecksumIn(-'{'));+    return true; }  /**@@ -6967,50 +7554,88 @@ bool ASFormatter::removeBracesFromStatement()  */ size_t ASFormatter::findNextChar(std::string_view line, char searchChar, int searchStart /*0*/) const {-	// find the next searchChar-	size_t i;-	for (i = searchStart; i < line.length(); i++)-	{-		if (line.compare(i, 2, "//") == 0)-			return std::string::npos;-		if (line.compare(i, 2, "/*") == 0)-		{-			size_t endComment = line.find("*/", i + 2);-			if (endComment == std::string::npos)-				return std::string::npos;-			i = endComment + 2;-			if (i >= line.length())-				return std::string::npos;-		}-		if (line[i] == '"'-		        || (line[i] == '\'' && !isDigitSeparator(line, i)))-		{-			char quote = line[i];-			while (i < line.length())-			{-				size_t endQuote = line.find(quote, i + 1);-				if (endQuote == std::string::npos)-					return std::string::npos;-				i = endQuote;-				if (line[endQuote - 1] != '\\')	// check for '\"'-					break;-				if (line[endQuote - 2] == '\\')	// check for '\\'-					break;-			}-		}--		if (line[i] == searchChar)-			break;--		// for now don't process C# 'delegate' braces-		// do this last in case the search char is a '{'-		if (line[i] == '{')-			return std::string::npos;-	}-	if (i >= line.length())	// didn't find searchChar-		return std::string::npos;--	return i;+    // find the next searchChar+    size_t i;+    for (i = searchStart; i < line.length(); i++)+    {+        if (line.compare(i, 2, "//") == 0)+            return std::string::npos;+        if (line.compare(i, 2, "/*") == 0)+        {+            size_t endComment = line.find("*/", i + 2);+            if (endComment == std::string::npos)+                return std::string::npos;+            i = endComment + 2;+            if (i >= line.length())+                return std::string::npos;+        }+        if (line[i] == '"'+                || (line[i] == '\'' && !isDigitSeparator(line, i)))+        {+            char quote = line[i];+            while (i < line.length())+            {+                size_t endQuote = line.find(quote, i + 1);+                if (endQuote == std::string::npos)+                    return std::string::npos;+                i = endQuote;+                if (line[endQuote - 1] != '\\')	// check for '\"'+                    break;+                if (line[endQuote - 2] == '\\')	// check for '\\'+                    break;+            }+        }++        if (line[i] == searchChar)+            break;++        // for now don't process C# 'delegate' braces+        // do this last in case the search char is a '{'+        if (line[i] == '{')+            return std::string::npos;+    }+    if (i >= line.length())	// didn't find searchChar+        return std::string::npos;++    return i;+}++/**+ * Check if the text in line between start and end consists only of+ * function specifiers or modifiers (e.g. "explicit", "virtual", "public").+ * In this case there is no return type, e.g. for constructors, destructors+ * and conversion operators, and the line must not be broken.+ * https://sourceforge.net/p/astyle/bugs/499/+ */+bool ASFormatter::isOnlyFunctionSpecifiers(const std::string& line, size_t start, size_t end) const+{+    static const std::string_view specifiers[] =+    {+        "explicit", "virtual", "inline", "constexpr", "consteval",+        "static", "public", "protected", "private", "internal"+    };++    if (start >= end || end > line.length())+        return false;++    for (size_t i = start; i < end; )+    {+        if (std::isblank(line[i]))+        {+            ++i;+            continue;+        }+        size_t wordEnd = i;+        while (wordEnd < end && isLegalNameChar(line[wordEnd]))+            ++wordEnd;+        if (wordEnd == i)+            return false;+        const std::string_view word(line.data() + i, wordEnd - i);+        if (std::find(std::begin(specifiers), std::end(specifiers), word) == std::end(specifiers))+            return false;+        i = wordEnd;+    }+    return true; }  /**@@ -7018,284 +7643,288 @@ size_t ASFormatter::findNextChar(std::string_view line, char searchChar, int sea  */ void ASFormatter::findReturnTypeSplitPoint(const std::string& firstLine) {-	assert((isBraceType(braceTypeStack->back(), NULL_TYPE)-	        || isBraceType(braceTypeStack->back(), DEFINITION_TYPE)));-	assert(shouldBreakReturnType || shouldBreakReturnTypeDecl-	       || shouldAttachReturnType || shouldAttachReturnTypeDecl);--	bool isFirstLine     = true;-	bool isInComment_    = false;-	bool isInQuote_      = false;-	bool foundSplitPoint = false;-	bool isAlreadyBroken = false;-	char quoteChar_      = ' ';-	char currNonWSChar   = ' ';-	char prevNonWSChar   = ' ';-	size_t parenCount    = 0;-	size_t squareCount   = 0;-	size_t angleCount    = 0;-	size_t breakLineNum  = 0;-	size_t breakCharNum  = std::string::npos;-	std::string line          = firstLine;--	// Process the lines until a ';' or '{'.-	ASPeekStream stream(sourceIterator);-	while (stream.hasMoreLines() || isFirstLine)-	{-		if (isFirstLine)-			isFirstLine = false;-		else-		{-			if (isInQuote_)-				return;-			line = stream.peekNextLine();-			if (!foundSplitPoint)-				++breakLineNum;-		}-		size_t firstCharNum = line.find_first_not_of(" \t");-		if (firstCharNum == std::string::npos)-			continue;-		if (line[firstCharNum] == '#')-		{-			// don't attach to a preprocessor-			if (shouldAttachReturnType || shouldAttachReturnTypeDecl)-				return;-			continue;-		}-		// parse the line-		for (size_t i = 0; i < line.length(); i++)-		{-			if (!std::isblank(line[i]))-			{-				prevNonWSChar = currNonWSChar;-				currNonWSChar = line[i];-			}-			else if (line[i] == '\t' && shouldConvertTabs)-			{-				size_t tabSize = getTabLength();-				size_t numSpaces = tabSize - ((tabIncrementIn + i) % tabSize);-				line.replace(i, 1, numSpaces, ' ');-				currentChar = line[i];-			}-			if (line.compare(i, 2, "/*") == 0)-				isInComment_ = true;-			if (isInComment_)-			{-				if (line.compare(i, 2, "*/") == 0)-				{-					isInComment_ = false;-					++i;-				}-				continue;-			}-			if (line[i] == '\\')-			{-				++i;-				continue;-			}--			if (isInQuote_)-			{-				if (line[i] == quoteChar_)-					isInQuote_ = false;-				continue;-			}--			if (line[i] == '"'-			        || (line[i] == '\'' && !isDigitSeparator(line, i)))-			{-				isInQuote_ = true;-				quoteChar_ = line[i];-				continue;-			}-			if (line.compare(i, 2, "//") == 0)-			{-				i = line.length();-				continue;-			}--			// https://sourceforge.net/p/astyle/bugs/504/-			if (line[line.length() - 1] == ':')-			{-				i = line.length();-				foundSplitPoint = true;-				continue;-			}--			// not in quote or comment-			if (!foundSplitPoint)-			{-				if (line[i] == '<')-				{-					++angleCount;-					continue;-				}-				if (line[i] == '>')-				{-					if (angleCount)-						--angleCount;-					if (!angleCount)-					{-						size_t nextCharNum = line.find_first_not_of(" \t*&", i + 1);-						if (nextCharNum == std::string::npos)-						{-							breakCharNum  = std::string::npos;-							continue;-						}-						if (line[nextCharNum] != ':')		// scope operator-							breakCharNum  = nextCharNum;-					}-					continue;-				}-				if (angleCount)-					continue;-				if (line[i] == '[')-				{-					++squareCount;-					continue;-				}-				if (line[i] == ']')-				{-					if (squareCount)-						--squareCount;-					continue;-				}-				// an assignment before the parens is not a function-				if (line[i] == '=')-					return;-				if (std::isblank(line[i]) || line[i] == '*' || line[i] == '&')-				{-					size_t nextNum = line.find_first_not_of(" \t", i + 1);-					if (nextNum == std::string::npos)-						breakCharNum = std::string::npos;-					else-					{-						if (line.length() > nextNum + 1-						        && line[nextNum] == ':' && line[nextNum + 1] == ':')-							i = --nextNum;-						else if (line[nextNum] != '(')-							breakCharNum = std::string::npos;-					}-					continue;-				}-				if ((isLegalNameChar(line[i]) || line[i] == '~')-				        && breakCharNum == std::string::npos)-				{-					breakCharNum = i;-					if (isLegalNameChar(line[i])-					        && findKeyword(line, i, ASResource::AS_OPERATOR))-					{-						if (breakCharNum == firstCharNum)-							isAlreadyBroken = true;-						foundSplitPoint = true;-						// find the operator, may be parens-						size_t parenNum =-						    line.find_first_not_of(" \t", i + ASResource::AS_OPERATOR.length());-						if (parenNum == std::string::npos)-							return;-						// find paren after the operator-						parenNum = line.find('(', parenNum + 1);-						if (parenNum == std::string::npos)-							return;-						i = --parenNum;-					}-					continue;-				}-				if (line[i] == ':'-				        && line.length() > i + 1-				        && line[i + 1] == ':')-				{-					size_t nextCharNum = line.find_first_not_of(" \t:", i + 1);-					if (nextCharNum == std::string::npos)-						return;--					if (isLegalNameChar(line[nextCharNum])-					        && findKeyword(line, nextCharNum, ASResource::AS_OPERATOR))-					{-						i = nextCharNum;-						if (breakCharNum == firstCharNum)-							isAlreadyBroken = true;-						foundSplitPoint = true;-						// find the operator, may be parens-						size_t parenNum =-						    line.find_first_not_of(" \t", i + ASResource::AS_OPERATOR.length());-						if (parenNum == std::string::npos)-							return;-						// find paren after the operator-						parenNum = line.find('(', parenNum + 1);-						if (parenNum == std::string::npos)-							return;-						i = --parenNum;-					}-					else-						i = --nextCharNum;-					continue;-				}-				if (line[i] == '(' && !squareCount)-				{--					// is line is already broken?-					if (breakCharNum == firstCharNum && breakLineNum > 0)-						isAlreadyBroken = true;-					++parenCount;-					foundSplitPoint = true;-					continue;-				}-			}-			// end !foundSplitPoint-			if (line[i] == '(')-			{-				// consecutive ')(' parens is probably a function pointer-				if (prevNonWSChar == ')' && !parenCount)-					return;-				++parenCount;-				continue;-			}-			if (line[i] == ')')-			{-				if (parenCount)-					--parenCount;-				continue;-			}-			if (line[i] == '{')-			{-				if (shouldBreakReturnType && foundSplitPoint && !isAlreadyBroken)-				{-					methodBreakCharNum = breakCharNum;-					methodBreakLineNum = breakLineNum;-				}--				if (shouldAttachReturnType && foundSplitPoint && isAlreadyBroken)-				{-					//https://sourceforge.net/p/astyle/bugs/545/-					if ((maxCodeLength != std::string::npos && previousReadyFormattedLineLength < maxCodeLength) || maxCodeLength == std::string::npos)-					{-						methodAttachCharNum = breakCharNum;-						methodAttachLineNum = breakLineNum;-					}-				}-				return;-			}-			if (line[i] == ';')-			{-				if (shouldBreakReturnTypeDecl && foundSplitPoint && !isAlreadyBroken)-				{-					methodBreakCharNum = breakCharNum;-					methodBreakLineNum = breakLineNum;-				}-				if (shouldAttachReturnTypeDecl && foundSplitPoint && isAlreadyBroken)-				{-					methodAttachCharNum = breakCharNum;-					methodAttachLineNum = breakLineNum;-				}-				return;-			}-			if (line[i] == '}')-				return;-		}   // end of for loop-		if (!foundSplitPoint)-			breakCharNum = std::string::npos;-	}   // end of while loop+    assert((isBraceType(braceTypeStack->back(), BraceType::NULL_TYPE)+            || isBraceType(braceTypeStack->back(), BraceType::DEFINITION_TYPE)));+    assert(shouldBreakReturnType || shouldBreakReturnTypeDecl+           || shouldAttachReturnType || shouldAttachReturnTypeDecl);++    bool isFirstLine     = true;+    bool isInComment_    = false;+    bool isInQuote_      = false;+    bool foundSplitPoint = false;+    bool isAlreadyBroken = false;+    bool hasReturnType   = true;+    char quoteChar_      = ' ';+    char currNonWSChar   = ' ';+    char prevNonWSChar   = ' ';+    size_t parenCount    = 0;+    size_t squareCount   = 0;+    size_t angleCount    = 0;+    size_t breakLineNum  = 0;+    size_t breakCharNum  = std::string::npos;+    std::string line          = firstLine;++    // Process the lines until a ';' or '{'.+    ASPeekStream stream(sourceIterator);+    while (stream.hasMoreLines() || isFirstLine)+    {+        if (isFirstLine)+            isFirstLine = false;+        else+        {+            if (isInQuote_)+                return;+            line = stream.peekNextLine();+            if (!foundSplitPoint)+                ++breakLineNum;+        }+        size_t firstCharNum = line.find_first_not_of(" \t");+        if (firstCharNum == std::string::npos)+            continue;+        if (line[firstCharNum] == '#')+        {+            // don't attach to a preprocessor+            if (shouldAttachReturnType || shouldAttachReturnTypeDecl)+                return;+            continue;+        }+        // parse the line+        for (size_t i = 0; i < line.length(); i++)+        {+            if (!std::isblank(line[i]))+            {+                prevNonWSChar = currNonWSChar;+                currNonWSChar = line[i];+            }+            else if (line[i] == '\t' && shouldConvertTabs)+            {+                size_t tabSize = getTabLength();+                size_t numSpaces = tabSize - ((tabIncrementIn + i) % tabSize);+                line.replace(i, 1, numSpaces, ' ');+                currentChar = line[i];+            }+            if (line.compare(i, 2, "/*") == 0)+                isInComment_ = true;+            if (isInComment_)+            {+                if (line.compare(i, 2, "*/") == 0)+                {+                    isInComment_ = false;+                    ++i;+                }+                continue;+            }+            if (line[i] == '\\')+            {+                ++i;+                continue;+            }++            if (isInQuote_)+            {+                if (line[i] == quoteChar_)+                    isInQuote_ = false;+                continue;+            }++            if (line[i] == '"'+                    || (line[i] == '\'' && !isDigitSeparator(line, i)))+            {+                isInQuote_ = true;+                quoteChar_ = line[i];+                continue;+            }+            if (line.compare(i, 2, "//") == 0)+            {+                i = line.length();+                continue;+            }++            // https://sourceforge.net/p/astyle/bugs/504/+            if (line[line.length() - 1] == ':')+            {+                i = line.length();+                foundSplitPoint = true;+                continue;+            }++            // not in quote or comment+            if (!foundSplitPoint)+            {+                if (line[i] == '<')+                {+                    ++angleCount;+                    continue;+                }+                if (line[i] == '>')+                {+                    if (angleCount)+                        --angleCount;+                    if (!angleCount)+                    {+                        size_t nextCharNum = line.find_first_not_of(" \t*&", i + 1);+                        if (nextCharNum == std::string::npos)+                        {+                            breakCharNum  = std::string::npos;+                            continue;+                        }+                        if (line[nextCharNum] != ':')		// scope operator+                            breakCharNum  = nextCharNum;+                    }+                    continue;+                }+                if (angleCount)+                    continue;+                if (line[i] == '[')+                {+                    ++squareCount;+                    continue;+                }+                if (line[i] == ']')+                {+                    if (squareCount)+                        --squareCount;+                    continue;+                }+                // an assignment before the parens is not a function+                if (line[i] == '=')+                    return;+                if (std::isblank(line[i]) || line[i] == '*' || line[i] == '&')+                {+                    size_t nextNum = line.find_first_not_of(" \t", i + 1);+                    if (nextNum == std::string::npos)+                        breakCharNum = std::string::npos;+                    else+                    {+                        if (line.length() > nextNum + 1+                                && line[nextNum] == ':' && line[nextNum + 1] == ':')+                            i = --nextNum;+                        else if (line[nextNum] != '(')+                            breakCharNum = std::string::npos;+                    }+                    continue;+                }+                if ((isLegalNameChar(line[i]) || line[i] == '~')+                        && breakCharNum == std::string::npos)+                {+                    breakCharNum = i;+                    if (isLegalNameChar(line[i])+                            && findKeyword(line, i, ASResource::AS_OPERATOR))+                    {+                        if (breakCharNum == firstCharNum)+                            isAlreadyBroken = true;+                        hasReturnType = !isOnlyFunctionSpecifiers(line, firstCharNum, breakCharNum);+                        foundSplitPoint = true;+                        // find the operator, may be parens+                        size_t parenNum =+                            line.find_first_not_of(" \t", i + ASResource::AS_OPERATOR.length());+                        if (parenNum == std::string::npos)+                            return;+                        // find paren after the operator+                        parenNum = line.find('(', parenNum + 1);+                        if (parenNum == std::string::npos)+                            return;+                        i = --parenNum;+                    }+                    continue;+                }+                if (line[i] == ':'+                        && line.length() > i + 1+                        && line[i + 1] == ':')+                {+                    size_t nextCharNum = line.find_first_not_of(" \t:", i + 1);+                    if (nextCharNum == std::string::npos)+                        return;++                    if (isLegalNameChar(line[nextCharNum])+                            && findKeyword(line, nextCharNum, ASResource::AS_OPERATOR))+                    {+                        i = nextCharNum;+                        if (breakCharNum == firstCharNum)+                            isAlreadyBroken = true;+                        hasReturnType = !isOnlyFunctionSpecifiers(line, firstCharNum, breakCharNum);+                        foundSplitPoint = true;+                        // find the operator, may be parens+                        size_t parenNum =+                            line.find_first_not_of(" \t", i + ASResource::AS_OPERATOR.length());+                        if (parenNum == std::string::npos)+                            return;+                        // find paren after the operator+                        parenNum = line.find('(', parenNum + 1);+                        if (parenNum == std::string::npos)+                            return;+                        i = --parenNum;+                    }+                    else+                        i = --nextCharNum;+                    continue;+                }+                if (line[i] == '(' && !squareCount)+                {++                    // is line is already broken?+                    if (breakCharNum == firstCharNum && breakLineNum > 0)+                        isAlreadyBroken = true;+                    hasReturnType = !isOnlyFunctionSpecifiers(line, firstCharNum, breakCharNum);+                    ++parenCount;+                    foundSplitPoint = true;+                    continue;+                }+            }+            // end !foundSplitPoint+            if (line[i] == '(')+            {+                // consecutive ')(' parens is probably a function pointer+                if (prevNonWSChar == ')' && !parenCount)+                    return;+                ++parenCount;+                continue;+            }+            if (line[i] == ')')+            {+                if (parenCount)+                    --parenCount;+                continue;+            }+            if (line[i] == '{')+            {+                if (shouldBreakReturnType && foundSplitPoint && !isAlreadyBroken && hasReturnType)+                {+                    methodBreakCharNum = breakCharNum;+                    methodBreakLineNum = breakLineNum;+                }++                if (shouldAttachReturnType && foundSplitPoint && isAlreadyBroken)+                {+                    //https://sourceforge.net/p/astyle/bugs/545/+                    if ((maxCodeLength != std::string::npos && previousReadyFormattedLineLength.has_value() && *previousReadyFormattedLineLength < maxCodeLength) || maxCodeLength == std::string::npos)+                    {+                        methodAttachCharNum = breakCharNum;+                        methodAttachLineNum = breakLineNum;+                    }+                }+                return;+            }+            if (line[i] == ';')+            {+                if (shouldBreakReturnTypeDecl && foundSplitPoint && !isAlreadyBroken && hasReturnType)+                {+                    methodBreakCharNum = breakCharNum;+                    methodBreakLineNum = breakLineNum;+                }+                if (shouldAttachReturnTypeDecl && foundSplitPoint && isAlreadyBroken)+                {+                    methodAttachCharNum = breakCharNum;+                    methodAttachLineNum = breakLineNum;+                }+                return;+            }+            if (line[i] == '}')+                return;+        }   // end of for loop+        if (!foundSplitPoint)+            breakCharNum = std::string::npos;+    }   // end of while loop }  /**@@ -7307,86 +7936,86 @@ void ASFormatter::findReturnTypeSplitPoint(const std::string& firstLine)  */ bool ASFormatter::isStructAccessModified(const std::string& firstLine, size_t index) const {-	assert(firstLine[index] == '{');-	assert(isCStyle());--	bool isFirstLine = true;-	size_t braceCount = 1;-	std::string nextLine_ = firstLine.substr(index + 1);-	ASPeekStream stream(sourceIterator);--	// find the first non-blank text, bypassing all comments and quotes.-	bool isInComment_ = false;-	bool isInQuote_ = false;-	char quoteChar_ = ' ';-	while (stream.hasMoreLines() || isFirstLine)-	{-		if (isFirstLine)-			isFirstLine = false;-		else-			nextLine_ = stream.peekNextLine();-		// parse the line-		for (size_t i = 0; i < nextLine_.length(); i++)-		{-			if (std::isblank(nextLine_[i]))-				continue;-			if (nextLine_.compare(i, 2, "/*") == 0)-				isInComment_ = true;-			if (isInComment_)-			{-				if (nextLine_.compare(i, 2, "*/") == 0)-				{-					isInComment_ = false;-					++i;-				}-				continue;-			}-			if (nextLine_[i] == '\\')-			{-				++i;-				continue;-			}--			if (isInQuote_)-			{-				if (nextLine_[i] == quoteChar_)-					isInQuote_ = false;-				continue;-			}--			if (nextLine_[i] == '"'-			        || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))-			{-				isInQuote_ = true;-				quoteChar_ = nextLine_[i];-				continue;-			}-			if (nextLine_.compare(i, 2, "//") == 0)-			{-				i = nextLine_.length();-				continue;-			}-			// handle braces-			if (nextLine_[i] == '{')-				++braceCount;-			if (nextLine_[i] == '}')-				--braceCount;-			if (braceCount == 0)-				return false;-			// check for access modifiers-			if (isCharPotentialHeader(nextLine_, i))-			{-				if (findKeyword(nextLine_, i, ASResource::AS_PUBLIC)-				        || findKeyword(nextLine_, i, ASResource::AS_PRIVATE)-				        || findKeyword(nextLine_, i, ASResource::AS_PROTECTED))-					return true;-				std::string_view name = getCurrentWord(nextLine_, i);-				i += name.length() - 1;-			}-		}	// end of for loop-	}	// end of while loop--	return false;+    assert(firstLine[index] == '{');+    assert(isCStyle());++    bool isFirstLine = true;+    size_t braceCount = 1;+    std::string nextLine_ = firstLine.substr(index + 1);+    ASPeekStream stream(sourceIterator);++    // find the first non-blank text, bypassing all comments and quotes.+    bool isInComment_ = false;+    bool isInQuote_ = false;+    char quoteChar_ = ' ';+    while (stream.hasMoreLines() || isFirstLine)+    {+        if (isFirstLine)+            isFirstLine = false;+        else+            nextLine_ = stream.peekNextLine();+        // parse the line+        for (size_t i = 0; i < nextLine_.length(); i++)+        {+            if (std::isblank(nextLine_[i]))+                continue;+            if (nextLine_.compare(i, 2, "/*") == 0)+                isInComment_ = true;+            if (isInComment_)+            {+                if (nextLine_.compare(i, 2, "*/") == 0)+                {+                    isInComment_ = false;+                    ++i;+                }+                continue;+            }+            if (nextLine_[i] == '\\')+            {+                ++i;+                continue;+            }++            if (isInQuote_)+            {+                if (nextLine_[i] == quoteChar_)+                    isInQuote_ = false;+                continue;+            }++            if (nextLine_[i] == '"'+                    || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))+            {+                isInQuote_ = true;+                quoteChar_ = nextLine_[i];+                continue;+            }+            if (nextLine_.compare(i, 2, "//") == 0)+            {+                i = nextLine_.length();+                continue;+            }+            // handle braces+            if (nextLine_[i] == '{')+                ++braceCount;+            if (nextLine_[i] == '}')+                --braceCount;+            if (braceCount == 0)+                return false;+            // check for access modifiers+            if (isCharPotentialHeader(nextLine_, i))+            {+                if (findKeyword(nextLine_, i, ASResource::AS_PUBLIC)+                        || findKeyword(nextLine_, i, ASResource::AS_PRIVATE)+                        || findKeyword(nextLine_, i, ASResource::AS_PROTECTED))+                    return true;+                std::string_view name = getCurrentWord(nextLine_, i);+                i += name.length() - 1;+            }+        }	// end of for loop+    }	// end of while loop++    return false; }  /**@@ -7398,174 +8027,174 @@ bool ASFormatter::isStructAccessModified(const std::string& firstLine, size_t in */ bool ASFormatter::isIndentablePreprocessorBlock(const std::string& firstLine, size_t index) {-	assert(firstLine[index] == '#');--	bool isFirstLine = true;-	bool isInIndentableBlock = false;-	bool blockContainsBraces = false;-	bool blockContainsDefineContinuation = false;-	bool isInClassConstructor = false;-	bool isPotentialHeaderGuard = false;	// ifndef is first preproc statement-	bool isPotentialHeaderGuard2 = false;	// define is within the first preproc-	int  numBlockIndents = 0;-	int  lineParenCount = 0;-	std::string nextLine_ = firstLine.substr(index);-	auto stream = std::make_shared<ASPeekStream>(sourceIterator);--	// find end of the block, bypassing all comments and quotes.-	bool isInComment_ = false;-	bool isInQuote_ = false;-	char quoteChar_ = ' ';-	while (stream->hasMoreLines() || isFirstLine)-	{-		if (isFirstLine)-			isFirstLine = false;-		else-			nextLine_ = stream->peekNextLine();-		// parse the line-		for (size_t i = 0; i < nextLine_.length(); i++)-		{-			if (std::isblank(nextLine_[i]))-				continue;-			if (nextLine_.compare(i, 2, "/*") == 0)-				isInComment_ = true;-			if (isInComment_)-			{-				if (nextLine_.compare(i, 2, "*/") == 0)-				{-					isInComment_ = false;-					++i;-				}-				continue;-			}-			if (nextLine_[i] == '\\')-			{-				++i;-				continue;-			}-			if (isInQuote_)-			{-				if (nextLine_[i] == quoteChar_)-					isInQuote_ = false;-				continue;-			}--			if (nextLine_[i] == '"'-			        || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))-			{-				isInQuote_ = true;-				quoteChar_ = nextLine_[i];-				continue;-			}-			if (nextLine_.compare(i, 2, "//") == 0)-			{-				i = nextLine_.length();-				continue;-			}-			// handle preprocessor statement-			if (nextLine_[i] == '#')-			{-				std::string preproc = ASBeautifier::extractPreprocessorStatement(nextLine_);-				if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef-				{-					numBlockIndents += 1;-					isInIndentableBlock = true;-					// flag first preprocessor conditional for header include guard check-					if (!processedFirstConditional)-					{-						processedFirstConditional = true;-						isFirstPreprocConditional = true;-						if (isNDefPreprocStatement(nextLine_, preproc))-							isPotentialHeaderGuard = true;-					}-				}-				else if (preproc == "endif")-				{-					if (numBlockIndents > 0)-						numBlockIndents -= 1;-					// must exit BOTH loops-					if (numBlockIndents == 0)-						goto EndOfWhileLoop;-				}-				else if (preproc == "define")-				{-					if (nextLine_[nextLine_.length() - 1] == '\\')-						blockContainsDefineContinuation = true;-					// check for potential header include guards-					else if (isPotentialHeaderGuard && numBlockIndents == 1)-						isPotentialHeaderGuard2 = true;-				}-				i = nextLine_.length();-				continue;-			}-			// handle exceptions-			if (nextLine_[i] == '{' || nextLine_[i] == '}')-				blockContainsBraces = true;-			else if (nextLine_[i] == '(')-				++lineParenCount;-			else if (nextLine_[i] == ')')-				--lineParenCount;-			else if (nextLine_[i] == ':')-			{-				// check for '::'-				if (nextLine_.length() > i + 1 && nextLine_[i + 1] == ':')-					++i;-				else-					isInClassConstructor = true;-			}--			// bypass unnecessary parsing - must exit BOTH loops-			if (blockContainsBraces || isInClassConstructor || blockContainsDefineContinuation)-				goto EndOfWhileLoop;-		}	// end of for loop, end of line-		if (lineParenCount != 0)-			break;-	}	// end of while loop+    assert(firstLine[index] == '#');++    bool isFirstLine = true;+    bool isInIndentableBlock = false;+    bool blockContainsBraces = false;+    bool blockContainsDefineContinuation = false;+    bool isInClassConstructor = false;+    bool isPotentialHeaderGuard = false;	// ifndef is first preproc statement+    bool isPotentialHeaderGuard2 = false;	// define is within the first preproc+    int  numBlockIndents = 0;+    int  lineParenCount = 0;+    std::string nextLine_ = firstLine.substr(index);+    auto stream = std::make_shared<ASPeekStream>(sourceIterator);++    // find end of the block, bypassing all comments and quotes.+    bool isInComment_ = false;+    bool isInQuote_ = false;+    char quoteChar_ = ' ';+    while (stream->hasMoreLines() || isFirstLine)+    {+        if (isFirstLine)+            isFirstLine = false;+        else+            nextLine_ = stream->peekNextLine();+        // parse the line+        for (size_t i = 0; i < nextLine_.length(); i++)+        {+            if (std::isblank(nextLine_[i]))+                continue;+            if (nextLine_.compare(i, 2, "/*") == 0)+                isInComment_ = true;+            if (isInComment_)+            {+                if (nextLine_.compare(i, 2, "*/") == 0)+                {+                    isInComment_ = false;+                    ++i;+                }+                continue;+            }+            if (nextLine_[i] == '\\')+            {+                ++i;+                continue;+            }+            if (isInQuote_)+            {+                if (nextLine_[i] == quoteChar_)+                    isInQuote_ = false;+                continue;+            }++            if (nextLine_[i] == '"'+                    || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))+            {+                isInQuote_ = true;+                quoteChar_ = nextLine_[i];+                continue;+            }+            if (nextLine_.compare(i, 2, "//") == 0)+            {+                i = nextLine_.length();+                continue;+            }+            // handle preprocessor statement+            if (nextLine_[i] == '#')+            {+                std::string preproc = ASBeautifier::extractPreprocessorStatement(nextLine_);+                if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef+                {+                    numBlockIndents += 1;+                    isInIndentableBlock = true;+                    // flag first preprocessor conditional for header include guard check+                    if (!processedFirstConditional)+                    {+                        processedFirstConditional = true;+                        isFirstPreprocConditional = true;+                        if (isNDefPreprocStatement(nextLine_, preproc))+                            isPotentialHeaderGuard = true;+                    }+                }+                else if (preproc == "endif")+                {+                    if (numBlockIndents > 0)+                        numBlockIndents -= 1;+                    // must exit BOTH loops+                    if (numBlockIndents == 0)+                        goto EndOfWhileLoop;+                }+                else if (preproc == "define")+                {+                    if (nextLine_[nextLine_.length() - 1] == '\\')+                        blockContainsDefineContinuation = true;+                    // check for potential header include guards+                    else if (isPotentialHeaderGuard && numBlockIndents == 1)+                        isPotentialHeaderGuard2 = true;+                }+                i = nextLine_.length();+                continue;+            }+            // handle exceptions+            if (nextLine_[i] == '{' || nextLine_[i] == '}')+                blockContainsBraces = true;+            else if (nextLine_[i] == '(')+                ++lineParenCount;+            else if (nextLine_[i] == ')')+                --lineParenCount;+            else if (nextLine_[i] == ':')+            {+                // check for '::'+                if (nextLine_.length() > i + 1 && nextLine_[i + 1] == ':')+                    ++i;+                else+                    isInClassConstructor = true;+            }++            // bypass unnecessary parsing - must exit BOTH loops+            if (blockContainsBraces || isInClassConstructor || blockContainsDefineContinuation)+                goto EndOfWhileLoop;+        }	// end of for loop, end of line+        if (lineParenCount != 0)+            break;+    }	// end of while loop EndOfWhileLoop:-	preprocBlockEnd = sourceIterator->tellg();-	if (preprocBlockEnd < 0)-		preprocBlockEnd = sourceIterator->getStreamLength();-	if (blockContainsBraces-	        || isInClassConstructor-	        || blockContainsDefineContinuation-	        || lineParenCount != 0-	        || numBlockIndents != 0)-		isInIndentableBlock = false;-	// find next executable instruction-	// this WILL RESET the get pointer-	std::string nextText = peekNextText("", false, stream);-	// bypass header include guards-	if (isFirstPreprocConditional)-	{-		isFirstPreprocConditional = false;-		if (nextText.empty() && isPotentialHeaderGuard2)-		{-			isInIndentableBlock = false;-			preprocBlockEnd = 0;-		}-	}-	// this allows preprocessor blocks within this block to be indented-	if (!isInIndentableBlock)-		preprocBlockEnd = 0;-	// peekReset() is done by previous peekNextText()-	return isInIndentableBlock;+    preprocBlockEnd = sourceIterator->tellg();+    if (preprocBlockEnd < 0)+        preprocBlockEnd = sourceIterator->getStreamLength();+    if (blockContainsBraces+            || isInClassConstructor+            || blockContainsDefineContinuation+            || lineParenCount != 0+            || numBlockIndents != 0)+        isInIndentableBlock = false;+    // find next executable instruction+    // this WILL RESET the get pointer+    std::string nextText = peekNextText("", false, stream);+    // bypass header include guards+    if (isFirstPreprocConditional)+    {+        isFirstPreprocConditional = false;+        if (nextText.empty() && isPotentialHeaderGuard2)+        {+            isInIndentableBlock = false;+            preprocBlockEnd = 0;+        }+    }+    // this allows preprocessor blocks within this block to be indented+    if (!isInIndentableBlock)+        preprocBlockEnd = 0;+    // peekReset() is done by previous peekNextText()+    return isInIndentableBlock; }  bool ASFormatter::isNDefPreprocStatement(std::string_view nextLine_, std::string_view preproc) const {-	if (preproc == "ifndef")-		return true;-	// check for '!defined'-	if (preproc == "if")-	{-		size_t i = nextLine_.find('!');-		if (i == std::string::npos)-			return false;-		i = nextLine_.find_first_not_of(" \t", ++i);-		if (i != std::string::npos && nextLine_.compare(i, 7, "defined") == 0)-			return true;-	}-	return false;+    if (preproc == "ifndef")+        return true;+    // check for '!defined'+    if (preproc == "if")+    {+        size_t i = nextLine_.find('!');+        if (i == std::string::npos)+            return false;+        i = nextLine_.find_first_not_of(" \t", ++i);+        if (i != std::string::npos && nextLine_.compare(i, 7, "defined") == 0)+            return true;+    }+    return false; }  /**@@ -7577,29 +8206,29 @@ bool ASFormatter::isNDefPreprocStatement(std::string_view nextLine_, std::string  */ bool ASFormatter::isExecSQL(std::string_view line, size_t index) const {-	if (line[index] != 'e' && line[index] != 'E')	// quick check to reject most-		return false;-	std::string_view word;-	if (isCharPotentialHeader(line, index))-		word = getCurrentWord(line, index);-	for (char character : word)-		character = (char) toupper(character);-	if (word != "EXEC")-		return false;-	size_t index2 = index + word.length();-	index2 = line.find_first_not_of(" \t", index2);-	if (index2 == std::string::npos)-		return false;+    if (line[index] != 'e' && line[index] != 'E')	// quick check to reject most+        return false;+    std::string_view word;+    if (isCharPotentialHeader(line, index))+        word = getCurrentWord(line, index);+    for (char character : word)+        character = (char) toupper(character);+    if (word != "EXEC")+        return false;+    size_t index2 = index + word.length();+    index2 = line.find_first_not_of(" \t", index2);+    if (index2 == std::string::npos)+        return false; -	std::string_view word2;+    std::string_view word2; -	if (isCharPotentialHeader(line, index2))-		word2 = getCurrentWord(line, index2);-	for (char character : word2)-		character = (char) toupper(character);-	if (word2 != "SQL")-		return false;-	return true;+    if (isCharPotentialHeader(line, index2))+        word2 = getCurrentWord(line, index2);+    for (char character : word2)+        character = (char) toupper(character);+    if (word2 != "SQL")+        return false;+    return true; }  /**@@ -7610,46 +8239,46 @@ bool ASFormatter::isExecSQL(std::string_view line, size_t index) const  */ void ASFormatter::trimContinuationLine() {-	size_t len = currentLine.length();-	size_t tabSize = getTabLength();-	charNum = 0;--	if (leadingSpaces > 0 && len > 0)-	{-		size_t i;-		size_t continuationIncrementIn = 0;-		for (i = 0; (i < len) && (i + continuationIncrementIn < leadingSpaces); i++)-		{-			if (!std::isblank(currentLine[i]))		// don't delete any text-			{-				if (i < continuationIncrementIn)-					leadingSpaces = i + tabIncrementIn;-				continuationIncrementIn = tabIncrementIn;-				break;-			}-			if (currentLine[i] == '\t')-				continuationIncrementIn += tabSize - 1 - ((continuationIncrementIn + i) % tabSize);-		}--		if ((int) continuationIncrementIn == tabIncrementIn)-			charNum = i;-		else-		{-			// build a new line with the equivalent leading chars-			std::string newLine;-			int leadingChars = 0;-			if ((int) leadingSpaces > tabIncrementIn)-				leadingChars = leadingSpaces - tabIncrementIn;-			newLine.append(leadingChars, ' ');-			newLine.append(currentLine, i, len - i);-			currentLine = newLine;-			charNum = leadingChars;-			if (currentLine.empty())-				currentLine = std::string(" ");        // a null is inserted if this is not done-		}-		if (i >= len)-			charNum = 0;-	}+    size_t len = currentLine.length();+    size_t tabSize = getTabLength();+    charNum = 0;++    if (leadingSpaces > 0 && len > 0)+    {+        size_t i;+        size_t continuationIncrementIn = 0;+        for (i = 0; (i < len) && (i + continuationIncrementIn < leadingSpaces); i++)+        {+            if (!std::isblank(currentLine[i]))		// don't delete any text+            {+                if (i < continuationIncrementIn)+                    leadingSpaces = i + tabIncrementIn;+                continuationIncrementIn = tabIncrementIn;+                break;+            }+            if (currentLine[i] == '\t')+                continuationIncrementIn += tabSize - 1 - ((continuationIncrementIn + i) % tabSize);+        }++        if ((int) continuationIncrementIn == tabIncrementIn)+            charNum = i;+        else+        {+            // build a new line with the equivalent leading chars+            std::string newLine;+            int leadingChars = 0;+            if ((int) leadingSpaces > tabIncrementIn)+                leadingChars = leadingSpaces - tabIncrementIn;+            newLine.append(leadingChars, ' ');+            newLine.append(currentLine, i, len - i);+            currentLine = newLine;+            charNum = leadingChars;+            if (currentLine.empty())+                currentLine = std::string(" ");        // a null is inserted if this is not done+        }+        if (i >= len)+            charNum = 0;+    } }  /**@@ -7659,9 +8288,9 @@ void ASFormatter::trimContinuationLine()  */ bool ASFormatter::isClosingHeader(const std::string* header) const {-	return (header == &ASResource::AS_ELSE-	        || header == &ASResource::AS_CATCH-	        || header == &ASResource::AS_FINALLY);+    return (header == &ASResource::AS_ELSE+            || header == &ASResource::AS_CATCH+            || header == &ASResource::AS_FINALLY); }  /**@@ -7671,31 +8300,85 @@ bool ASFormatter::isClosingHeader(const std::string* header) const  */ bool ASFormatter::isImmediatelyPostCast() const {-	assert(previousNonWSChar == ')' && currentChar == '*');-	// find preceding closing paren on currentLine or readyFormattedLine-	std::string line;		// currentLine or readyFormattedLine-	size_t paren = currentLine.rfind(')', charNum);-	if (paren != std::string::npos)-		line = currentLine;-	// if not on currentLine it must be on the previous line-	else-	{-		line = readyFormattedLine;-		paren = line.rfind(')');-		if (paren == std::string::npos)-			return false;-	}-	if (paren == 0)-		return false;--	// find character preceding the closing paren-	size_t lastChar = line.find_last_not_of(" \t", paren - 1);-	if (lastChar == std::string::npos)-		return false;-	// check for pointer cast-	if (line[lastChar] == '*')-		return true;-	return false;+    assert(previousNonWSChar == ')' && currentChar == '*');+    // find preceding closing paren on currentLine or readyFormattedLine+    std::string line;		// currentLine or readyFormattedLine+    size_t paren = currentLine.rfind(')', charNum);+    if (paren != std::string::npos)+        line = currentLine;+    // if not on currentLine it must be on the previous line+    else+    {+        line = readyFormattedLine;+        paren = line.rfind(')');+        if (paren == std::string::npos)+            return false;+    }+    if (paren == 0)+        return false;++    // find character preceding the closing paren+    size_t lastChar = line.find_last_not_of(" \t", paren - 1);+    if (lastChar == std::string::npos)+        return false;+    // check for pointer cast+    if (line[lastChar] == '*')+        return true;++    // https://gitlab.com/saalen/astyle/-/work_items/100+    // check for a cast to a builtin type like "(unsigned char) *ptr"+    size_t openParen = line.rfind('(', paren);+    if (openParen == std::string::npos)+        return false;++    static const std::set<std::string_view> castTypeWords =+    {+        "unsigned", "signed", "char", "short", "int", "long", "float", "double",+        "void", "bool", "_Bool", "const", "volatile"+    };+    size_t wordStart = std::string::npos;+    for (size_t i = openParen + 1; i <= paren; i++)+    {+        if (i < paren && isLegalNameChar(line[i]) && line[i] != '.')+        {+            if (wordStart == std::string::npos)+                wordStart = i;+            continue;+        }+        if (i < paren && line[i] != ' ' && line[i] != '\t')+            return false;+        if (wordStart != std::string::npos)+        {+            std::string_view word = std::string_view(line).substr(wordStart, i - wordStart);+            bool isTypeWord = castTypeWords.find(word) != castTypeWords.end()+                              || (word.length() > 2+                                  && word.compare(word.length() - 2, 2, "_t") == 0);+            if (!isTypeWord)+                return false;+            wordStart = std::string::npos;+        }+    }+    if (line.find_first_not_of(" \t", openParen + 1) == paren)+        return false;++    // the parens must not belong to a function call or sizeof, alignof...+    size_t prevChar = openParen > 0 ? line.find_last_not_of(" \t", openParen - 1) : std::string::npos;+    if (prevChar == std::string::npos)+        return true;+    if (line[prevChar] == ')' || line[prevChar] == ']')+        return false;+    if (isLegalNameChar(line[prevChar]))+    {+        std::string_view prevWord = getPreviousWord(line, openParen);+        return prevWord == ASResource::AS_RETURN+               || prevWord == ASResource::AS_THROW+               || prevWord == ASResource::AS_CASE+               || prevWord == ASResource::AS_ELSE+               || prevWord == ASResource::AS_DO+               || prevWord == "co_return"+               || prevWord == "co_yield";+    }+    return true; }  /**@@ -7704,346 +8387,346 @@ bool ASFormatter::isImmediatelyPostCast() const  */ void ASFormatter::checkIfTemplateOpener() {-	assert(!isInTemplate && currentChar == '<');--	// find first char after the '<' operators-	size_t firstChar = currentLine.find_first_not_of("< \t", charNum);-	if (firstChar == std::string::npos-	        || currentLine[firstChar] == '=')-	{-		// this is not a template -> leave...-		isInTemplate = false;-		return;-	}--	bool isFirstLine = true;-	int parenDepth_ = 0;-	int maxTemplateDepth = 0;-	templateDepth = 0;-	std::string nextLine_ = currentLine.substr(charNum);-	ASPeekStream stream(sourceIterator);--	// find the angle braces, bypassing all comments and quotes.-	bool isInComment_ = false;-	bool isInQuote_ = false;-	char quoteChar_ = ' ';-	while (stream.hasMoreLines() || isFirstLine)-	{-		if (isFirstLine)-			isFirstLine = false;-		else-			nextLine_ = stream.peekNextLine();-		// parse the line-		for (size_t i = 0; i < nextLine_.length(); i++)-		{-			char currentChar_ = nextLine_[i];-			if (std::isblank(currentChar_))-				continue;-			if (nextLine_.compare(i, 2, "/*") == 0)-				isInComment_ = true;-			if (isInComment_)-			{-				if (nextLine_.compare(i, 2, "*/") == 0)-				{-					isInComment_ = false;-					++i;-				}-				continue;-			}-			if (currentChar_ == '\\')-			{-				++i;-				continue;-			}--			if (isInQuote_)-			{-				if (currentChar_ == quoteChar_)-					isInQuote_ = false;-				continue;-			}--			if (currentChar_ == '"'-			        || (currentChar_ == '\'' && !isDigitSeparator(nextLine_, i)))-			{-				isInQuote_ = true;-				quoteChar_ = currentChar_;-				continue;-			}-			if (nextLine_.compare(i, 2, "//") == 0)-			{-				i = nextLine_.length();-				continue;-			}--			// not in a comment or quote-			if (currentChar_ == '<')-			{-				++templateDepth;-				++maxTemplateDepth;-				continue;-			}-			if (currentChar_ == '>')-			{-				--templateDepth;-				if (templateDepth == 0)-				{-					if (parenDepth_ == 0)-					{-						// this is a template!-						// gl85 + sf585-						isInTemplate = true; //!isInStruct;-						templateDepth = maxTemplateDepth;-					}-					return;-				}-				continue;-			}-			if (currentChar_ == '(' || currentChar_ == ')')-			{-				if (currentChar_ == '(')-					++parenDepth_;-				else-					--parenDepth_;-				if (parenDepth_ >= 0)-					continue;-				// this is not a template -> leave...-				isInTemplate = false;-				templateDepth = 0;-				return;-			}-			if (nextLine_.compare(i, 2, ASResource::AS_AND) == 0-			        || nextLine_.compare(i, 2, ASResource::AS_OR) == 0)-			{-				// this is not a template -> leave...-				isInTemplate = false;-				templateDepth = 0;-				return;-			}--			if (currentChar_ == ','  // comma,     e.g. A<int, char>-			        || currentChar_ == '&'    // reference, e.g. A<int&>-			        || currentChar_ == '*'    // pointer,   e.g. A<int*>-			        || currentChar_ == '^'    // C++/CLI managed pointer, e.g. A<int^>-			        || currentChar_ == ':'    // ::,        e.g. std::string-			        || currentChar_ == '='    // assign     e.g. default parameter-			        || currentChar_ == '['    // []         e.g. std::string[]-			        || currentChar_ == ']'    // []         e.g. std::string[]-			        || currentChar_ == '('    // (...)      e.g. function definition-			        || currentChar_ == ')'    // (...)      e.g. function definition-			        || (isJavaStyle() && currentChar_ == '?')   // Java wildcard-			   )-			{-				continue;-			}-			if (!isLegalNameChar(currentChar_))-			{-				// this is not a template -> leave...-				isInTemplate = false;-				templateDepth = 0;-				return;-			}-			std::string_view name = getCurrentWord(nextLine_, i);-			i += name.length() - 1;-		}	// end for loop-	}	// end while loop+    assert(!isInTemplate && currentChar == '<');++    // find first char after the '<' operators+    size_t firstChar = currentLine.find_first_not_of("< \t", charNum);+    if (firstChar == std::string::npos+            || currentLine[firstChar] == '=')+    {+        // this is not a template -> leave...+        isInTemplate = false;+        return;+    }++    bool isFirstLine = true;+    int parenDepth_ = 0;+    int maxTemplateDepth = 0;+    templateDepth = 0;+    std::string nextLine_ = currentLine.substr(charNum);+    ASPeekStream stream(sourceIterator);++    // find the angle braces, bypassing all comments and quotes.+    bool isInComment_ = false;+    bool isInQuote_ = false;+    char quoteChar_ = ' ';+    while (stream.hasMoreLines() || isFirstLine)+    {+        if (isFirstLine)+            isFirstLine = false;+        else+            nextLine_ = stream.peekNextLine();+        // parse the line+        for (size_t i = 0; i < nextLine_.length(); i++)+        {+            char currentChar_ = nextLine_[i];+            if (std::isblank(currentChar_))+                continue;+            if (nextLine_.compare(i, 2, "/*") == 0)+                isInComment_ = true;+            if (isInComment_)+            {+                if (nextLine_.compare(i, 2, "*/") == 0)+                {+                    isInComment_ = false;+                    ++i;+                }+                continue;+            }+            if (currentChar_ == '\\')+            {+                ++i;+                continue;+            }++            if (isInQuote_)+            {+                if (currentChar_ == quoteChar_)+                    isInQuote_ = false;+                continue;+            }++            if (currentChar_ == '"'+                    || (currentChar_ == '\'' && !isDigitSeparator(nextLine_, i)))+            {+                isInQuote_ = true;+                quoteChar_ = currentChar_;+                continue;+            }+            if (nextLine_.compare(i, 2, "//") == 0)+            {+                i = nextLine_.length();+                continue;+            }++            // not in a comment or quote+            if (currentChar_ == '<')+            {+                ++templateDepth;+                ++maxTemplateDepth;+                continue;+            }+            if (currentChar_ == '>')+            {+                --templateDepth;+                if (templateDepth == 0)+                {+                    if (parenDepth_ == 0)+                    {+                        // this is a template!+                        // gl85 + sf585+                        isInTemplate = true; //!isInStruct;+                        templateDepth = maxTemplateDepth;+                    }+                    return;+                }+                continue;+            }+            if (currentChar_ == '(' || currentChar_ == ')')+            {+                if (currentChar_ == '(')+                    ++parenDepth_;+                else+                    --parenDepth_;+                if (parenDepth_ >= 0)+                    continue;+                // this is not a template -> leave...+                isInTemplate = false;+                templateDepth = 0;+                return;+            }+            if (nextLine_.compare(i, 2, ASResource::AS_AND) == 0+                    || nextLine_.compare(i, 2, ASResource::AS_OR) == 0)+            {+                // this is not a template -> leave...+                isInTemplate = false;+                templateDepth = 0;+                return;+            }++            if (currentChar_ == ','  // comma,     e.g. A<int, char>+                    || currentChar_ == '&'    // reference, e.g. A<int&>+                    || currentChar_ == '*'    // pointer,   e.g. A<int*>+                    || currentChar_ == '^'    // C++/CLI managed pointer, e.g. A<int^>+                    || currentChar_ == ':'    // ::,        e.g. std::string+                    || currentChar_ == '='    // assign     e.g. default parameter+                    || currentChar_ == '['    // []         e.g. std::string[]+                    || currentChar_ == ']'    // []         e.g. std::string[]+                    || currentChar_ == '('    // (...)      e.g. function definition+                    || currentChar_ == ')'    // (...)      e.g. function definition+                    || (isJavaStyle() && currentChar_ == '?')   // Java wildcard+               )+            {+                continue;+            }+            if (!isLegalNameChar(currentChar_))+            {+                // this is not a template -> leave...+                isInTemplate = false;+                templateDepth = 0;+                return;+            }+            std::string_view name = getCurrentWord(nextLine_, i);+            i += name.length() - 1;+        }	// end for loop+    }	// end while loop }  void ASFormatter::updateFormattedLineSplitPoints(char appendedChar) {-	assert(maxCodeLength != std::string::npos);-	assert(!formattedLine.empty());--	if (!isOkToSplitFormattedLine())-		return;--	char nextChar = peekNextChar();--	// don't split before an end of line comment-	if (nextChar == '/')-		return;--	// don't split before or after a brace-	if (appendedChar == '{' || appendedChar == '}'-	        || previousNonWSChar == '{' || previousNonWSChar == '}'-	        || nextChar == '{' || nextChar == '}'-	        || currentChar == '{' || currentChar == '}')	// currentChar tests for an appended brace-		return;--	// don't split before or after a block paren-	if (appendedChar == '[' || appendedChar == ']'-	        || previousNonWSChar == '['-	        || nextChar == '[' || nextChar == ']')-		return;--	if (std::isblank(appendedChar))-	{-		if (nextChar != ')'						// space before a closing paren-		        && nextChar != '('				// space before an opening paren-		        && nextChar != '/'				// space before a comment-		        && nextChar != ':'				// space before a colon-		        && currentChar != ')'			// appended space before and after a closing paren-		        && currentChar != '('			// appended space before and after a opening paren-		        && previousNonWSChar != '('		// decided at the '('-		        // don't break before a pointer or reference aligned to type-		        && !(nextChar == '*'-		             && !isCharPotentialOperator(previousNonWSChar)-		             && pointerAlignment == PTR_ALIGN_TYPE)-		        && !(nextChar == '&'-		             && !isCharPotentialOperator(previousNonWSChar)-		             && (referenceAlignment == REF_ALIGN_TYPE-		                 || (referenceAlignment == REF_SAME_AS_PTR && pointerAlignment == PTR_ALIGN_TYPE)))-		   )-		{-			if (formattedLine.length() - 1 <= maxCodeLength)-				maxWhiteSpace = formattedLine.length() - 1;-			else-				maxWhiteSpacePending = formattedLine.length() - 1;-		}-	}-	// unpadded closing parens may split after the paren (counts as whitespace)-	else if (appendedChar == ')')-	{-		if (nextChar != ')'-		        && nextChar != ' '-		        && nextChar != ';'-		        && nextChar != ','-		        && nextChar != '.'-		        && !(nextChar == '-' && pointerSymbolFollows()))	// check for ->-		{-			if (formattedLine.length() <= maxCodeLength)-				maxWhiteSpace = formattedLine.length();-			else-				maxWhiteSpacePending = formattedLine.length();-		}-	}-	// unpadded commas may split after the comma-	else if (appendedChar == ',')-	{-		if (formattedLine.length() <= maxCodeLength)-			maxComma = formattedLine.length();-		else-			maxCommaPending = formattedLine.length();-	}-	else if (appendedChar == '(')-	{-		if (nextChar != ')' && nextChar != '(' && nextChar != '"' && nextChar != '\'')-		{-			// if follows an operator break before-			size_t parenNum;-			if (previousNonWSChar != ' ' && isCharPotentialOperator(previousNonWSChar))-				parenNum = formattedLine.length() - 1;-			else-				parenNum = formattedLine.length();-			if (formattedLine.length() <= maxCodeLength)-				maxParen = parenNum;-			else-				maxParenPending = parenNum;-		}-	}-	else if (appendedChar == ';')-	{-		if (nextChar != ' '  && nextChar != '}' && nextChar != '/')	// check for following comment-		{-			if (formattedLine.length() <= maxCodeLength)-				maxSemi = formattedLine.length();-			else-				maxSemiPending = formattedLine.length();-		}-	}+    assert(maxCodeLength != std::string::npos);+    assert(!formattedLine.empty());++    if (!isOkToSplitFormattedLine())+        return;++    char nextChar = peekNextChar();++    // don't split before an end of line comment+    if (nextChar == '/')+        return;++    // don't split before or after a brace+    if (appendedChar == '{' || appendedChar == '}'+            || previousNonWSChar == '{' || previousNonWSChar == '}'+            || nextChar == '{' || nextChar == '}'+            || currentChar == '{' || currentChar == '}')	// currentChar tests for an appended brace+        return;++    // don't split before or after a block paren+    if (appendedChar == '[' || appendedChar == ']'+            || previousNonWSChar == '['+            || nextChar == '[' || nextChar == ']')+        return;++    if (std::isblank(appendedChar))+    {+        if (nextChar != ')'						// space before a closing paren+                && nextChar != '('				// space before an opening paren+                && nextChar != '/'				// space before a comment+                && nextChar != ':'				// space before a colon+                && currentChar != ')'			// appended space before and after a closing paren+                && currentChar != '('			// appended space before and after a opening paren+                && previousNonWSChar != '('		// decided at the '('+                // don't break before a pointer or reference aligned to type+                && !(nextChar == '*'+                     && !isCharPotentialOperator(previousNonWSChar)+                     && pointerAlignment == PTR_ALIGN_TYPE)+                && !(nextChar == '&'+                     && !isCharPotentialOperator(previousNonWSChar)+                     && (referenceAlignment == REF_ALIGN_TYPE+                         || (referenceAlignment == REF_SAME_AS_PTR && pointerAlignment == PTR_ALIGN_TYPE)))+           )+        {+            if (getEffectiveLineLength() - 1 <= maxCodeLength)+                maxWhiteSpace = formattedLine.length() - 1;+            else+                maxWhiteSpacePending = formattedLine.length() - 1;+        }+    }+    // unpadded closing parens may split after the paren (counts as whitespace)+    else if (appendedChar == ')')+    {+        if (nextChar != ')'+                && nextChar != ' '+                && nextChar != ';'+                && nextChar != ','+                && nextChar != '.'+                && !(nextChar == '-' && pointerSymbolFollows()))	// check for ->+        {+            if (getEffectiveLineLength() <= maxCodeLength)+                maxWhiteSpace = formattedLine.length();+            else+                maxWhiteSpacePending = formattedLine.length();+        }+    }+    // unpadded commas may split after the comma+    else if (appendedChar == ',')+    {+        if (getEffectiveLineLength() <= maxCodeLength)+            maxComma = formattedLine.length();+        else+            maxCommaPending = formattedLine.length();+    }+    else if (appendedChar == '(')+    {+        if (nextChar != ')' && nextChar != '(' && nextChar != '"' && nextChar != '\'')+        {+            // if follows an operator break before+            size_t parenNum;+            if (previousNonWSChar != ' ' && isCharPotentialOperator(previousNonWSChar))+                parenNum = formattedLine.length() - 1;+            else+                parenNum = formattedLine.length();+            if (getEffectiveLineLength() <= maxCodeLength)+                maxParen = parenNum;+            else+                maxParenPending = parenNum;+        }+    }+    else if (appendedChar == ';')+    {+        if (nextChar != ' '  && nextChar != '}' && nextChar != '/')	// check for following comment+        {+            if (getEffectiveLineLength() <= maxCodeLength)+                maxSemi = formattedLine.length();+            else+                maxSemiPending = formattedLine.length();+        }+    } }  void ASFormatter::updateFormattedLineSplitPointsOperator(std::string_view sequence) {-	assert(maxCodeLength != std::string::npos);-	assert(!formattedLine.empty());--	if (!isOkToSplitFormattedLine())-		return;--	char nextChar = peekNextChar();--	// don't split before an end of line comment-	if (nextChar == '/')-		return;--	// check for logical conditional-	if (sequence == "||" || sequence == "&&" || sequence == "or" || sequence == "and")-	{-		if (shouldBreakLineAfterLogical)-		{-			if (formattedLine.length() <= maxCodeLength)-				maxAndOr = formattedLine.length();-			else-				maxAndOrPending = formattedLine.length();-		}-		else-		{-			// adjust for leading space in the sequence-			size_t sequenceLength = sequence.length();-			if (formattedLine.length() > sequenceLength-			        && std::isblank(formattedLine[formattedLine.length() - sequenceLength - 1]))-				sequenceLength++;-			if (formattedLine.length() - sequenceLength <= maxCodeLength)-				maxAndOr = formattedLine.length() - sequenceLength;-			else-				maxAndOrPending = formattedLine.length() - sequenceLength;-		}-	}-	// comparison operators will split after the operator (counts as whitespace)-	else if (sequence == "==" || sequence == "!=" || sequence == ">=" || sequence == "<=")-	{-		if (formattedLine.length() <= maxCodeLength)-			maxWhiteSpace = formattedLine.length();-		else-			maxWhiteSpacePending = formattedLine.length();-	}-	// unpadded operators that will split BEFORE the operator (counts as whitespace)-	else if (sequence == "+" || sequence == "-" || sequence == "?")-	{-		if (charNum > 0-		        && !(sequence == "+" && isInExponent())-		        && !(sequence == "-"  && isInExponent())-		        && (isLegalNameChar(currentLine[charNum - 1])-		            || currentLine[charNum - 1] == ')'-		            || currentLine[charNum - 1] == ']'-		            || currentLine[charNum - 1] == '\"'))-		{-			if (formattedLine.length() - 1 <= maxCodeLength)-				maxWhiteSpace = formattedLine.length() - 1;-			else-				maxWhiteSpacePending = formattedLine.length() - 1;-		}-	}-	// unpadded operators that will USUALLY split AFTER the operator (counts as whitespace)-	else if (sequence == "=" || sequence == ":")-	{-		// split BEFORE if the line is too long-		// do NOT use <= here, must allow for a brace attached to an array-		size_t splitPoint = 0;-		if (formattedLine.length() < maxCodeLength)-			splitPoint = formattedLine.length();-		else-			splitPoint = formattedLine.length() - 1;-		// padded or unpadded arrays-		if (previousNonWSChar == ']')-		{-			if (formattedLine.length() - 1 <= maxCodeLength)-				maxWhiteSpace = splitPoint;-			else-				maxWhiteSpacePending = splitPoint;-		}-		else if (charNum > 0-		         && (isLegalNameChar(currentLine[charNum - 1])-		             || currentLine[charNum - 1] == ')'-		             || currentLine[charNum - 1] == ']'))-		{-			if (formattedLine.length() <= maxCodeLength)-				maxWhiteSpace = splitPoint;-			else-				maxWhiteSpacePending = splitPoint;-		}-	}+    assert(maxCodeLength != std::string::npos);+    assert(!formattedLine.empty());++    if (!isOkToSplitFormattedLine())+        return;++    char nextChar = peekNextChar();++    // don't split before an end of line comment+    if (nextChar == '/')+        return;++    // check for logical conditional+    if (sequence == "||" || sequence == "&&" || sequence == "or" || sequence == "and")+    {+        if (shouldBreakLineAfterLogical)+        {+            if (getEffectiveLineLength() <= maxCodeLength)+                maxAndOr = formattedLine.length();+            else+                maxAndOrPending = formattedLine.length();+        }+        else+        {+            // adjust for leading space in the sequence+            size_t sequenceLength = sequence.length();+            if (formattedLine.length() > sequenceLength+                    && std::isblank(formattedLine[formattedLine.length() - sequenceLength - 1]))+                sequenceLength++;+            if (formattedLine.length() - sequenceLength <= maxCodeLength)+                maxAndOr = formattedLine.length() - sequenceLength;+            else+                maxAndOrPending = formattedLine.length() - sequenceLength;+        }+    }+    // comparison operators will split after the operator (counts as whitespace)+    else if (sequence == "==" || sequence == "!=" || sequence == ">=" || sequence == "<=")+    {+        if (getEffectiveLineLength() <= maxCodeLength)+            maxWhiteSpace = formattedLine.length();+        else+            maxWhiteSpacePending = formattedLine.length();+    }+    // unpadded operators that will split BEFORE the operator (counts as whitespace)+    else if (sequence == "+" || sequence == "-" || sequence == "?")+    {+        if (charNum > 0+                && !(sequence == "+" && isInExponent())+                && !(sequence == "-"  && isInExponent())+                && (isLegalNameChar(currentLine[charNum - 1])+                    || currentLine[charNum - 1] == ')'+                    || currentLine[charNum - 1] == ']'+                    || currentLine[charNum - 1] == '\"'))+        {+            if (getEffectiveLineLength() - 1 <= maxCodeLength)+                maxWhiteSpace = formattedLine.length() - 1;+            else+                maxWhiteSpacePending = formattedLine.length() - 1;+        }+    }+    // unpadded operators that will USUALLY split AFTER the operator (counts as whitespace)+    else if (sequence == "=" || sequence == ":")+    {+        // split BEFORE if the line is too long+        // do NOT use <= here, must allow for a brace attached to an array+        size_t splitPoint = 0;+        if (getEffectiveLineLength() < maxCodeLength)+            splitPoint = formattedLine.length();+        else+            splitPoint = formattedLine.length() - 1;+        // padded or unpadded arrays+        if (previousNonWSChar == ']')+        {+            if (getEffectiveLineLength() - 1 <= maxCodeLength)+                maxWhiteSpace = splitPoint;+            else+                maxWhiteSpacePending = splitPoint;+        }+        else if (charNum > 0+                 && (isLegalNameChar(currentLine[charNum - 1])+                     || currentLine[charNum - 1] == ')'+                     || currentLine[charNum - 1] == ']'))+        {+            if (getEffectiveLineLength() <= maxCodeLength)+                maxWhiteSpace = splitPoint;+            else+                maxWhiteSpacePending = splitPoint;+        }+    } }  /**@@ -8052,212 +8735,265 @@ void ASFormatter::updateFormattedLineSplitPointsOperator(std::string_view sequen  */ void ASFormatter::updateFormattedLineSplitPointsPointerOrReference(size_t index) {-	assert(maxCodeLength != std::string::npos);-	assert(!formattedLine.empty());-	assert(index < formattedLine.length());+    assert(maxCodeLength != std::string::npos);+    assert(!formattedLine.empty());+    assert(index < formattedLine.length()); -	if (!isOkToSplitFormattedLine())-		return;+    if (!isOkToSplitFormattedLine())+        return; -	if (index < maxWhiteSpace)		// just in case-		return;+    if (index < maxWhiteSpace)		// just in case+        return; -	if (index <= maxCodeLength)-		maxWhiteSpace = index;-	else-		maxWhiteSpacePending = index;+    if (index <= maxCodeLength)+        maxWhiteSpace = index;+    else+        maxWhiteSpacePending = index; }  bool ASFormatter::isOkToSplitFormattedLine() {-	assert(maxCodeLength != std::string::npos);-	// Is it OK to split the line?-	if (shouldKeepLineUnbroken-	        || isInLineComment-	        || isInComment-	        || isInQuote-	        || isInCase-	        || isInPreprocessor-	        || isInExecSQL-	        || isInAsm || isInAsmOneLine || isInAsmBlock-	        || isInTemplate)-		return false;--	if (!isOkToBreakBlock(braceTypeStack->back()) && currentChar != '{')-	{-		shouldKeepLineUnbroken = true;-		clearFormattedLineSplitPoints();-		return false;-	}-	if (isBraceType(braceTypeStack->back(), ARRAY_TYPE))-	{-		shouldKeepLineUnbroken = true;-		if (!isBraceType(braceTypeStack->back(), ARRAY_NIS_TYPE))-			clearFormattedLineSplitPoints();-		return false;-	}-	return true;+    assert(maxCodeLength != std::string::npos);+    // Is it OK to split the line?+    if (shouldKeepLineUnbroken+            || isInLineComment+            || isInComment+            || isInQuote+            || isInCase+            || isInPreprocessor+            || isInExecSQL+            || isInAsm || isInAsmOneLine || isInAsmBlock+            || isInTemplate)+        return false;++    if (!isOkToBreakBlock(braceTypeStack->back()) && currentChar != '{')+    {+        shouldKeepLineUnbroken = true;+        clearFormattedLineSplitPoints();+        return false;+    }+    if (isBraceType(braceTypeStack->back(), BraceType::ARRAY_TYPE))+    {+        shouldKeepLineUnbroken = true;+        if (!isBraceType(braceTypeStack->back(), BraceType::ARRAY_NIS_TYPE))+            clearFormattedLineSplitPoints();+        return false;+    }+    return true; }  /* This is called if the option maxCodeLength is set.  */ void ASFormatter::testForTimeToSplitFormattedLine() {-	//	DO NOT ASSERT maxCodeLength HERE-	// should the line be split-	if (formattedLine.length() > maxCodeLength && !isLineReady)-	{-		size_t splitPoint = findFormattedLineSplitPoint();-		if (splitPoint > 0 && splitPoint < formattedLine.length())-		{-			std::string splitLine = formattedLine.substr(splitPoint);-			formattedLine = formattedLine.substr(0, splitPoint);-			breakLine(true);-			formattedLine = splitLine;-			// if break-blocks is requested and this is a one-line statement-			std::string nextWord = ASBeautifier::getNextWord(currentLine, charNum - 1);-			if (isAppendPostBlockEmptyLineRequested-			        && (nextWord == "break" || nextWord == "continue"))-			{-				isAppendPostBlockEmptyLineRequested = false;-				isPrependPostBlockEmptyLineRequested = true;-			}-			else-				isPrependPostBlockEmptyLineRequested = false;-			// adjust max split points-			maxAndOr = (maxAndOr > splitPoint) ? (maxAndOr - splitPoint) : 0;-			maxSemi = (maxSemi > splitPoint) ? (maxSemi - splitPoint) : 0;-			maxComma = (maxComma > splitPoint) ? (maxComma - splitPoint) : 0;-			maxParen = (maxParen > splitPoint) ? (maxParen - splitPoint) : 0;-			maxWhiteSpace = (maxWhiteSpace > splitPoint) ? (maxWhiteSpace - splitPoint) : 0;-			if (maxSemiPending > 0)-			{-				maxSemi = (maxSemiPending > splitPoint) ? (maxSemiPending - splitPoint) : 0;-				maxSemiPending = 0;-			}-			if (maxAndOrPending > 0)-			{-				maxAndOr = (maxAndOrPending > splitPoint) ? (maxAndOrPending - splitPoint) : 0;-				maxAndOrPending = 0;-			}-			if (maxCommaPending > 0)-			{-				maxComma = (maxCommaPending > splitPoint) ? (maxCommaPending - splitPoint) : 0;-				maxCommaPending = 0;-			}-			if (maxParenPending > 0)-			{-				maxParen = (maxParenPending > splitPoint) ? (maxParenPending - splitPoint) : 0;-				maxParenPending = 0;-			}-			if (maxWhiteSpacePending > 0)-			{-				maxWhiteSpace = (maxWhiteSpacePending > splitPoint) ? (maxWhiteSpacePending - splitPoint) : 0;-				maxWhiteSpacePending = 0;-			}-			// don't allow an empty formatted line-			size_t firstText = formattedLine.find_first_not_of(" \t");-			if (firstText == std::string::npos && !formattedLine.empty())-			{-				formattedLine.erase();-				clearFormattedLineSplitPoints();-				if (std::isblank(currentChar))-					for (size_t i = charNum + 1; i < currentLine.length() && std::isblank(currentLine[i]); i++)-						goForward(1);-			}-			else if (firstText > 0)-			{-				formattedLine.erase(0, firstText);-				maxSemi = (maxSemi > firstText) ? (maxSemi - firstText) : 0;-				maxAndOr = (maxAndOr > firstText) ? (maxAndOr - firstText) : 0;-				maxComma = (maxComma > firstText) ? (maxComma - firstText) : 0;-				maxParen = (maxParen > firstText) ? (maxParen - firstText) : 0;-				maxWhiteSpace = (maxWhiteSpace > firstText) ? (maxWhiteSpace - firstText) : 0;-			}-			// reset formattedLineCommentNum-			if (formattedLineCommentNum != std::string::npos)-			{-				formattedLineCommentNum = formattedLine.find("//");-				if (formattedLineCommentNum == std::string::npos)-					formattedLineCommentNum = formattedLine.find("/*");-			}-		}-	}+    //	DO NOT ASSERT maxCodeLength HERE+    // should the line be split+    if (getEffectiveLineLength() > maxCodeLength && !isLineReady)+    {+        size_t splitPoint = findFormattedLineSplitPoint();+        if (splitPoint > 0 && splitPoint < formattedLine.length())+        {+            std::string splitLine = formattedLine.substr(splitPoint);+            formattedLine = formattedLine.substr(0, splitPoint);+            breakLine(true);+            formattedLine = splitLine;+            // if break-blocks is requested and this is a one-line statement+            std::string nextWord = ASBeautifier::getNextWord(currentLine, charNum - 1);+            if (isAppendPostBlockEmptyLineRequested+                    && (nextWord == "break" || nextWord == "continue"))+            {+                isAppendPostBlockEmptyLineRequested = false;+                isPrependPostBlockEmptyLineRequested = true;+            }+            else+                isPrependPostBlockEmptyLineRequested = false;+            // adjust max split points+            maxAndOr = (maxAndOr > splitPoint) ? (maxAndOr - splitPoint) : 0;+            maxSemi = (maxSemi > splitPoint) ? (maxSemi - splitPoint) : 0;+            maxComma = (maxComma > splitPoint) ? (maxComma - splitPoint) : 0;+            maxParen = (maxParen > splitPoint) ? (maxParen - splitPoint) : 0;+            maxWhiteSpace = (maxWhiteSpace > splitPoint) ? (maxWhiteSpace - splitPoint) : 0;+            if (maxSemiPending > 0)+            {+                maxSemi = (maxSemiPending > splitPoint) ? (maxSemiPending - splitPoint) : 0;+                maxSemiPending = 0;+            }+            if (maxAndOrPending > 0)+            {+                maxAndOr = (maxAndOrPending > splitPoint) ? (maxAndOrPending - splitPoint) : 0;+                maxAndOrPending = 0;+            }+            if (maxCommaPending > 0)+            {+                maxComma = (maxCommaPending > splitPoint) ? (maxCommaPending - splitPoint) : 0;+                maxCommaPending = 0;+            }+            if (maxParenPending > 0)+            {+                maxParen = (maxParenPending > splitPoint) ? (maxParenPending - splitPoint) : 0;+                maxParenPending = 0;+            }+            if (maxWhiteSpacePending > 0)+            {+                maxWhiteSpace = (maxWhiteSpacePending > splitPoint) ? (maxWhiteSpacePending - splitPoint) : 0;+                maxWhiteSpacePending = 0;+            }+            // don't allow an empty formatted line+            size_t firstText = formattedLine.find_first_not_of(" \t");+            if (firstText == std::string::npos && !formattedLine.empty())+            {+                formattedLine.erase();+                clearFormattedLineSplitPoints();+                if (std::isblank(currentChar))+                    for (size_t i = charNum + 1; i < currentLine.length() && std::isblank(currentLine[i]); i++)+                        goForward(1);+            }+            else if (firstText > 0)+            {+                formattedLine.erase(0, firstText);+                maxSemi = (maxSemi > firstText) ? (maxSemi - firstText) : 0;+                maxAndOr = (maxAndOr > firstText) ? (maxAndOr - firstText) : 0;+                maxComma = (maxComma > firstText) ? (maxComma - firstText) : 0;+                maxParen = (maxParen > firstText) ? (maxParen - firstText) : 0;+                maxWhiteSpace = (maxWhiteSpace > firstText) ? (maxWhiteSpace - firstText) : 0;+            }+            // reset formattedLineCommentNum+            if (formattedLineCommentNum != std::string::npos)+            {+                formattedLineCommentNum = formattedLine.find("//");+                if (formattedLineCommentNum == std::string::npos)+                    formattedLineCommentNum = formattedLine.find("/*");+            }+        }+    } }  size_t ASFormatter::findFormattedLineSplitPoint() const {-	assert(maxCodeLength != std::string::npos);-	// determine where to split-	size_t minCodeLength = 10;-	size_t splitPoint = 0;-	splitPoint = maxSemi;-	if (maxAndOr >= minCodeLength)-		splitPoint = maxAndOr;-	if (splitPoint < minCodeLength)-	{-		splitPoint = maxWhiteSpace;-		// use maxParen instead if it is long enough-		if (maxParen > splitPoint-		        || maxParen >= maxCodeLength * .7)-			splitPoint = maxParen;-		// use maxComma instead if it is long enough-		// increasing the multiplier causes more splits at whitespace-		if (maxComma > splitPoint-		        || maxComma >= maxCodeLength * .3)-			splitPoint = maxComma;-	}-	// replace split point with first available break point-	if (splitPoint < minCodeLength)-	{-		splitPoint = std::string::npos;-		if (maxSemiPending > 0 && maxSemiPending < splitPoint)-			splitPoint = maxSemiPending;-		if (maxAndOrPending > 0 && maxAndOrPending < splitPoint)-			splitPoint = maxAndOrPending;-		if (maxCommaPending > 0 && maxCommaPending < splitPoint)-			splitPoint = maxCommaPending;-		if (maxParenPending > 0 && maxParenPending < splitPoint)-			splitPoint = maxParenPending;-		if (maxWhiteSpacePending > 0 && maxWhiteSpacePending < splitPoint)-			splitPoint = maxWhiteSpacePending;-		if (splitPoint == std::string::npos)-			splitPoint = 0;-	}-	// if remaining line after split is too long-	else if (formattedLine.length() - splitPoint > maxCodeLength)-	{-		// if end of the currentLine, find a new split point-		size_t newCharNum;-		if (!std::isblank(currentChar) && isCharPotentialHeader(currentLine, charNum))-			newCharNum = getCurrentWord(currentLine, charNum).length() + charNum;-		else-			newCharNum = charNum + 2;-		if (newCharNum + 1 > currentLine.length())-		{-			// don't move splitPoint from before a conditional to after-			if (maxWhiteSpace > splitPoint + 3)-				splitPoint = maxWhiteSpace;-			if (maxParen > splitPoint)-				splitPoint = maxParen;-		}-	}--	return splitPoint;+    assert(maxCodeLength != std::string::npos);+    // determine where to split+    size_t minCodeLength = 10;+    size_t splitPoint = 0;+    splitPoint = maxSemi;+    if (maxAndOr >= minCodeLength)+        splitPoint = maxAndOr;+    if (splitPoint < minCodeLength)+    {+        splitPoint = maxWhiteSpace;+        // use maxParen instead if it is long enough+        if (maxParen > splitPoint+                || maxParen >= maxCodeLength * .7)+            splitPoint = maxParen;+        // use maxComma instead if it is long enough+        // increasing the multiplier causes more splits at whitespace+        if (maxComma > splitPoint+                || maxComma >= maxCodeLength * .3)+            splitPoint = maxComma;+    }+    // replace split point with first available break point+    if (splitPoint < minCodeLength)+    {+        splitPoint = std::string::npos;+        if (maxSemiPending > 0 && maxSemiPending < splitPoint)+            splitPoint = maxSemiPending;+        if (maxAndOrPending > 0 && maxAndOrPending < splitPoint)+            splitPoint = maxAndOrPending;+        if (maxCommaPending > 0 && maxCommaPending < splitPoint)+            splitPoint = maxCommaPending;+        if (maxParenPending > 0 && maxParenPending < splitPoint)+            splitPoint = maxParenPending;+        if (maxWhiteSpacePending > 0 && maxWhiteSpacePending < splitPoint)+            splitPoint = maxWhiteSpacePending;+        if (splitPoint == std::string::npos)+            splitPoint = 0;+    }+    // if remaining line after split is too long+    else if (getEffectiveLineLength() - splitPoint > maxCodeLength)+    {+        // if end of the currentLine, find a new split point+        size_t newCharNum;+        if (!std::isblank(currentChar) && isCharPotentialHeader(currentLine, charNum))+            newCharNum = getCurrentWord(currentLine, charNum).length() + charNum;+        else+            newCharNum = charNum + 2;+        if (newCharNum + 1 > currentLine.length())+        {+            // don't move splitPoint from before a conditional to after+            if (maxWhiteSpace > splitPoint + 3)+                splitPoint = maxWhiteSpace;+            if (maxParen > splitPoint)+                splitPoint = maxParen;+        }+    }++    return splitPoint;+}+++size_t ASFormatter::getEffectiveLineLength() const+{+    size_t lineLength = formattedLine.length();++    // Exclude trailing side-comment text from the length used for split decisions.+    // A side comment has non-whitespace code preceding it on the same line; a+    // stand-alone comment line (no preceding code) is left alone.+    if (shouldIgnoreSideCommentLengths+            && formattedLineCommentNum != std::string::npos+            && formattedLineCommentNum > 0+            && formattedLineCommentNum < lineLength)+    {+        size_t firstNonWs = formattedLine.find_first_not_of(" \t");+        if (firstNonWs != std::string::npos && firstNonWs < formattedLineCommentNum)+            lineLength = formattedLineCommentNum;+    }++    if (maxCodeLengthMode == MAXCODELENGTH_TOTAL)+    {+        int predictedIndentCount = bracesNestingLevel;+        int predictedSpaceIndent = 0;+        if (getPrevFinalLineSpaceIndentCount()>0 && bracesNestingLevel == getPrevFinalLineIndentCount())+        {+            predictedSpaceIndent = getPrevFinalLineSpaceIndentCount();+        }+        else if (isLineContinuation && bracesNestingLevel == getPrevFinalLineIndentCount())+        {+            // First continuation line of a multi-line statement: the previous+            // emitted line was the statement header (spaceIndentCount == 0),+            // but ASBeautifier will indent this line by minConditionalIndent.+            // Without this branch the predictor is one line behind and the+            // first wrapped line escapes the max-code-length check.+            predictedSpaceIndent = getMinConditionalIndent();+        }++        if (!formattedLine.empty())+        {+            size_t firstChar = formattedLine.find_first_not_of(" \t");+            if (firstChar != std::string::npos && formattedLine[firstChar] == '}')+            {+                if (predictedIndentCount > 0)+                    predictedIndentCount--;+                predictedSpaceIndent = 0;+            }+        }+        size_t indentChars = getIndentLength() * predictedIndentCount + predictedSpaceIndent;+        lineLength += indentChars;+    }+    return lineLength; } + void ASFormatter::clearFormattedLineSplitPoints() {-	maxSemi = 0;-	maxAndOr = 0;-	maxComma = 0;-	maxParen = 0;-	maxWhiteSpace = 0;-	maxSemiPending = 0;-	maxAndOrPending = 0;-	maxCommaPending = 0;-	maxParenPending = 0;-	maxWhiteSpacePending = 0;+    maxSemi = 0;+    maxAndOr = 0;+    maxComma = 0;+    maxParen = 0;+    maxWhiteSpace = 0;+    maxSemiPending = 0;+    maxAndOrPending = 0;+    maxCommaPending = 0;+    maxParenPending = 0;+    maxWhiteSpacePending = 0; }  /**@@ -8265,10 +9001,10 @@ void ASFormatter::clearFormattedLineSplitPoints()  */ bool ASFormatter::pointerSymbolFollows() const {-	size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);-	if (peekNum == std::string::npos || currentLine.compare(peekNum, 2, "->") != 0)-		return false;-	return true;+    size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);+    if (peekNum == std::string::npos || currentLine.compare(peekNum, 2, "->") != 0)+        return false;+    return true; }  /**@@ -8277,10 +9013,10 @@ bool ASFormatter::pointerSymbolFollows() const  */ bool ASFormatter::computeChecksumIn(std::string_view currentLine_) {-	for (const char character : currentLine_)-		if (!std::isblank(character))-			checksumIn += character;-	return true;+    for (const char character : currentLine_)+        if (!std::isblank(character))+            checksumIn += character;+    return true; }  /**@@ -8289,8 +9025,8 @@ bool ASFormatter::computeChecksumIn(std::string_view currentLine_)  */ bool ASFormatter::adjustChecksumIn(int adjustment) {-	checksumIn += adjustment;-	return true;+    checksumIn += adjustment;+    return true; }  /**@@ -8300,7 +9036,7 @@ bool ASFormatter::adjustChecksumIn(int adjustment)  */ size_t ASFormatter::getChecksumIn() const {-	return checksumIn;+    return checksumIn; }  /**@@ -8309,10 +9045,10 @@ size_t ASFormatter::getChecksumIn() const  */ bool ASFormatter::computeChecksumOut(std::string_view beautifiedLine) {-	for (const char character : beautifiedLine)-		if (!std::isblank(character))-			checksumOut += character;-	return true;+    for (const char character : beautifiedLine)+        if (!std::isblank(character))+            checksumOut += character;+    return true; }  /**@@ -8320,7 +9056,7 @@ bool ASFormatter::computeChecksumOut(std::string_view beautifiedLine)  */ bool ASFormatter::getIsLineReady() const {-	return isLineReady;+    return isLineReady; }  /**@@ -8330,7 +9066,7 @@ bool ASFormatter::getIsLineReady() const  */ size_t ASFormatter::getChecksumOut() const {-	return checksumOut;+    return checksumOut; }  /**@@ -8339,401 +9075,404 @@ size_t ASFormatter::getChecksumOut() const  */ int ASFormatter::getChecksumDiff() const {-	return checksumOut - checksumIn;+    return checksumOut - checksumIn; }  // for unit testing int ASFormatter::getFormatterFileType() const {-	return formatterFileType;+    return formatterFileType; }  // Check if an operator follows the next word. // The next word must be a legal name. const std::string* ASFormatter::getFollowingOperator() const {-	// find next word-	size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);-	if (nextNum == std::string::npos)-		return nullptr;+    // find next word+    size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);+    if (nextNum == std::string::npos)+        return nullptr; -	if (!isLegalNameChar(currentLine[nextNum]))-		return nullptr;+    if (!isLegalNameChar(currentLine[nextNum]))+        return nullptr; -	// bypass next word and following spaces-	while (nextNum < currentLine.length())-	{-		if (!isLegalNameChar(currentLine[nextNum])-		        && !std::isblank(currentLine[nextNum]))-			break;-		nextNum++;-	}+    // bypass next word and following spaces+    while (nextNum < currentLine.length())+    {+        if (!isLegalNameChar(currentLine[nextNum])+                && !std::isblank(currentLine[nextNum]))+            break;+        nextNum++;+    } -	if (nextNum >= currentLine.length()-	        || !isCharPotentialOperator(currentLine[nextNum])-	        || currentLine[nextNum] == '/')		// comment-		return nullptr;+    if (nextNum >= currentLine.length()+            || !isCharPotentialOperator(currentLine[nextNum])+            || currentLine[nextNum] == '/')		// comment+        return nullptr; -	const std::string* newOperator = ASBase::findOperator(currentLine, nextNum, operators);-	return newOperator;+    const std::string* newOperator = ASBase::findOperator(currentLine, nextNum, operators.get());+    return newOperator; }  // Check following data to determine if the current character is an array operator. bool ASFormatter::isArrayOperator() const {-	assert(currentChar == '*' || currentChar == '&' || currentChar == '^');-	assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE));+    assert(currentChar == '*' || currentChar == '&' || currentChar == '^');+    assert(isBraceType(braceTypeStack->back(), BraceType::ARRAY_TYPE)); -	// find next word-	size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);-	if (nextNum == std::string::npos)-		return false;+    // find next word+    size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);+    if (nextNum == std::string::npos)+        return false; -	if (!isLegalNameChar(currentLine[nextNum]))-		return false;+    if (!isLegalNameChar(currentLine[nextNum]))+        return false; -	// bypass next word and following spaces-	while (nextNum < currentLine.length())-	{-		if (!isLegalNameChar(currentLine[nextNum])-		        && !std::isblank(currentLine[nextNum]))-			break;-		nextNum++;-	}+    // bypass next word and following spaces+    while (nextNum < currentLine.length())+    {+        if (!isLegalNameChar(currentLine[nextNum])+                && !std::isblank(currentLine[nextNum]))+            break;+        nextNum++;+    } -	// check for characters that indicate an operator-	if (currentLine[nextNum] == ','-	        || currentLine[nextNum] == '}'-	        || currentLine[nextNum] == ')'-	        || currentLine[nextNum] == '(')-		return true;-	return false;+    // check for characters that indicate an operator+    if (currentLine[nextNum] == ','+            || currentLine[nextNum] == '}'+            || currentLine[nextNum] == ')'+            || currentLine[nextNum] == '(')+        return true;+    return false; }   // Reset the flags that indicate various statement information. void ASFormatter::resetEndOfStatement() {-	foundQuestionMark = false;-	foundNamespaceHeader = false;-	foundClassHeader = false;-	foundStructHeader = false;-	foundInterfaceHeader = false;-	foundPreDefinitionHeader = false;-	foundPreCommandHeader = false;-	foundPreCommandMacro = false;-	foundTrailingReturnType = false;-	foundCastOperator = false;-	isInPotentialCalculation = false;-	isSharpAccessor = false;-	isSharpDelegate = false;-	isInObjCMethodDefinition = false;-	isImmediatelyPostObjCMethodPrefix = false;-	isInObjCReturnType = false;-	isInObjCParam = false;-	isInObjCInterface = false;-	isInObjCSelector = false;-	isInEnum = false;-	isInExternC = false;-	elseHeaderFollowsComments = false;-	returnTypeChecked = false;-	nonInStatementBrace = 0;-	while (!questionMarkStack->empty())-		questionMarkStack->pop_back();+    foundQuestionMark = false;+    foundNamespaceHeader = false;+    foundClassHeader = false;+    foundStructHeader = false;+    foundDefinitionAttribute = false;+    foundInterfaceHeader = false;+    foundPreDefinitionHeader = false;+    foundPreCommandHeader = false;+    foundPreCommandMacro = false;+    foundTrailingReturnType = false;+    foundConstevalCondition = false;+    foundRequiresExpression = false;+    foundCastOperator = false;+    isInPotentialCalculation = false;+    isSharpAccessor = false;+    isSharpDelegate = false;+    isInObjCMethodDefinition = false;+    isImmediatelyPostObjCMethodPrefix = false;+    isInObjCReturnType = false;+    isInObjCParam = false;+    isInObjCInterface = false;+    isInObjCSelector = false;+    isInEnum = false;+    isInExternC = false;+    elseHeaderFollowsComments = false;+    returnTypeChecked = false;+    nonInStatementBrace = 0;+    while (!questionMarkStack->empty())+        questionMarkStack->pop_back(); }  // Find the colon alignment for Objective-C method definitions and method calls. int ASFormatter::findObjCColonAlignment() const {-	assert(currentChar == '+' || currentChar == '-' || currentChar == '[');-	assert(getAlignMethodColon());--	bool isFirstLine = true;-	bool haveFirstColon = false;-	bool foundMethodColon = false;-	bool isInComment_ = false;-	bool isInQuote_ = false;-	bool haveTernary = false;-	char quoteChar_ = ' ';-	int  sqBracketCount = 0;-	int  colonAdjust = 0;-	int  colonAlign = 0;-	std::string nextLine_ = currentLine;-	ASPeekStream stream(sourceIterator);--	// peek next line-	while (sourceIterator->hasMoreLines() || isFirstLine)-	{-		if (!isFirstLine)-			nextLine_ = stream.peekNextLine();-		// parse the line-		haveFirstColon = false;-		nextLine_ = ASBeautifier::trim(nextLine_);-		for (size_t i = 0; i < nextLine_.length(); i++)-		{-			if (std::isblank(nextLine_[i]))-				continue;-			if (nextLine_.compare(i, 2, "/*") == 0)-				isInComment_ = true;-			if (isInComment_)-			{-				if (nextLine_.compare(i, 2, "*/") == 0)-				{-					isInComment_ = false;-					++i;-				}-				continue;-			}-			if (nextLine_[i] == '\\')-			{-				++i;-				continue;-			}-			if (isInQuote_)-			{-				if (nextLine_[i] == quoteChar_)-					isInQuote_ = false;-				continue;-			}--			if (nextLine_[i] == '"'-			        || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))-			{-				isInQuote_ = true;-				quoteChar_ = nextLine_[i];-				continue;-			}-			if (nextLine_.compare(i, 2, "//") == 0)-			{-				i = nextLine_.length();-				continue;-			}-			// process the current char-			if ((nextLine_[i] == '{' && (currentChar == '-' || currentChar == '+'))-			        || nextLine_[i] == ';')-				goto EndOfWhileLoop;       // end of method definition-			if (nextLine_[i] == ']')-			{-				--sqBracketCount;-				if (sqBracketCount == 0)-					goto EndOfWhileLoop;   // end of method call-			}-			if (nextLine_[i] == '[')-				++sqBracketCount;-			if (isFirstLine)	 // colon align does not include the first line-				continue;-			if (sqBracketCount > 1)-				continue;-			if (haveFirstColon)  // multiple colons per line-				continue;-			if (nextLine_[i] == '?')-			{-				haveTernary = true;-				continue;-			}-			// compute colon adjustment-			if (nextLine_[i] == ':')-			{-				if (haveTernary)-				{-					haveTernary = false;-					continue;-				}-				haveFirstColon = true;-				foundMethodColon = true;-				if (isObjCStyle() && shouldPadMethodColon)-				{-					int spacesStart;-					for (spacesStart = i; spacesStart > 0; spacesStart--)-						if (!std::isblank(nextLine_[spacesStart - 1]))-							break;-					int spaces = i - spacesStart;-					if (objCColonPadMode == COLON_PAD_ALL || objCColonPadMode == COLON_PAD_BEFORE)-						colonAdjust = 1 - spaces;-					else if (objCColonPadMode == COLON_PAD_NONE || objCColonPadMode == COLON_PAD_AFTER)-						colonAdjust = 0 - spaces;-				}-				// compute alignment-				int colonPosition = i + colonAdjust;-				if (colonPosition > colonAlign)-					colonAlign = colonPosition;-			}-		}	// end of for loop-		isFirstLine = false;-	}	// end of while loop+    assert(currentChar == '+' || currentChar == '-' || currentChar == '[');+    assert(getAlignMethodColon());++    bool isFirstLine = true;+    bool haveFirstColon = false;+    bool foundMethodColon = false;+    bool isInComment_ = false;+    bool isInQuote_ = false;+    bool haveTernary = false;+    char quoteChar_ = ' ';+    int  sqBracketCount = 0;+    int  colonAdjust = 0;+    int  colonAlign = 0;+    std::string nextLine_ = currentLine;+    ASPeekStream stream(sourceIterator);++    // peek next line+    while (sourceIterator->hasMoreLines() || isFirstLine)+    {+        if (!isFirstLine)+            nextLine_ = stream.peekNextLine();+        // parse the line+        haveFirstColon = false;+        nextLine_ = ASBeautifier::trim(nextLine_);+        for (size_t i = 0; i < nextLine_.length(); i++)+        {+            if (std::isblank(nextLine_[i]))+                continue;+            if (nextLine_.compare(i, 2, "/*") == 0)+                isInComment_ = true;+            if (isInComment_)+            {+                if (nextLine_.compare(i, 2, "*/") == 0)+                {+                    isInComment_ = false;+                    ++i;+                }+                continue;+            }+            if (nextLine_[i] == '\\')+            {+                ++i;+                continue;+            }+            if (isInQuote_)+            {+                if (nextLine_[i] == quoteChar_)+                    isInQuote_ = false;+                continue;+            }++            if (nextLine_[i] == '"'+                    || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))+            {+                isInQuote_ = true;+                quoteChar_ = nextLine_[i];+                continue;+            }+            if (nextLine_.compare(i, 2, "//") == 0)+            {+                i = nextLine_.length();+                continue;+            }+            // process the current char+            if ((nextLine_[i] == '{' && (currentChar == '-' || currentChar == '+'))+                    || nextLine_[i] == ';')+                goto EndOfWhileLoop;       // end of method definition+            if (nextLine_[i] == ']')+            {+                --sqBracketCount;+                if (sqBracketCount == 0)+                    goto EndOfWhileLoop;   // end of method call+            }+            if (nextLine_[i] == '[')+                ++sqBracketCount;+            if (isFirstLine)	 // colon align does not include the first line+                continue;+            if (sqBracketCount > 1)+                continue;+            if (haveFirstColon)  // multiple colons per line+                continue;+            if (nextLine_[i] == '?')+            {+                haveTernary = true;+                continue;+            }+            // compute colon adjustment+            if (nextLine_[i] == ':')+            {+                if (haveTernary)+                {+                    haveTernary = false;+                    continue;+                }+                haveFirstColon = true;+                foundMethodColon = true;+                if (isObjCStyle() && shouldPadMethodColon)+                {+                    int spacesStart;+                    for (spacesStart = i; spacesStart > 0; spacesStart--)+                        if (!std::isblank(nextLine_[spacesStart - 1]))+                            break;+                    int spaces = i - spacesStart;+                    if (objCColonPadMode == COLON_PAD_ALL || objCColonPadMode == COLON_PAD_BEFORE)+                        colonAdjust = 1 - spaces;+                    else if (objCColonPadMode == COLON_PAD_NONE || objCColonPadMode == COLON_PAD_AFTER)+                        colonAdjust = 0 - spaces;+                }+                // compute alignment+                int colonPosition = i + colonAdjust;+                if (colonPosition > colonAlign)+                    colonAlign = colonPosition;+            }+        }	// end of for loop+        isFirstLine = false;+    }	// end of while loop EndOfWhileLoop:-	if (!foundMethodColon)-		colonAlign = -1;-	return colonAlign;+    if (!foundMethodColon)+        colonAlign = -1;+    return colonAlign; }  // pad an Objective-C method colon void ASFormatter::padObjCMethodColon() {-	assert(currentChar == ':');-	int commentAdjust = 0;-	char nextChar = peekNextChar();-	if (objCColonPadMode == COLON_PAD_NONE-	        || objCColonPadMode == COLON_PAD_AFTER-	        || nextChar == ')')-	{-		// remove spaces before-		for (int i = formattedLine.length() - 1; (i > -1) && std::isblank(formattedLine[i]); i--)-		{-			formattedLine.erase(i);-			--commentAdjust;-		}-	}-	else-	{-		// pad space before-		for (int i = formattedLine.length() - 1; (i > 0) && std::isblank(formattedLine[i]); i--)-			if (std::isblank(formattedLine[i - 1]))-			{-				formattedLine.erase(i);-				--commentAdjust;-			}-		if (!formattedLine.empty())-		{-			appendSpacePad();-			formattedLine.back() = ' ';  // convert any tab to space-		}-	}-	if (objCColonPadMode == COLON_PAD_NONE-	        || objCColonPadMode == COLON_PAD_BEFORE-	        || nextChar == ')')-	{-		// remove spaces after-		size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);-		if (nextText == std::string::npos)-			nextText = currentLine.length();-		int spaces = nextText - charNum - 1;-		if (spaces > 0)-		{-			// do not use goForward here-			currentLine.erase(charNum + 1, spaces);-			spacePadNum -= spaces;-		}-	}-	else-	{-		// pad space after-		size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);-		if (nextText == std::string::npos)-			nextText = currentLine.length();-		int spaces = nextText - charNum - 1;-		if (spaces == 0)-		{-			currentLine.insert(charNum + 1, 1, ' ');-			spacePadNum += 1;-		}-		else if (spaces > 1)-		{-			// do not use goForward here-			currentLine.erase(charNum + 1, spaces - 1);-			currentLine[charNum + 1] = ' ';  // convert any tab to space-			spacePadNum -= spaces - 1;-		}-	}-	spacePadNum += commentAdjust;+    assert(currentChar == ':');+    int commentAdjust = 0;+    char nextChar = peekNextChar();+    if (objCColonPadMode == COLON_PAD_NONE+            || objCColonPadMode == COLON_PAD_AFTER+            || nextChar == ')')+    {+        // remove spaces before+        for (int i = formattedLine.length() - 1; (i > -1) && std::isblank(formattedLine[i]); i--)+        {+            formattedLine.erase(i);+            --commentAdjust;+        }+    }+    else+    {+        // pad space before+        for (int i = formattedLine.length() - 1; (i > 0) && std::isblank(formattedLine[i]); i--)+            if (std::isblank(formattedLine[i - 1]))+            {+                formattedLine.erase(i);+                --commentAdjust;+            }+        if (!formattedLine.empty())+        {+            appendSpacePad();+            formattedLine.back() = ' ';  // convert any tab to space+        }+    }+    if (objCColonPadMode == COLON_PAD_NONE+            || objCColonPadMode == COLON_PAD_BEFORE+            || nextChar == ')')+    {+        // remove spaces after+        size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);+        if (nextText == std::string::npos)+            nextText = currentLine.length();+        int spaces = nextText - charNum - 1;+        if (spaces > 0)+        {+            // do not use goForward here+            currentLine.erase(charNum + 1, spaces);+            spacePadNum -= spaces;+        }+    }+    else+    {+        // pad space after+        size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);+        if (nextText == std::string::npos)+            nextText = currentLine.length();+        int spaces = nextText - charNum - 1;+        if (spaces == 0)+        {+            currentLine.insert(charNum + 1, 1, ' ');+            spacePadNum += 1;+        }+        else if (spaces > 1)+        {+            // do not use goForward here+            currentLine.erase(charNum + 1, spaces - 1);+            currentLine[charNum + 1] = ' ';  // convert any tab to space+            spacePadNum -= spaces - 1;+        }+    }+    spacePadNum += commentAdjust; }  // Remove the leading '*' from a comment line and indent to the next tab. void ASFormatter::stripCommentPrefix() {-	int firstChar = formattedLine.find_first_not_of(" \t");-	if (firstChar < 0)-		return;--	if (isInCommentStartLine)-	{-		// comment opener must begin the line-		if (formattedLine.compare(firstChar, 2, "/*") != 0)-			return;-		int commentOpener = firstChar;-		// ignore single line comments-		int commentEnd = formattedLine.find("*/", firstChar + 2);-		if (commentEnd != -1)-			return;-		// first char after the comment opener must be at least one indent-		int followingText = formattedLine.find_first_not_of(" \t", commentOpener + 2);-		if (followingText < 0)-			return;-		if (formattedLine[followingText] == '*' || formattedLine[followingText] == '!')-			followingText = formattedLine.find_first_not_of(" \t", followingText + 1);-		if (followingText < 0)-			return;-		if (formattedLine[followingText] == '*')-			return;-		int indentLen = getIndentLength();-		int followingTextIndent = followingText - commentOpener;-		if (followingTextIndent < indentLen)-		{-			std::string stringToInsert(indentLen - followingTextIndent, ' ');-			formattedLine.insert(followingText, stringToInsert);-		}-		return;-	}-	// comment body including the closer-	if (formattedLine[firstChar] == '*')-	{-		if (formattedLine.compare(firstChar, 2, "*/") == 0)-		{-			// line starts with an end comment-			formattedLine = "*/";-		}-		else-		{-			// build a new line with one indent-			int secondChar = formattedLine.find_first_not_of(" \t", firstChar + 1);-			if (secondChar < 0)-			{-				adjustChecksumIn(-'*');-				formattedLine.erase();-				return;-			}-			if (formattedLine[secondChar] == '*')-				return;-			// replace the leading '*'-			int indentLen = getIndentLength();-			adjustChecksumIn(-'*');-			// second char must be at least one indent-			if (formattedLine.substr(0, secondChar).find('\t') != std::string::npos)-			{-				formattedLine.erase(firstChar, 1);-			}-			else-			{-				int spacesToInsert = 0;-				if (secondChar >= indentLen)-					spacesToInsert = secondChar;-				else-					spacesToInsert = indentLen;-				formattedLine = std::string(spacesToInsert, ' ') + formattedLine.substr(secondChar);-			}-			// remove a trailing '*'-			int lastChar = formattedLine.find_last_not_of(" \t");-			if (lastChar > -1 && formattedLine[lastChar] == '*')-			{-				adjustChecksumIn(-'*');-				formattedLine[lastChar] = ' ';-			}-		}-	}-	else-	{-		// first char not a '*'-		// first char must be at least one indent-		if (formattedLine.substr(0, firstChar).find('\t') == std::string::npos)-		{-			int indentLen = getIndentLength();-			if (firstChar < indentLen)-			{-				std::string stringToInsert(indentLen, ' ');-				formattedLine = stringToInsert + formattedLine.substr(firstChar);-			}-		}-	}+    int firstChar = formattedLine.find_first_not_of(" \t");+    if (firstChar < 0)+        return;++    if (isInCommentStartLine)+    {+        // comment opener must begin the line+        if (formattedLine.compare(firstChar, 2, "/*") != 0)+            return;+        int commentOpener = firstChar;+        // ignore single line comments+        int commentEnd = formattedLine.find("*/", firstChar + 2);+        if (commentEnd != -1)+            return;+        // first char after the comment opener must be at least one indent+        int followingText = formattedLine.find_first_not_of(" \t", commentOpener + 2);+        if (followingText < 0)+            return;+        if (formattedLine[followingText] == '*' || formattedLine[followingText] == '!')+            followingText = formattedLine.find_first_not_of(" \t", followingText + 1);+        if (followingText < 0)+            return;+        if (formattedLine[followingText] == '*')+            return;+        int indentLen = getIndentLength();+        int followingTextIndent = followingText - commentOpener;+        if (followingTextIndent < indentLen)+        {+            std::string stringToInsert(indentLen - followingTextIndent, ' ');+            formattedLine.insert(followingText, stringToInsert);+        }+        return;+    }+    // comment body including the closer+    if (formattedLine[firstChar] == '*')+    {+        if (formattedLine.compare(firstChar, 2, "*/") == 0)+        {+            // line starts with an end comment+            formattedLine = "*/";+        }+        else+        {+            // build a new line with one indent+            int secondChar = formattedLine.find_first_not_of(" \t", firstChar + 1);+            if (secondChar < 0)+            {+                adjustChecksumIn(-'*');+                formattedLine.erase();+                return;+            }+            if (formattedLine[secondChar] == '*')+                return;+            // replace the leading '*'+            int indentLen = getIndentLength();+            adjustChecksumIn(-'*');+            // second char must be at least one indent+            if (formattedLine.substr(0, secondChar).find('\t') != std::string::npos)+            {+                formattedLine.erase(firstChar, 1);+            }+            else+            {+                int spacesToInsert = 0;+                if (secondChar >= indentLen)+                    spacesToInsert = secondChar;+                else+                    spacesToInsert = indentLen;+                formattedLine = std::string(spacesToInsert, ' ') + formattedLine.substr(secondChar);+            }+            // remove a trailing '*'+            int lastChar = formattedLine.find_last_not_of(" \t");+            if (lastChar > -1 && formattedLine[lastChar] == '*')+            {+                adjustChecksumIn(-'*');+                formattedLine[lastChar] = ' ';+            }+        }+    }+    else+    {+        // first char not a '*'+        // first char must be at least one indent+        if (formattedLine.substr(0, firstChar).find('\t') == std::string::npos)+        {+            int indentLen = getIndentLength();+            if (firstChar < indentLen)+            {+                std::string stringToInsert(indentLen, ' ');+                formattedLine = stringToInsert + formattedLine.substr(firstChar);+            }+        }+    } }  }   // end namespace astyle

src/core/astyle/ASResource.cpp

@@ -1,5 +1,5 @@ // ASResource.cpp-// Copyright (c) 2025 The Artistic Style Authors.+// Copyright (c) 2026 The Artistic Style Authors. // This code is licensed under the MIT License. // License.md describes the conditions under which this software may be distributed. @@ -21,6 +21,7 @@ const std::string ASResource::_AS_FINALLY = std::string("__finally"); const std::string ASResource::_AS_TRY = std::string("__try"); const std::string ASResource::AS_ADD = std::string("add"); const std::string ASResource::AS_AUTO = std::string("auto");+const std::string ASResource::AS_REQUIRES = std::string("requires"); const std::string ASResource::AS_AUTORELEASEPOOL = std::string("autoreleasepool"); const std::string ASResource::AS_CASE = std::string("case"); const std::string ASResource::AS_CATCH = std::string("catch");@@ -89,6 +90,10 @@ const std::string ASResource::AS__ASM__ = std::string("__asm__"); const std::string ASResource::AS_MS_ASM = std::string("_asm"); const std::string ASResource::AS_MS__ASM = std::string("__asm"); +const std::string ASResource::AS__ATTRIBUTE__ = std::string("__attribute__");+const std::string ASResource::AS__DECLSPEC = std::string("__declspec");+const std::string ASResource::AS_ALIGNAS = std::string("alignas");+ const std::string ASResource::AS_BAR_DEFINE = std::string("#define"); const std::string ASResource::AS_BAR_INCLUDE = std::string("#include"); const std::string ASResource::AS_BAR_IF = std::string("#if");

src/core/bbcodegenerator.cpp

@@ -111,6 +111,9 @@ void BBCodeGenerator::initOutputTags ()         getCloseTag ( docStyle.getErrorStyle() ),         getCloseTag ( docStyle.getErrorMessageStyle() )     };++    guideTagOpen = getOpenTag ( docStyle.getIndentGuideStyle() );+    guideTagClose = getCloseTag ( docStyle.getIndentGuideStyle() ); }  string BBCodeGenerator::maskCharacter ( unsigned char c )

src/core/codegenerator.cpp

@@ -89,6 +89,7 @@ const string CodeGenerator::STY_NAME_IPL="ipl"; //interpolation const string CodeGenerator::STY_NAME_HVR="hvr"; const string CodeGenerator::STY_NAME_ERR="err"; const string CodeGenerator::STY_NAME_ERM="erm";+const string CodeGenerator::STY_NAME_GUI="gui"; //indentation guide  vector<Diluculum::LuaFunction*> CodeGenerator::pluginChunks; @@ -145,6 +146,7 @@ CodeGenerator::CodeGenerator ( highlight::OutputType type )      out ( nullptr ),      encoding ( "none" ),      docTitle ( "Source file" ),+     isUtf8Encoding ( false ),      maskWs ( false ),      excludeWs ( false ),      fragmentOutput ( false ),@@ -171,6 +173,8 @@ CodeGenerator::CodeGenerator ( highlight::OutputType type )      startLineCntCurFile( 1 ),      extraEOFChar( 255 ),      maxLineCnt ( UINT_MAX ),+     skipLeadingCols ( 0 ),+     lineHeadPending ( false ),      inputFilesCnt (0),      processedFilesCnt (0),      kwOffset(0),@@ -471,6 +475,7 @@ string CodeGenerator::getTitle() void CodeGenerator::setEncoding ( const string& encodingName ) {     encoding = encodingName;+    isUtf8Encoding = encoding=="utf-8"; }  bool CodeGenerator::formattingDisabled()@@ -488,6 +493,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;@@ -534,6 +544,8 @@ void CodeGenerator::setEOLDelimiter(char delim)  void CodeGenerator::reset() {+    lookaheadLines.clear();+    lookaheadEof = false;     lineIndex = 0;     lineNumber = 0;     line.clear();@@ -617,6 +629,101 @@ bool CodeGenerator::AtEnd(char c) const {     bool ret = instream_eof || c_null || instream_peek_null;     return ret; }+bool CodeGenerator::fetchRawLine ( string &newLine )+{+    if ( formattingPossible && formattingEnabled ) {+        if ( !formatter->hasMoreLines() ) return true;+        newLine = formatter->nextLine();+        return false;+    }+    return AtEnd() || ! getline ( *in, newLine, eolDelimiter );+}++bool CodeGenerator::readLookahead ( string &newLine )+{+    if ( lookaheadLines.empty() ) {+        if ( lookaheadEof ) return true;+        string bufferedLine;+        if ( ( lookaheadEof = fetchRawLine ( bufferedLine ) ) ) return true;+        lookaheadLines.push_back ( bufferedLine );+    }+    newLine = lookaheadLines.front();+    lookaheadLines.pop_front();+    return false;+}++unsigned int CodeGenerator::nextCodeIndent()+{+    // bounded so that a long run of blank lines cannot buffer the whole input+    for ( size_t i=0; i<MAX_LOOKAHEAD_LINES; ++i ) {+        while ( i >= lookaheadLines.size() ) {+            string bufferedLine;+            if ( lookaheadEof || ( lookaheadEof = fetchRawLine ( bufferedLine ) ) ) return 0;+            lookaheadLines.push_back ( bufferedLine );+        }+        const string &l = lookaheadLines[i];+        size_t codeStart = l.find_first_not_of ( " \t" );+        if ( codeStart == string::npos ) continue;++        unsigned int tabWidth = preFormatter.getNumberSpaces(), indent=0;+        for ( size_t p=0; p<codeStart; ++p )+            indent += ( l[p]=='\t' ) ? tabWidth - ( indent % tabWidth ) : 1;+        return indent;+    }+    return 0;+}++void CodeGenerator::setIndentGuides ( bool b )+{+    showIndentGuides = b;+}++void CodeGenerator::initIndentGuides()+{+    guidePrefix.clear();+    guideSkipWs = 0;+    guideColDelta = 0;+    // wrapped continuation lines carry a synthetic alignment prefix, not real indentation+    if ( !showIndentGuides || guideTagOpen.empty() || !numberCurrentLine ) return;++    if ( guideGlyph.empty() )+        guideGlyph = ( StringTools::change_case ( encoding ) == "utf-8" ) ? "\xE2\x94\x82" : "|";++    size_t codeStart = line.find_first_not_of ( " \t" );+    unsigned int indent;++    if ( codeStart == string::npos ) {+        // blank lines adopt the indentation of the next line which contains code+        guideSkipWs = line.length();+        indent = nextCodeIndent();+    } else {+        guideSkipWs = codeStart;+        indent = codeStart;+    }++    unsigned int tabWidth = preFormatter.getNumberSpaces();+    unsigned int guideCnt = indent / tabWidth;+    if ( !guideCnt ) {+        guideSkipWs = ( codeStart == string::npos ) ? line.length() : 0;+        guideColDelta = -(int) guideSkipWs;+        return;+    }++    string raw;+    for ( unsigned int i=0; i<guideCnt; ++i )+        raw += guideGlyph + string ( tabWidth-1, ' ' );+    raw.append ( indent % tabWidth, ' ' );++    // encode the glyph and spaces through the format's own escaping, so the+    // guide does not collapse where literal whitespace would (latex, tex, odt)+    string guides;+    for ( unsigned char c : raw )+        guides += maskCharacter ( c );++    guidePrefix = guideTagOpen + guides + guideTagClose;+    guideColDelta = (int) indent - (int) guideSkipWs;+}+ bool CodeGenerator::readNewLine ( string &newLine ) {     bool eof=false;@@ -624,14 +731,7 @@ bool CodeGenerator::readNewLine ( string &newLine )     if ( lineIndex ) terminatingChar=newLine[lineIndex-1];      while (!eof && startLineCntCurFile>0) {-        if ( formattingPossible && formattingEnabled ) {-            eof=!formatter->hasMoreLines();-            if ( !eof ) {-                newLine = formatter->nextLine();-            }-        } else {-            eof = AtEnd() || ! getline ( *in, newLine, eolDelimiter );-        }+        eof = readLookahead ( newLine );         --startLineCntCurFile;     } @@ -642,6 +742,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 ); } @@ -672,8 +787,14 @@ void CodeGenerator::matchRegex ( const string &line, State skipState)             groupID = ( regexElem->capturingGroup<0 ) ? cur->size()-1 : regexElem->capturingGroup;             matchBegin = cur->position(groupID); -            regexGroups.insert (+            // if another regex already claimed this start position, keep whichever+            // match is longer (e.g. a raw string open delimiter like R"( must win+            // over a single-character identifier match on the same 'R')+            auto insertResult = regexGroups.insert (                 make_pair ( matchBegin + 1, RegexToken ( regexElem->open, cur->length(groupID), regexElem->kwClass, regexElem->langName ) ) );+            if ( !insertResult.second && insertResult.first->second.length < ( unsigned int ) cur->length ( groupID ) ) {+                insertResult.first->second = RegexToken ( regexElem->open, cur->length(groupID), regexElem->kwClass, regexElem->langName );+            }              // priority regex (match required)             if (regexElem->priority) {@@ -690,9 +811,9 @@ unsigned char CodeGenerator::getInputChar()          //more testing required:         if (outputType==ESC_TRUECOLOR || outputType==ESC_XTERM256)-            lastLineLength=StringTools::utf8_strlen(line + lsSyntaxErrorDesc);+            lastLineLength=StringTools::utf8_strlen(line + lsSyntaxErrorDesc) + guideColDelta; -        bool eof=false;+        bool eof=false, freshSourceLine=true;         if ( preFormatter.isEnabled() ) {             if ( !preFormatter.hasMoreLines() ) {                 eof=readNewLine ( line );@@ -700,6 +821,7 @@ unsigned char CodeGenerator::getInputChar()                 ++lineNumber;                 numberCurrentLine = true;             } else {+                freshSourceLine = false;                 if (numberWrappedLines)                     ++lineNumber;                 numberCurrentLine = numberWrappedLines;@@ -721,6 +843,7 @@ unsigned char CodeGenerator::getInputChar()          lineContainedTestCase=false;         lineContainedStmt=false;+        if ( freshSourceLine ) initIndentGuides();         matchRegex ( line );          return ( eof ) ?'\0':'\n';@@ -886,7 +1009,7 @@ unsigned int CodeGenerator::getCurrentKeywordClassId(){     unsigned int kwClassId=0;      // this vector contains the defined keyword classes, and currentKeywordClass is its index:-    vector<string> kwClasses=currentSyntax->getKeywordClasses();+    const vector<string>& kwClasses=currentSyntax->getKeywordClasses();      if (currentKeywordClass && currentKeywordClass<=kwClasses.size()) {         string kwClassName=kwClasses[currentKeywordClass-1];@@ -916,10 +1039,13 @@ void CodeGenerator::maskString ( ostream& ss, const string & s )         ss << getHoverTagOpen(escHoverText);     } +    string maskedText;+    maskedText.reserve(s.size());     for (const auto &c : s)     {-        ss << maskCharacter ( c );+        maskedText.append(maskCharacter ( c ));     }+    ss << maskedText;      if (escHoverText.size()) {         ss << getHoverTagClose();@@ -930,8 +1056,7 @@ void CodeGenerator::maskString ( ostream& ss, const string & s )          PositionState ps(currentState, getCurrentKeywordClassId(), false); -        //TODO avoid repeated string comparison:-        int slen = encoding=="utf-8" ? StringTools::utf8_strlen(s) : s.length();+        int slen = isUtf8Encoding ? StringTools::utf8_strlen(s) : s.length();         for (int i=0; i< slen; i++ ) {             stateTraceCurrent.push_back(ps);         }@@ -1086,6 +1211,77 @@ LoadResult CodeGenerator::loadLanguage ( const string& langDefPath, bool embedde     return result; } +bool CodeGenerator::convertUnicodeInput()+{+    if ( !in || in->fail() ) return false;++    // UTF-32LE has to be tested before UTF-16LE (same first two bytes)+    struct UnicodeBom {+        const char* magic;+        size_t length;+        unsigned int unitSize;+        bool bigEndian;+    };+    const UnicodeBom boms[] = {+        { "\xFF\xFE\x00\x00", 4, 4, false },+        { "\x00\x00\xFE\xFF", 4, 4, true },+        { "\xFF\xFE", 2, 2, false },+        { "\xFE\xFF", 2, 2, true },+    };++    // read the first bytes sequentially, so that this works with stdin too+    string head;+    while ( head.size() < 4 ) {+        int c = in->peek();+        if ( c == EOF ) break;+        // stop as soon as no BOM can match anymore+        bool candidate = false;+        for ( const UnicodeBom& bom : boms ) {+            if ( head.size() < bom.length && head.compare ( 0, head.size(), bom.magic, head.size() ) == 0+                    && (char) c == bom.magic[head.size()] ) {+                candidate = true;+                break;+            }+        }+        if ( !candidate ) break;+        head += (char) in->get();+    }++    const UnicodeBom* found = nullptr;+    for ( const UnicodeBom& bom : boms ) {+        if ( head.size() >= bom.length && head.compare ( 0, bom.length, bom.magic, bom.length ) == 0 ) {+            found = &bom;+            break;+        }+    }++    if ( !found ) {+        // nothing consumed except for partial BOM candidates; restore them+        if ( !head.empty() ) {+            in->clear();+            for ( size_t i=head.size(); i>0; --i ) {+                if ( !in->putback ( head[i-1] ) ) break;+            }+        }+        in->clear();+        return false;+    }++    // a UTF-16LE BOM may have been followed by a NUL character matching the UTF-32LE pattern+    string content = head.substr ( found->length );+    std::ostringstream rest;+    rest << in->rdbuf();+    content += rest.str();++    if ( in != &cin ) delete in;+    in = new istringstream ( StringTools::utfWideToUtf8 ( content, found->unitSize, found->bigEndian ) );++    if ( StringTools::change_case ( encoding ) != "none" )+        setEncoding ( "utf-8" );++    return true;+}+ bool CodeGenerator::validateInputStream() {     if ( !in ) return false;@@ -1245,6 +1441,9 @@ ParseError CodeGenerator::generateFile ( const string &inFileName,      in = ( inFileName.empty() ? &cin :new ifstream ( inFileName.c_str() ) ); +    const string savedEncoding = encoding;+    convertUnicodeInput();+     if ( validateInput )         if ( !validateInputStream() ) error= BAD_INPUT; @@ -1271,10 +1470,14 @@ ParseError CodeGenerator::generateFile ( const string &inFileName,         delete out;         out=nullptr;     }-    if ( !inFileName.empty() ) {+    if ( in != &cin ) {         delete in;-        in=nullptr;     }+    in=nullptr;++    if ( encoding != savedEncoding )+        setEncoding ( savedEncoding );+     return error; } @@ -1349,7 +1552,11 @@ string CodeGenerator::generateStringFromFile ( const string &inFileName )         return "";     } +    const string savedEncoding = encoding;+    convertUnicodeInput();+     if ( validateInput && !validateInputStream() ) {+        setEncoding ( savedEncoding );         return "ERROR: detected binary input";     } @@ -1368,6 +1575,9 @@ string CodeGenerator::generateStringFromFile ( const string &inFileName )     delete in;     in=nullptr; +    if ( encoding != savedEncoding )+        setEncoding ( savedEncoding );+     return result; } @@ -1398,13 +1608,6 @@ void CodeGenerator::openKWTag ( unsigned int kwClassID )     currentState=KEYWORD; } -void CodeGenerator::closeKWTag ( unsigned int kwClassID )-{-    *out << closeTags.at(getStyleID ( KEYWORD, kwClassID ) );-    flushWs(3);-    currentState=_UNKNOWN;-}- bool CodeGenerator::loadEmbeddedLang(const string&embedLangDefPath) {     if (nestedLangs.empty()) {@@ -1504,15 +1707,18 @@ void CodeGenerator::processRootState()          case _EOL:             // XTERM256 fix (issue with less cmd)-            if  (!firstLine || showLineNumbers) {+            if  (!firstLine || showLineNumbers || !guidePrefix.empty()) {                 closeTag ( STANDARD );             }+            {+            bool reopen = !firstLine || showLineNumbers || !guidePrefix.empty();             insertLineNumber(!firstLine);-            if (!firstLine || showLineNumbers) {+            if (reopen) {                 flushWs(5);                 stateTraceCurrent.clear();                 openTag ( STANDARD );             }+            }             firstLine=false;             break;         case _EOF:@@ -1596,6 +1802,14 @@ bool CodeGenerator::processKeywordState ( State myState )          exitState=false;      openKWTag ( myClassID );++    // Capture the closing tag now: a NestedSections delimiter may switch the+    // active syntax mid-token (via getCurrentState() -> loadEmbeddedLang()),+    // which resizes openTags/closeTags to match the nested language's keyword+    // class count. Deriving the closing tag from myClassID again afterwards+    // would then index into the wrong (differently sized) vector.+    const string myCloseTag = closeTags.at ( getStyleID ( KEYWORD, myClassID ) );+     do {         printMaskedToken ( newState!=_WS,                            ( currentSyntax->isIgnoreCase() ) ? keywordCase : StringTools::CASE_UNCHANGED );@@ -1622,7 +1836,9 @@ bool CodeGenerator::processKeywordState ( State myState )         }     } while ( !exitState  &&  !eof ); -    closeKWTag ( myClassID );+    *out << myCloseTag;+    flushWs(3);+    currentState=_UNKNOWN;      currentKeywordClass=0;     return eof;@@ -2052,7 +2268,8 @@ void CodeGenerator::processWsState() {      if ( !maskWs ) {-        wsBuffer += token;+        if ( guideSkipWs ) --guideSkipWs;+        else wsBuffer += token;         token.clear();         return;     }@@ -2068,10 +2285,21 @@ void CodeGenerator::processWsState()         ++lineIndex;     } +    if ( guideSkipWs ) {+        int skipped = std::min ( (int) guideSkipWs, cntWs );+        guideSkipWs -= skipped;+        cntWs -= skipped;+    }+     if ( cntWs>1 ) {          unsigned int styleID=getStyleID ( currentState, currentKeywordClass );-        if ( excludeWs && styleID!=_UNKNOWN ) {+        // A NestedSections delimiter may switch the active syntax between the+        // keyword's opening and this whitespace, resizing openTags/closeTags+        // to the nested language's (possibly smaller) keyword class count.+        // styleID may then be stale, so guard the lookup.+        bool validStyleID = styleID!=_UNKNOWN && styleID<closeTags.size() && styleID<openTags.size();+        if ( excludeWs && validStyleID ) {             *out << closeTags[styleID];         } @@ -2083,10 +2311,10 @@ void CodeGenerator::processWsState()             }         }         *out << maskWsEnd;-        if ( excludeWs && styleID!=_UNKNOWN ) {+        if ( excludeWs && validStyleID ) {             *out << openTags[styleID];         }-    } else {+    } else if ( cntWs==1 ) {          *out << spacer; //Bugfix fehlender Space nach Strings         if (applySyntaxTestCase){@@ -2174,7 +2402,7 @@ void CodeGenerator::printTrace(const string &s){ //column: lineIndex (not a UTF-8 validated string position) void CodeGenerator::runSyntaxTestcases(unsigned int column){ -    if (encoding=="utf-8")+    if (isUtf8Encoding)         column = StringTools::utf8_strlen(line.substr(0, column));      if (column >= stateTraceTest.size()) return;@@ -2331,6 +2559,25 @@ void CodeGenerator::insertLineNumber ( bool insertNewLine )         numberPrefix << initialSpacer << closeTags[LINENUMBER];         wsBuffer += numberPrefix.str();     }++    insertLineHead();+}++void CodeGenerator::insertLineHead()+{+    // wrapped segments continue a line whose head was already printed+    if ( !lineHeadPending ) {+        wsBuffer += guidePrefix;+        guidePrefix.clear();+        return;+    }++    ostringstream headPrefix;+    maskString ( headPrefix, lineHead );+    wsBuffer += headPrefix.str();+    lineHeadPending = false;+    wsBuffer += guidePrefix;+    guidePrefix.clear(); }  unsigned int CodeGenerator::getLineIndex()

src/core/elementstyle.cpp

@@ -141,4 +141,12 @@ void ElementStyle::setCustomOverride(bool override) {     customOverride = override; } +int ElementStyle::getAnsiIndex() const {+    return ansiIndex;+}++void ElementStyle::setAnsiIndex(int idx) {+    ansiIndex = idx;+}+ }

src/core/htmlgenerator.cpp

@@ -187,6 +187,10 @@ void HtmlGenerator::initOutputTags ()      closeTags.assign ( NUMBER_BUILTIN_STATES, "</span>" );     closeTags[0] = "";++    guideTagOpen = useInlineCSS ? getOpenTag ( docStyle.getIndentGuideStyle() )+                                : getOpenTag ( STY_NAME_GUI );+    guideTagClose = "</span>"; }  string HtmlGenerator::getAttributes ( const string & elemName, const ElementStyle & elem )@@ -294,6 +298,10 @@ string HtmlGenerator::getStyleDefinition()             << getAttributes ( STY_NAME_ERM, docStyle.getErrorMessageStyle() )             << getAttributes ( STY_NAME_ERR, docStyle.getErrorStyle() ); +        if ( showIndentGuides ) {+            os << getAttributes ( STY_NAME_GUI, docStyle.getIndentGuideStyle() );+        }+         for ( const auto &[first, second] : docStyle.getKeywordStyles() ) {             os << getAttributes ( first, second );         }@@ -413,6 +421,8 @@ void HtmlGenerator::insertLineNumber ( bool insertNewLine )         }         wsBuffer += numberPrefix.str();     }++    insertLineHead(); }  bool HtmlGenerator::printIndexFile ( const vector<string> &fileList,

src/core/latexgenerator.cpp

@@ -86,7 +86,7 @@ string LatexGenerator::getHeader()     if ( StringTools::change_case ( encoding ) == "utf-8" ) {         os << "\\usepackage{ucs}\n\\usepackage[utf8x]{inputenc}\n";     } else if ( encodingDefined() ) {-        os << "\\usepackage[latin1]{inputenc}\n";+        os << "\\usepackage[utf8]{inputenc}\n";     }      //needed for Righttorque symbol@@ -153,14 +153,14 @@ string LatexGenerator::getFooter()     if (beamerMode)       os  << "}\n"; -    os << "\\end {document}\n";+    os << "\\end{document}\n";      if (!omitVersionComment) {-     os  << "(* LaTeX generated by highlight "+     os  << "% LaTeX generated by highlight "        << highlight::Info::getVersion()        << ", "        << highlight::Info::getWebsite()-       << " *)\n";+       << "\n";     }     return os.str(); }@@ -185,6 +185,9 @@ void LatexGenerator::initOutputTags()     };      closeTags.assign ( NUMBER_BUILTIN_STATES, "}" );++    guideTagOpen = "\\hl" + STY_NAME_GUI + "{";+    guideTagClose = "}"; }  string LatexGenerator::getAttributes ( const string & elemName,@@ -329,6 +332,9 @@ string LatexGenerator::getStyleDefinition()          os << getAttributes ( STY_NAME_ERR, docStyle.getErrorStyle() );         os << getAttributes ( STY_NAME_ERM, docStyle.getErrorMessageStyle() );+        if ( showIndentGuides ) {+            os << getAttributes ( STY_NAME_GUI, docStyle.getIndentGuideStyle() );+        }          for ( const auto &[first, second] : docStyle.getKeywordStyles() ) {             os << getAttributes ( first, second );

src/core/odtgenerator.cpp

@@ -71,6 +71,10 @@ string ODTGenerator::getStyleDefinition()            << getAttributes ( STY_NAME_ERR, docStyle.getErrorStyle() )            << getAttributes ( STY_NAME_ERM, docStyle.getErrorMessageStyle() ); +        if ( showIndentGuides ) {+            os << getAttributes ( STY_NAME_GUI, docStyle.getIndentGuideStyle() );+        }+         for ( const auto &[first, second] : docStyle.getKeywordStyles() ) {             os << getAttributes ( first, second );         }@@ -188,6 +192,9 @@ void ODTGenerator::initOutputTags ()      closeTags.assign ( NUMBER_BUILTIN_STATES, "</text:span>" );     closeTags[0] = "";++    guideTagOpen = getOpenTag ( STY_NAME_GUI );+    guideTagClose = "</text:span>"; }  string ODTGenerator::maskCharacter ( unsigned char c )

src/core/pangogenerator.cpp

@@ -92,6 +92,9 @@ void PangoGenerator::initOutputTags()      closeTags.assign ( NUMBER_BUILTIN_STATES, "</span>" );     closeTags[0] = "";++    guideTagOpen = getOpenTag ( docStyle.getIndentGuideStyle() );+    guideTagClose = "</span>"; }  string PangoGenerator::getHeader()

src/core/rtfgenerator.cpp

@@ -65,7 +65,134 @@ RtfGenerator::RtfGenerator()  string RtfGenerator::getHeader() {-    return string();+    stringstream s;+    isUtf8 = StringTools::change_case ( encoding ) == "utf-8";++    s << R"({\rtf1\ansi \deff1)" // drop \\uc0 because of unicode output+      << R"({\fonttbl{\f1\fmodern\fprq1\fcharset0 )";++    s << this->getBaseFont() ;+    s << ";}}"+      << "{\\colortbl;";++    s << "\\red"    << ( docStyle.getBgColour().getRed ( RTF ) );+    s << "\\green"    << ( docStyle.getBgColour().getGreen ( RTF ) );+    s << "\\blue"    << ( docStyle.getBgColour().getBlue ( RTF ) );+    s << ";";++    s << getAttributes ( docStyle.getDefaultStyle() );++    s << getAttributes ( docStyle.getStringStyle() );+    s << getAttributes ( docStyle.getNumberStyle() );+    s << getAttributes ( docStyle.getSingleLineCommentStyle() );++    s << getAttributes ( docStyle.getCommentStyle() );+    s << getAttributes ( docStyle.getEscapeCharStyle() );+    s << getAttributes ( docStyle.getPreProcessorStyle() );++    s << getAttributes ( docStyle.getPreProcStringStyle() );+    s << getAttributes ( docStyle.getLineStyle() );+    s << getAttributes ( docStyle.getOperatorStyle() );+    s << getAttributes ( docStyle.getInterpolationStyle() );++    s << getAttributes ( docStyle.getErrorStyle() );+    s << getAttributes ( docStyle.getErrorMessageStyle() );++    /* For output formats which can refer to external styles it is more safe+        to use the colour theme's keyword class names, since the language+        definitions (which may change during a batch conversion) do not have to+        define all keyword classes, that are needed to highlight all input files+        correctly. It is ok for RTF to use the language definition's class+        names, because RTF does not refer to external styles.+        We cannot use the theme's class names, because KSIterator returns an+        alphabetically ordered list, which is not good because RTF is dependent+        on the order. We access the keyword style with an ID, which is+        calculated ignoring the alphabetic order.+        */++    ///FIXME: nested syntax may be highlighted incorrectly if it contains more+    //        keyword definitions than the hosting syntax.+    //        Workaround: Add keyword group to hosting syntax (see html.lang)+    vector<string>  keywordClasses = currentSyntax->getKeywordClasses();++    for ( unsigned int i=0; i<keywordClasses.size(); i++ ) {+        s << getAttributes ( docStyle.getKeywordStyle ( keywordClasses[i] ) );+    }++    if ( showIndentGuides ) {+        // the guide colour is appended after the (variable-length) keyword classes,+        // so its colour table index has to be computed here rather than in initOutputTags()+        int guideStyleNumber = KEYWORD + ( int ) keywordClasses.size();+        s << getAttributes ( docStyle.getIndentGuideStyle() );+        guideTagOpen = getOpenTag ( guideStyleNumber, docStyle.getIndentGuideStyle() );+        guideTagClose = getCloseTag ( docStyle.getIndentGuideStyle() );+    }++    s << "}\n";++    if ( addCharStyles ) {+        s << "{\\stylesheet{\n";+        s << getCharStyle ( STANDARD, docStyle.getDefaultStyle(),+                            "HL Default" );+        s << getCharStyle ( STRING, docStyle.getStringStyle(), "HL String" );+        s << getCharStyle ( NUMBER, docStyle.getNumberStyle(), "HL Number" );+        s << getCharStyle ( SL_COMMENT, docStyle.getSingleLineCommentStyle(),+                            "HL SL Comment" );+        s << getCharStyle ( ML_COMMENT, docStyle.getCommentStyle(),+                            "HL ML Comment" );+        s << getCharStyle ( ESC_CHAR, docStyle.getEscapeCharStyle(),+                            "HL Escape Character" );+        s << getCharStyle ( DIRECTIVE, docStyle.getPreProcessorStyle(),+                            "HL Directive" );+        s << getCharStyle ( DIRECTIVE_STRING, docStyle.getPreProcStringStyle(),+                            "HL Directive String" );+        s << getCharStyle ( LINENUMBER, docStyle.getLineStyle(), "HL Line" );+        s << getCharStyle ( SYMBOL, docStyle.getOperatorStyle(),+                            "HL Operator" );+        s << getCharStyle ( STRING_INTERPOLATION,+                            docStyle.getInterpolationStyle(),+                            "HL Interpolation" );++        s << getCharStyle ( SYNTAX_ERROR, docStyle.getErrorStyle(),+                            "HL Error" );+        s << getCharStyle ( SYNTAX_ERROR_MSG, docStyle.getErrorMessageStyle(),+                            "HL Warning" );++        char styleName[20];+        for ( unsigned int i=0; i<keywordClasses.size(); i++ ) {+            // maybe better simple numbering+            snprintf ( styleName, sizeof styleName - 1, "HL Keyword %c",+                       'A' + i );+            s << getCharStyle ( KEYWORD + i,+                                docStyle.getKeywordStyle ( keywordClasses[i] ),+                                string ( styleName ) );+        }+        s << "}}\n";+    }++    if (addPageColor) {+        long svVal =  docStyle.getBgColour().getRed() ++        docStyle.getBgColour().getGreen() * 256++        docStyle.getBgColour().getBlue() * 256 * 256;++        s << R"(\viewbksp1\ilfomacatclnup0{\*\background{\shp{{\*\shpinst)"+             R"(\shpleft0\shptop0\shpright0\shpbottom0\shpfhdr0\shpbxmargin)"+             R"(\shpbymargin\shpwr0\shpwrk0\shpfblwtxt1\shpz0\shplid1025)"+             R"({\sp{\sn shapeType}{\sv 1}}{\sp{\sn fillColor}{\sv )"+          << svVal+          << "}}{\\sp{\\sn fFilled}{\\sv 1}}{\\sp{\\sn lineWidth}{\\sv 0}}"+             "{\\sp{\\sn fLine}{\\sv 0}}{\\sp{\\sn bWMode}{\\sv 9}}"+             "{\\sp{\\sn fBackground}{\\sv 1}}}}}}\n";+    }++    s << "\\paperw" << psMap[pageSize].width+      << "\\paperh" << psMap[pageSize].height+      << R"(\margl1134\margr1134\margt1134\margb1134\sectd)" // page margins+      << R"(\plain\f1\fs)";  // Font formatting+    int fontSize=0;+    StringTools::str2num<int> ( fontSize, this->getBaseFontSize(), std::dec );+    s << ( ( fontSize ) ? fontSize*2: 20 );  // RTF needs double amount+    return s.str(); }  string RtfGenerator::getAttributes ( const ElementStyle & col )@@ -124,132 +251,48 @@ string RtfGenerator::getCharStyle ( int styleNumber,const ElementStyle &elem,  void RtfGenerator::printBody() {-    isUtf8 = StringTools::change_case ( encoding ) == "utf-8";--    *out << R"({\rtf1\ansi \deff1)" // drop \\uc0 because of unicode output-         << R"({\fonttbl{\f1\fmodern\fprq1\fcharset0 )" ;-    *out << this->getBaseFont() ;-    *out << ";}}"-         << "{\\colortbl;";--    *out << "\\red"    << ( docStyle.getBgColour().getRed ( RTF ) );-    *out << "\\green"    << ( docStyle.getBgColour().getGreen ( RTF ) );-    *out << "\\blue"    << ( docStyle.getBgColour().getBlue ( RTF ) );-    *out << ";";--    *out << getAttributes ( docStyle.getDefaultStyle() );--    *out << getAttributes ( docStyle.getStringStyle() );-    *out << getAttributes ( docStyle.getNumberStyle() );-    *out << getAttributes ( docStyle.getSingleLineCommentStyle() );--    *out << getAttributes ( docStyle.getCommentStyle() );-    *out << getAttributes ( docStyle.getEscapeCharStyle() );-    *out << getAttributes ( docStyle.getPreProcessorStyle() );--    *out << getAttributes ( docStyle.getPreProcStringStyle() );-    *out << getAttributes ( docStyle.getLineStyle() );-    *out << getAttributes ( docStyle.getOperatorStyle() );-    *out << getAttributes ( docStyle.getInterpolationStyle() );--    *out << getAttributes ( docStyle.getErrorStyle() );-    *out << getAttributes ( docStyle.getErrorMessageStyle() );--    /* For output formats which can refer to external styles it is more safe-       to use the colour theme's keyword class names, since the language-       definitions (which may change during a batch conversion) do not have to define-       all keyword classes, that are needed to highlight all input files correctly.-       It is ok for RTF to use the language definition's class names, because RTF-       does not refer to external styles.-       We cannot use the theme's class names, because KSIterator returns an-       alphabetically ordered list, which is not good because RTF is dependent-       on the order. We access the keyword style with an ID, which is calculated-       ignoring the alphabetic order.-    */--    ///FIXME: nested syntax may be highlighted incorrectly if it contains more-    //        keyword definitions than the hosting syntax.-    //        Workaround: Add keyword group to hosting syntax (see html.lang)-    vector<string>  keywordClasses = currentSyntax->getKeywordClasses();--    for ( unsigned int i=0; i<keywordClasses.size(); i++ ) {-        *out << getAttributes ( docStyle.getKeywordStyle ( keywordClasses[i] ) );-    }--    *out << "}\n";--    if ( addCharStyles ) {-        *out << "{\\stylesheet{\n";-        *out << getCharStyle ( STANDARD, docStyle.getDefaultStyle(), "HL Default" );-        *out << getCharStyle ( STRING, docStyle.getStringStyle(), "HL String" );-        *out << getCharStyle ( NUMBER, docStyle.getNumberStyle(), "HL Number" );-        *out << getCharStyle ( SL_COMMENT, docStyle.getSingleLineCommentStyle(), "HL SL Comment" );-        *out << getCharStyle ( ML_COMMENT, docStyle.getCommentStyle(), "HL ML Comment" );-        *out << getCharStyle ( ESC_CHAR, docStyle.getEscapeCharStyle(), "HL Escape Character" );-        *out << getCharStyle ( DIRECTIVE, docStyle.getPreProcessorStyle(), "HL Directive" );-        *out << getCharStyle ( DIRECTIVE_STRING, docStyle.getPreProcStringStyle(), "HL Directive String" );-        *out << getCharStyle ( LINENUMBER, docStyle.getLineStyle(), "HL Line" );-        *out << getCharStyle ( SYMBOL, docStyle.getOperatorStyle(), "HL Operator" );-        *out << getCharStyle ( STRING_INTERPOLATION, docStyle.getInterpolationStyle(), "HL Interpolation" );--        *out << getCharStyle ( SYNTAX_ERROR, docStyle.getErrorStyle(), "HL Error" );-        *out << getCharStyle ( SYNTAX_ERROR_MSG, docStyle.getErrorMessageStyle(), "HL Warning" );--        char styleName[20];-        for ( unsigned int i=0; i<keywordClasses.size(); i++ ) {-            snprintf ( styleName, sizeof styleName - 1, "HL Keyword %c", 'A'+i ); //maybe better simple numbering-            *out << getCharStyle ( KEYWORD+i, docStyle.getKeywordStyle ( keywordClasses[i] ), string ( styleName ) );-        }-        *out << "}}\n";-    }--    if (addPageColor) {-        long svVal =  docStyle.getBgColour().getRed() +-                      docStyle.getBgColour().getGreen() * 256+-                      docStyle.getBgColour().getBlue() * 256 * 256;--        *out<<R"(\viewbksp1\ilfomacatclnup0{\*\background{\shp{{\*\shpinst\shpleft0\shptop0\shpright0\shpbottom0\shpfhdr0\shpbxmargin\shpbymargin\shpwr0\shpwrk0\shpfblwtxt1\shpz0\shplid1025{\sp{\sn shapeType}{\sv 1}}{\sp{\sn fillColor}{\sv )"<<svVal<<"}}{\\sp{\\sn fFilled}{\\sv 1}}{\\sp{\\sn lineWidth}{\\sv 0}}{\\sp{\\sn fLine}{\\sv 0}}{\\sp{\\sn bWMode}{\\sv 9}}{\\sp{\\sn fBackground}{\\sv 1}}}}}}\n";-    }--    *out  << "\\paperw"<< psMap[pageSize].width <<"\\paperh"<< psMap[pageSize].height-          << R"(\margl1134\margr1134\margt1134\margb1134\sectd)" // page margins-          << R"(\plain\f1\fs)" ;  // Font formatting-    int fontSize=0;-    StringTools::str2num<int> ( fontSize, this->getBaseFontSize(), std::dec );-    *out << ( ( fontSize ) ? fontSize*2: 20 );  // RTF needs double amount     *out << "\n\\pard \\cbpat1{";      processRootState(); -    *out << "}}"<<endl;+    *out << "}"<<endl; }  string RtfGenerator::getFooter() {-    return string();+    return "}"; // close the \rtf1 block } -void RtfGenerator::initOutputTags ( )+void RtfGenerator::initOutputTags() {     openTags.push_back ( getOpenTag ( STANDARD, docStyle.getDefaultStyle() ) );     openTags.push_back ( getOpenTag ( STRING, docStyle.getStringStyle() ) );     openTags.push_back ( getOpenTag ( NUMBER, docStyle.getNumberStyle() ) );-    openTags.push_back ( getOpenTag ( SL_COMMENT, docStyle.getSingleLineCommentStyle() ) );-    openTags.push_back ( getOpenTag ( ML_COMMENT,docStyle.getCommentStyle() ) );-    openTags.push_back ( getOpenTag ( ESC_CHAR, docStyle.getEscapeCharStyle() ) );-    openTags.push_back ( getOpenTag ( DIRECTIVE, docStyle.getPreProcessorStyle() ) );-    openTags.push_back ( getOpenTag ( DIRECTIVE_STRING, docStyle.getPreProcStringStyle() ) );+    openTags.push_back ( getOpenTag ( SL_COMMENT,+                                      docStyle.getSingleLineCommentStyle() ) );+    openTags.push_back ( getOpenTag ( ML_COMMENT,+                                      docStyle.getCommentStyle() ) );+    openTags.push_back ( getOpenTag ( ESC_CHAR,+                                      docStyle.getEscapeCharStyle() ) );+    openTags.push_back ( getOpenTag ( DIRECTIVE,+                                      docStyle.getPreProcessorStyle() ) );+    openTags.push_back ( getOpenTag ( DIRECTIVE_STRING,+                                      docStyle.getPreProcStringStyle() ) );     openTags.push_back ( getOpenTag ( LINENUMBER, docStyle.getLineStyle() ) );     openTags.push_back ( getOpenTag ( SYMBOL, docStyle.getOperatorStyle() ) );-    openTags.push_back ( getOpenTag ( STRING_INTERPOLATION, docStyle.getInterpolationStyle()) );+    openTags.push_back ( getOpenTag ( STRING_INTERPOLATION,+                                      docStyle.getInterpolationStyle() ) ); -    openTags.push_back ( getOpenTag ( SYNTAX_ERROR, docStyle.getErrorStyle() ) );-    openTags.push_back ( getOpenTag ( SYNTAX_ERROR_MSG, docStyle.getErrorMessageStyle()) );+    openTags.push_back ( getOpenTag ( SYNTAX_ERROR,+                                      docStyle.getErrorStyle() ) );+    openTags.push_back ( getOpenTag ( SYNTAX_ERROR_MSG,+                                      docStyle.getErrorMessageStyle() ) );      closeTags.push_back ( getCloseTag ( docStyle.getDefaultStyle() ) );     closeTags.push_back ( getCloseTag ( docStyle.getStringStyle() ) );     closeTags.push_back ( getCloseTag ( docStyle.getNumberStyle() ) );-    closeTags.push_back ( getCloseTag ( docStyle.getSingleLineCommentStyle() ) );+    closeTags.push_back (+        getCloseTag ( docStyle.getSingleLineCommentStyle() ) );     closeTags.push_back ( getCloseTag ( docStyle.getCommentStyle() ) );     closeTags.push_back ( getCloseTag ( docStyle.getEscapeCharStyle() ) );     closeTags.push_back ( getCloseTag ( docStyle.getPreProcessorStyle() ) );@@ -258,15 +301,16 @@ void RtfGenerator::initOutputTags ( )     closeTags.push_back ( getCloseTag ( docStyle.getOperatorStyle() ) );     closeTags.push_back ( getCloseTag ( docStyle.getInterpolationStyle() ) ); -    closeTags.push_back ( getCloseTag ( docStyle.getErrorStyle()) );-    closeTags.push_back ( getCloseTag ( docStyle.getErrorMessageStyle()) );+    closeTags.push_back ( getCloseTag ( docStyle.getErrorStyle() ) );+    closeTags.push_back ( getCloseTag ( docStyle.getErrorMessageStyle() ) ); }  string RtfGenerator::maskCharacter ( unsigned char c ) {     if (isUtf8 && c > 0x7f  && utf8SeqLen==0) { -        //http://stackoverflow.com/questions/7153935/how-to-convert-utf-8-stdstring-to-utf-16-stdwstring+        // http://stackoverflow.com/questions/7153935/+        // how-to-convert-utf-8-stdstring-to-utf-16-stdwstring          if (c <= 0xDF) {             utf16Char = c&0x1F;@@ -294,7 +338,8 @@ string RtfGenerator::maskCharacter ( unsigned char c )                 unsigned long cp = utf16Char - 0x10000;                 int high = 0xD800 + (cp >> 10);                 int low = 0xDC00 + (cp & 0x3FF);-                m = "\\u" + to_string ( ( short ) high ) + "?\\u" + to_string ( ( short ) low ) + "?";+                m = "\\u" + to_string ( ( short ) high ) + "?" ++                    "\\u" + to_string ( ( short ) low ) + "?";             } else {                 m = "\\u" + to_string ( ( short ) utf16Char ) + "?";             }@@ -411,13 +456,15 @@ string RtfGenerator::maskCharacter ( unsigned char c )  string RtfGenerator::getKeywordOpenTag ( unsigned int styleID ) {-    return getOpenTag ( KEYWORD+styleID,-                        docStyle.getKeywordStyle ( currentSyntax->getKeywordClasses() [styleID] ) );+    return getOpenTag ( KEYWORD + styleID,+                        docStyle.getKeywordStyle (+                            currentSyntax->getKeywordClasses() [styleID] ) ); }  string RtfGenerator::getKeywordCloseTag ( unsigned int styleID ) {-    return getCloseTag ( docStyle.getKeywordStyle ( currentSyntax->getKeywordClasses() [styleID] ) );+    return getCloseTag ( docStyle.getKeywordStyle (+        currentSyntax->getKeywordClasses() [styleID] ) ); }  void RtfGenerator::setRTFPageSize ( const string & ps )

src/core/stringtools.cpp

@@ -131,6 +131,71 @@ bool endsWith(std::string const & value, std::string const & ending)     return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); } +static void appendUtf8(string& out, unsigned long cp)+{+    if (cp < 0x80) {+        out += (char) cp;+    } else if (cp < 0x800) {+        out += (char) (0xC0 | (cp >> 6));+        out += (char) (0x80 | (cp & 0x3F));+    } else if (cp < 0x10000) {+        out += (char) (0xE0 | (cp >> 12));+        out += (char) (0x80 | ((cp >> 6) & 0x3F));+        out += (char) (0x80 | (cp & 0x3F));+    } else {+        out += (char) (0xF0 | (cp >> 18));+        out += (char) (0x80 | ((cp >> 12) & 0x3F));+        out += (char) (0x80 | ((cp >> 6) & 0x3F));+        out += (char) (0x80 | (cp & 0x3F));+    }+}++string utfWideToUtf8(const string& bytes, unsigned int unitSize, bool bigEndian)+{+    const unsigned long replacement = 0xFFFD;+    string result;+    result.reserve(bytes.size());++    auto readUnit = [&](size_t pos) {+        unsigned long unit = 0;+        for (unsigned int i=0; i<unitSize; i++) {+            unsigned char b = (unsigned char) bytes[pos + (bigEndian ? i : unitSize-1-i)];+            unit = (unit << 8) | b;+        }+        return unit;+    };++    size_t pos = 0;+    while (pos + unitSize <= bytes.size()) {+        unsigned long cp = readUnit(pos);+        pos += unitSize;++        if (unitSize == 2 && cp >= 0xD800 && cp <= 0xDBFF) {+            // high surrogate, needs a following low surrogate+            if (pos + 2 <= bytes.size()) {+                unsigned long low = readUnit(pos);+                if (low >= 0xDC00 && low <= 0xDFFF) {+                    cp = 0x10000 + ((cp - 0xD800) << 10) + (low - 0xDC00);+                    pos += 2;+                } else {+                    cp = replacement;+                }+            } else {+                cp = replacement;+            }+        } else if ((cp >= 0xD800 && cp <= 0xDFFF) || cp > 0x10FFFF) {+            cp = replacement;+        }+        appendUtf8(result, cp);+    }++    // truncated trailing code unit+    if (pos < bytes.size())+        appendUtf8(result, replacement);++    return result;+}+ int utf8_strlen(const string& str) {     int c,i,ix,q;@@ -146,4 +211,13 @@ int utf8_strlen(const string& str)     return q; } +std::string sanitizeForTerminal(std::string_view s)+{+    string out;+    out.reserve(s.size());+    for (unsigned char c : s)+        out += (c < 0x20 && c != '\t') ? '?' : static_cast<char>(c);+    return out;+}+ }

src/core/svggenerator.cpp

@@ -67,6 +67,9 @@ void SVGGenerator::initOutputTags()      closeTags.assign ( NUMBER_BUILTIN_STATES, "</tspan>" );     closeTags[0] = "";++    guideTagOpen = getOpenTag ( STY_NAME_GUI );+    guideTagClose = "</tspan>"; }  string SVGGenerator::getStyleDefinition()@@ -99,6 +102,9 @@ string SVGGenerator::getStyleDefinition()             os << getAttributes ( tspan+STY_NAME_ERM, docStyle.getErrorMessageStyle() );            os << getAttributes ( tspan+STY_NAME_ERR, docStyle.getErrorStyle() );+           if ( showIndentGuides ) {+               os << getAttributes ( tspan+STY_NAME_GUI, docStyle.getIndentGuideStyle() );+           }          for ( const auto &[first, second] : docStyle.getKeywordStyles() ) {             os << getAttributes ( tspan+first, second );

src/core/texgenerator.cpp

@@ -73,6 +73,9 @@ void TexGenerator::initOutputTags()     };      closeTags.assign ( NUMBER_BUILTIN_STATES, "}" );++    guideTagOpen = "{\\hl" + STY_NAME_GUI + " ";+    guideTagClose = "}"; }  string TexGenerator::getAttributes ( const string & elemName,const ElementStyle & elem )@@ -262,6 +265,9 @@ string TexGenerator::getStyleDefinition()          os << getAttributes ( STY_NAME_ERR, docStyle.getErrorStyle() );         os << getAttributes ( STY_NAME_ERM, docStyle.getErrorMessageStyle() );+        if ( showIndentGuides ) {+            os << getAttributes ( STY_NAME_GUI, docStyle.getIndentGuideStyle() );+        }          for ( const auto &[first, second] : docStyle.getKeywordStyles() ) {             os << getAttributes ( first, second );

src/core/themereader.cpp

@@ -30,6 +30,7 @@ along with Highlight.  If not, see <http://www.gnu.org/licenses/>. #include <sstream> #include <iostream> #include <cmath>+#include <iomanip>  #include <string_view> @@ -68,6 +69,16 @@ OutputType ThemeReader::getOutputType(string_view typeDesc) {     return HTML; } +static Colour blend(const Colour& fg, const Colour& bg, double f)+{+    std::ostringstream os;+    os << '#' << std::hex << std::setfill('0');+    os << std::setw(2) << (int)(fg.getRed()   * f + bg.getRed()   * (1-f));+    os << std::setw(2) << (int)(fg.getGreen() * f + bg.getGreen() * (1-f));+    os << std::setw(2) << (int)(fg.getBlue()  * f + bg.getBlue()  * (1-f));+    return Colour(os.str());+}+ void ThemeReader::initStyle(ElementStyle& style, const Diluculum::LuaVariable& var) { @@ -91,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();@@ -112,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)@@ -216,6 +234,12 @@ bool ThemeReader::load ( const string &styleDefinitionPath , OutputType type, bo             initStyle(errors, ls["Error"]);         } +        // faint by construction: a quarter step from the canvas towards the text colour+        indentGuide.setColour(blend(defaultElem.getColour(), canvas.getColour(), 0.25));+        if (ls["IndentGuide"].value() !=Diluculum::Nil){+            initStyle(indentGuide, ls["IndentGuide"]);+        }+         keywordStyles.clear();         semanticStyleMap.clear(); @@ -361,6 +385,11 @@ ElementStyle ThemeReader::getErrorMessageStyle() const     return errorMessages; } +ElementStyle ThemeReader::getIndentGuideStyle() const+{+    return indentGuide;+}+ bool ThemeReader::found () const {     return fileOK;

src/core/xterm256generator.cpp

@@ -64,7 +64,14 @@ string Xterm256Generator::getFooter()  string Xterm256Generator::maskCharacter ( unsigned char c ) {-    return string ( 1, c );+    switch ( c ) {+        case 0x1b :+            return "";+        case 0x07 :+            return "";+        default:+            return string ( 1, c );+    } }  void Xterm256Generator::initOutputTags ( )@@ -107,6 +114,9 @@ void Xterm256Generator::initOutputTags ( )     };      closeTags.assign ( NUMBER_BUILTIN_STATES, "\033[m" );++    guideTagOpen = getOpenTag ( docStyle.getIndentGuideStyle() );+    guideTagClose = "\033[m"; }  string  Xterm256Generator::getOpenTag ( const ElementStyle &col )

src/gui-qt/highlight.pro

@@ -13,13 +13,19 @@ SOURCES += main.cpp \     mainwindow.cpp \     io_report.cpp \     showtextfile.cpp \-    syntax_chooser.cpp+    syntax_chooser.cpp \+    syntaxpalette.cpp \+    thememodel.cpp \+    themeswatchdelegate.cpp  HEADERS += mainwindow.h \     precomp.h \     io_report.h \     showtextfile.h \-    syntax_chooser.h+    syntax_chooser.h \+    syntaxpalette.h \+    thememodel.h \+    themeswatchdelegate.h  FORMS += mainwindow.ui \     io_report.ui \

src/gui-qt/highlight_zh_CN.ts

@@ -1,1762 +1,1685 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS>-<TS version="2.1" language="zh_CN">-<context>-    <name>@default</name>-    <message>-        <source>Initialization error</source>-        <translation type="obsolete">初始化错误</translation>-    </message>-    <message>-        <source>Could not find syntax definitions. Check installation.</source>-        <translation type="obsolete">找不到语法定义文件.请检查安装.</translation>-    </message>-    <message>-        <source>Select one or more files to open</source>-        <translation type="obsolete">选择一个或多个文件打开</translation>-    </message>-    <message>-        <source>Select destination directory</source>-        <translation type="obsolete">选择目标路径</translation>-    </message>-    <message>-        <source>Tags file error</source>-        <translation type="obsolete">Tags文件错误</translation>-    </message>-    <message>-        <source>Could not read tags information in &quot;%1&quot;</source>-        <translation type="obsolete">无法读取 &quot;%1&quot; 的Tag信息</translation>-    </message>-    <message>-        <source>Output error</source>-        <translation type="obsolete">输出错误</translation>-    </message>-    <message>-        <source>Output directory does not exist!</source>-        <translation type="obsolete">输出目录错误!</translation>-    </message>-    <message>-        <source>You must define a style output file!</source>-        <translation type="obsolete">你必须等译一个style输出文件!</translation>-    </message>-    <message>-        <source>Language definition error</source>-        <translation type="obsolete">语言定义错误</translation>-    </message>-    <message>-        <source>Invalid regular expression in %1:-%2</source>-        <translation type="obsolete">错误的正则表达式 %1:-%2</translation>-    </message>-    <message>-        <source>Unknown syntax</source>-        <translation type="obsolete">未知的语法定义</translation>-    </message>-    <message>-        <source>Could not convert %1</source>-        <translation type="obsolete">%1转换失败</translation>-    </message>-    <message>-        <source>Converted %1 files in %2 ms</source>-        <translation type="obsolete">文件%1 转换完毕,用时 %2 ms</translation>-    </message>-    <message>-        <source>Conversion of &quot;%1&quot; not possible.</source>-        <translation type="obsolete">%1 转换不可用.</translation>-    </message>-    <message>-        <source>clipboard data</source>-        <translation type="obsolete">剪贴板数据</translation>-    </message>-    <message>-        <source>%1 options</source>-        <translation type="obsolete">%1 选项</translation>-    </message>-    <message>-        <source>Preview (%1):</source>-        <translation type="obsolete">预览 (%1):</translation>-    </message>-    <message>-        <source>Current syntax: %1</source>-        <translation type="obsolete">当前语言: %1</translation>-    </message>-    <message>-        <source>Preview of &quot;%1&quot; not possible.</source>-        <translation type="obsolete">&quot;%1&quot;.的预览不可用.</translation>-    </message>-    <message>-        <source>Choose a ctags file</source>-        <translation type="obsolete">选择一个ctags文件</translation>-    </message>-    <message>-        <source>Choose a style include file</source>-        <translation type="obsolete">选择一个style文件</translation>-    </message>-    <message>-        <source>About providing translations</source>-        <translation type="obsolete">关于提供翻译文件</translation>-    </message>-    <message>-        <source>The GUI was developed using the Qt toolkit, and translations may be provided using the tools Qt Linguist and lrelease.-The highlight.ts file for Linguist resides in the src/gui-qt subdirectory.-The qm file generated by lrelease has to be saved in gui-files/l10n.--Please send a note to as (at) andre-simon (dot) de if you have issues during translating or if you have finished or updated a translation.</source>-        <translation type="obsolete">这个GUI界面程序使用Qt开发,翻译可以通过Qt开发工具中的Qt Linguist和lrelease.-用于翻译的highlight.ts文件保存在src/gui-qt子目录中.-通过lrelease生成的qm文件需要保存在gui-files/l10n目录下.-如果你在翻译过程中遇到了问题,或者你弯沉或者更新了翻译-请通过as (at) andre-simon (dot) de联系我.</translation>-    </message>-    <message>-        <source>Select one or more plug-ins</source>-        <translation type="obsolete">选择一个或多个插件</translation>-    </message>-    <message>-        <source>Choose a plug-in input file</source>-        <translation type="obsolete">选择插件输入目录</translation>-    </message>-</context>+<TS version="2.1" language="zh_CN" sourcelanguage="en_US"> <context>     <name>MainWindow</name>     <message>         <source>Themes or indent schemes not found. Check installation.</source>-        <translation type="obsolete">Temas o esquemas de indentación no encontrados-Revise su instalación.</translation>+        <translation type="obsolete">未找到主题或缩进方案。+请检查安装。</translation>     </message>     <message>-        <location filename="mainwindow.cpp" line="+143"/>-        <location line="+15"/>-        <location line="+16"/>+        <location filename="mainwindow.cpp" line="143"/>+        <location filename="mainwindow.cpp" line="158"/>+        <location filename="mainwindow.cpp" line="174"/>         <source>Initialization error</source>-        <translation type="unfinished">初始化错误</translation>+        <translation>初始化错误</translation>     </message>     <message>-        <location line="-30"/>+        <location filename="mainwindow.cpp" line="144"/>         <source>Could not read a colour theme: </source>-        <translation type="unfinished"></translation>+        <translation>无法读取颜色主题:</translation>     </message>     <message>-        <location line="+4"/>+        <location filename="mainwindow.cpp" line="148"/>         <source>light</source>-        <translation type="unfinished"></translation>+        <translation>浅色</translation>     </message>     <message>-        <location line="+1"/>+        <location filename="mainwindow.cpp" line="149"/>         <source>dark</source>-        <translation type="unfinished"></translation>+        <translation>深色</translation>     </message>     <message>-        <location line="+1"/>+        <location filename="mainwindow.cpp" line="150"/>         <source>B16 light</source>-        <translation type="unfinished"></translation>+        <translation>B16 浅色</translation>     </message>     <message>-        <location line="+1"/>+        <location filename="mainwindow.cpp" line="151"/>         <source>B16 dark</source>-        <translation type="unfinished"></translation>+        <translation>B16 深色</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.cpp" line="154"/>         <source>Please select a Server</source>-        <translation type="unfinished"></translation>+        <translation>请选择一个服务器</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.cpp" line="159"/>         <source>Could not find LSP profiles. Check installation.</source>-        <translation type="unfinished"></translation>+        <translation>无法找到 LSP 配置文件。请检查安装。</translation>     </message>     <message>-        <location line="+16"/>+        <location filename="mainwindow.cpp" line="175"/>         <source>Could not find syntax definitions. Check installation.</source>-        <translation type="unfinished">找不到语法定义文件.请检查安装.</translation>+        <translation>未找到语法定义文件。+请检查安装。</translation>     </message>     <message>-        <location line="+121"/>+        <location filename="mainwindow.cpp" line="296"/>         <source>NTFS Short Names</source>-        <translation type="unfinished"></translation>+        <translation>NTFS 短名称</translation>     </message>     <message>-        <location line="+0"/>+        <location filename="mainwindow.cpp" line="296"/>         <source>NTFS short names may be disabled on your volumes. Highlight can not read input with multibyte file names if no short name is available. This information will no longer bother you.</source>-        <translation type="unfinished"></translation>+        <translation>你的磁盘分区可能禁用了 NTFS 短名称。如果没有短名称,Highlight 无法读取多字节文件名。此提示将不再显示。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.cpp" line="299"/>         <source>Always at your service</source>-        <translation type="unfinished"></translation>+        <translation>随时为你服务</translation>     </message>     <message>-        <location line="+44"/>+        <location filename="mainwindow.cpp" line="343"/>         <source>Select one or more files to open</source>-        <translation type="unfinished">选择一个或多个文件打开</translation>+        <translation>选择一个或多个文件打开</translation>     </message>     <message>-        <location line="+36"/>+        <location filename="mainwindow.cpp" line="379"/>         <source>Select destination directory</source>-        <translation type="unfinished">选择目标路径</translation>+        <translation>选择目标目录</translation>     </message>     <message>         <source>Tags file error</source>-        <translation type="obsolete">Tags文件错误</translation>+        <translation type="obsolete">标签文件错误</translation>     </message>     <message>         <source>Could not read tags information in &quot;%1&quot;</source>-        <translation type="obsolete">无法读取 &quot;%1&quot; 的Tag信息</translation>+        <translation type="obsolete">无法读取 &quot;%1&quot; 中的标签信息</translation>     </message>     <message>-        <location line="+718"/>-        <location line="+31"/>+        <location filename="mainwindow.cpp" line="1097"/>+        <location filename="mainwindow.cpp" line="1128"/>         <source>Output error</source>-        <translation type="unfinished">输出错误</translation>+        <translation>输出错误</translation>     </message>     <message>-        <location line="-31"/>+        <location filename="mainwindow.cpp" line="1097"/>         <source>Output directory does not exist!</source>-        <translation type="unfinished">输出目录错误!</translation>+        <translation>输出目录不存在!</translation>     </message>     <message>-        <location line="+31"/>+        <location filename="mainwindow.cpp" line="1128"/>         <source>You must define a style output file!</source>-        <translation type="unfinished">你必须等译一个style输出文件!</translation>+        <translation>你必须指定一个样式输出文件!</translation>     </message>     <message>-        <location line="+52"/>+        <location filename="mainwindow.cpp" line="1180"/>         <source>Processing %1 (%2/%3)</source>-        <translation type="unfinished"></translation>+        <translation>正在处理 %1(%2/%3)</translation>     </message>     <message>-        <location line="+10"/>+        <location filename="mainwindow.cpp" line="1190"/>         <source>Language definition error</source>-        <translation type="unfinished">语言定义错误</translation>+        <translation>语言定义错误</translation>     </message>     <message>-        <location line="+1"/>+        <location filename="mainwindow.cpp" line="1191"/>         <source>Invalid regular expression in %1: %2</source>-        <translation type="unfinished">错误的正则表达式 %1:+        <translation>在 %1 中存在无效的正则表达式: %2</translation>     </message>     <message>-        <location line="+4"/>+        <location filename="mainwindow.cpp" line="1195"/>         <source>Unknown syntax</source>-        <translation type="unfinished">未知的语法定义</translation>+        <translation>未知语法</translation>     </message>     <message>-        <location line="+0"/>+        <location filename="mainwindow.cpp" line="1195"/>         <source>Could not convert %1</source>-        <translation type="unfinished">%1转换失败</translation>+        <translation>无法转换 %1</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.cpp" line="1198"/>         <source>Lua error</source>-        <translation type="unfinished"></translation>+        <translation>Lua 错误</translation>     </message>     <message>-        <location line="+0"/>+        <location filename="mainwindow.cpp" line="1198"/>         <source>Could not convert %1: Lua Syntax error: %2</source>-        <translation type="unfinished"></translation>+        <translation>无法转换 %1:+Lua 语法错误:%2</translation>     </message>     <message>-        <location line="+175"/>+        <location filename="mainwindow.cpp" line="1373"/>         <source>Converted %1 files in %2 ms</source>-        <translation type="unfinished">文件%1 转换完毕,用时 %2 ms</translation>+        <translation>已转换 %1 个文件,耗时 %2 毫秒</translation>     </message>     <message>-        <location line="+206"/>+        <location filename="mainwindow.cpp" line="1579"/>         <source>Conversion of &quot;%1&quot; not possible.</source>-        <translation type="unfinished">No es posible la conversión de &quot;%1&quot;.</translation>+        <translation>无法转换 &quot;%1&quot;。</translation>     </message>     <message>-        <location line="+0"/>-        <location line="+148"/>-        <location line="+55"/>+        <location filename="mainwindow.cpp" line="1579"/>+        <location filename="mainwindow.cpp" line="1727"/>+        <location filename="mainwindow.cpp" line="1782"/>         <source>clipboard data</source>-        <translation type="unfinished">剪贴板数据</translation>+        <translation>剪贴板数据</translation>     </message>     <message>-        <location line="-124"/>+        <location filename="mainwindow.cpp" line="1658"/>         <source>%1 options</source>-        <translation type="unfinished">%1 选项</translation>+        <translation>%1 选项</translation>     </message>     <message>-        <location line="+41"/>-        <location line="+11"/>+        <location filename="mainwindow.cpp" line="1699"/>+        <location filename="mainwindow.cpp" line="1710"/>         <source>(user script)</source>-        <translation type="unfinished"></translation>+        <translation>(用户脚本)</translation>     </message>     <message>-        <location line="+16"/>+        <location filename="mainwindow.cpp" line="1726"/>         <source>Preview (%1):</source>-        <translation type="unfinished">预览 (%1):</translation>+        <translation>预览(%1):</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.cpp" line="1729"/>         <source>Current syntax: %1 %2</source>-        <translation type="unfinished">当前语言: %1 %2</translation>+        <translation>当前语法:%1 %2</translation>     </message>     <message>-        <location line="+1"/>+        <location filename="mainwindow.cpp" line="1730"/>         <source>Current theme: %1 %2</source>-        <translation type="unfinished"></translation>+        <translation>当前主题:%1 %2</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.cpp" line="1733"/>         <source>Contrast: %1 %2</source>-        <translation type="unfinished"></translation>+        <translation>对比度:%1 %2</translation>     </message>     <message>-        <location line="+451"/>+        <location filename="mainwindow.cpp" line="2184"/>         <source>Language server initialization successful</source>-        <translation type="unfinished"></translation>+        <translation>语言服务器初始化成功</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.cpp" line="2189"/>         <source>Language server connection failed</source>-        <translation type="unfinished"></translation>+        <translation>语言服务器连接失败</translation>     </message>     <message>-        <location line="+2"/>+        <location filename="mainwindow.cpp" line="2191"/>         <source>Language server initialization failed</source>-        <translation type="unfinished"></translation>+        <translation>语言服务器初始化失败</translation>     </message>     <message>-        <location line="+28"/>+        <location filename="mainwindow.cpp" line="2219"/>         <source>Select workspace directory</source>-        <translation type="unfinished"></translation>+        <translation>选择工作区目录</translation>     </message>     <message>-        <location line="+4"/>+        <location filename="mainwindow.cpp" line="2223"/>         <source>Choose the Language Server executable</source>-        <translation type="unfinished"></translation>+        <translation>选择语言服务器可执行文件</translation>     </message>     <message>         <source>Current syntax: %1</source>-        <translation type="obsolete">当前语言: %1</translation>+        <translation type="vanished">当前语法:%1</translation>     </message>     <message>-        <location line="-441"/>+        <location filename="mainwindow.cpp" line="1782"/>         <source>Preview of &quot;%1&quot; not possible.</source>-        <translation type="unfinished">&quot;%1&quot;.的预览不可用.</translation>+        <translation>无法预览 &quot;%1&quot;。</translation>     </message>     <message>-        <location line="+246"/>+        <location filename="mainwindow.cpp" line="2028"/>         <source>Some plug-in effects may not be visible in the preview.</source>-        <translation type="unfinished"></translation>+        <translation>部分插件效果可能无法在预览中显示。</translation>     </message>     <message>         <source>Choose a ctags file</source>-        <translation type="obsolete">选择一个ctags文件</translation>+        <translation type="obsolete">选择一个 ctags 文件</translation>     </message>     <message>-        <location line="-202"/>-        <location line="+4"/>-        <location line="+4"/>-        <location line="+5"/>+        <location filename="mainwindow.cpp" line="1826"/>+        <location filename="mainwindow.cpp" line="1830"/>+        <location filename="mainwindow.cpp" line="1834"/>+        <location filename="mainwindow.cpp" line="1839"/>         <source>Choose a style include file</source>-        <translation type="unfinished">选择一个style文件</translation>+        <translation>选择一个样式包含文件</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.cpp" line="1844"/>         <source>About providing translations</source>-        <translation type="unfinished">关于提供翻译文件</translation>+        <translation>关于提供翻译</translation>     </message>     <message>-        <location line="+1"/>         <source>The GUI was developed using the Qt toolkit, and translations may be provided using the tools Qt Linguist and lrelease. The highlight.ts file for Linguist resides in the src/gui-qt subdirectory. The qm file generated by lrelease has to be saved in gui-files/l10n.  Please send a note to as (at) andre-simon (dot) de if you have issues during translating or if you have finished or updated a translation.</source>-        <translation type="unfinished">这个GUI界面程序使用Qt开发,翻译可以通过Qt开发工具中的Qt Linguist和lrelease.-用于翻译的highlight.ts文件保存在src/gui-qt子目录中.-通过lrelease生成的qm文件需要保存在gui-files/l10n目录下.-如果你在翻译过程中遇到了问题,或者你弯沉或者更新了翻译-请通过as (at) andre-simon (dot) de联系我.</translation>+        <translation type="unfinished">本图形界面使用 Qt 工具包开发,翻译可通过 Qt Linguist 工具制作。+Linguist 使用的 highlight.ts 文件位于 src/gui-qt 目录下。+lrelease 生成的 qm 文件需保存到 gui-files/l10n 目录。+如果你在翻译过程中遇到了问题,或者你更新了翻译+如果你在翻译过程中遇到问题,或已完成/更新了翻译,请发送邮件至:as@andre-simon.de。+此中文版本由 大眼仔~旭(Anan)翻译</translation>     </message>     <message>-        <location line="+58"/>+        <location filename="mainwindow.cpp" line="1903"/>         <source>Select one or more plug-ins</source>-        <translation type="unfinished">选择一个或多个插件</translation>+        <translation>选择一个或多个插件</translation>     </message>     <message>-        <location line="+11"/>+        <location filename="mainwindow.cpp" line="1914"/>         <source>Select one or more syntax or theme scripts</source>-        <translation type="unfinished"></translation>+        <translation>选择一个或多个语法或主题脚本</translation>     </message>     <message>-        <location line="+56"/>+        <location filename="mainwindow.cpp" line="1970"/>         <source>Choose a plug-in input file</source>-        <translation type="unfinished">选择插件输入目录</translation>+        <translation>选择插件输入文件</translation>     </message> </context> <context>     <name>MainWindowClass</name>     <message>-        <location filename="mainwindow.ui" line="+173"/>+        <location filename="mainwindow.ui" line="173"/>         <source>Choose the source code files you want to convert.</source>-        <translation>选择你想要转换的代码文件.</translation>+        <translation>选择你想要转换的源代码文件。</translation>     </message>     <message>-        <location line="+6"/>+        <location filename="mainwindow.ui" line="179"/>         <source>Choose input files</source>         <translation>选择输入文件</translation>     </message>     <message>-        <location line="+26"/>+        <location filename="mainwindow.ui" line="205"/>         <source>List of input files.</source>-        <translation>输入文件列表.</translation>+        <translation>输入文件列表。</translation>     </message>     <message>-        <location line="+24"/>+        <location filename="mainwindow.ui" line="229"/>         <source>Remove the selected input files.</source>-        <translation>移除选中的输入文件.</translation>+        <translation>移除选中的输入文件。</translation>     </message>     <message>-        <location line="+3"/>-        <location line="+343"/>-        <location line="+136"/>+        <location filename="mainwindow.ui" line="232"/>+        <location filename="mainwindow.ui" line="575"/>+        <location filename="mainwindow.ui" line="711"/>         <source>Clear selection</source>-        <translation>移除选中项</translation>+        <translation>清除选择</translation>     </message>     <message>-        <location line="-472"/>+        <location filename="mainwindow.ui" line="239"/>         <source>Remove all input files.</source>-        <translation>清除所有输入文件.</translation>+        <translation>移除所有输入文件。</translation>     </message>     <message>-        <location line="+3"/>-        <location line="+343"/>-        <location line="+136"/>+        <location filename="mainwindow.ui" line="242"/>+        <location filename="mainwindow.ui" line="585"/>+        <location filename="mainwindow.ui" line="721"/>         <source>Clear all</source>-        <translation>移除所有</translation>+        <translation>全部清除</translation>     </message>     <message>         <source>Output destination</source>-        <translation type="obsolete">Destino de salida</translation>+        <translation type="obsolete">输出目标</translation>     </message>     <message>-        <location line="-440"/>+        <location filename="mainwindow.ui" line="281"/>         <source>Output directory</source>         <translation>输出目录</translation>     </message>     <message>-        <location line="+19"/>+        <location filename="mainwindow.ui" line="300"/>         <source>Select the output directory.</source>-        <translation>选择输出路径.</translation>+        <translation>选择输出目录。</translation>     </message>     <message>-        <location line="+3"/>-        <location line="+359"/>-        <location line="+126"/>-        <location line="+82"/>-        <location line="+642"/>-        <location line="+269"/>-        <location line="+108"/>-        <location line="+295"/>+        <location filename="mainwindow.ui" line="303"/>+        <location filename="mainwindow.ui" line="662"/>+        <location filename="mainwindow.ui" line="788"/>+        <location filename="mainwindow.ui" line="870"/>+        <location filename="mainwindow.ui" line="1512"/>+        <location filename="mainwindow.ui" line="1781"/>+        <location filename="mainwindow.ui" line="1889"/>+        <location filename="mainwindow.ui" line="2184"/>         <source>...</source>         <translation>...</translation>     </message>     <message>-        <location line="-1846"/>+        <location filename="mainwindow.ui" line="338"/>         <source>Save output in the input file directories.</source>-        <translation>将输出保存在输入路径中.</translation>+        <translation>将输出保存到输入文件所在目录。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="341"/>         <source>Write to source directories</source>-        <translation>输出到源文件目录</translation>+        <translation>写入源目录</translation>     </message>     <message>         <source>Output options</source>-        <translation type="obsolete">Opciones de salida</translation>+        <translation type="obsolete">输出选项</translation>     </message>     <message>-        <location line="+626"/>+        <location filename="mainwindow.ui" line="967"/>         <source>General</source>-        <translation>通用</translation>+        <translation>常规</translation>     </message>     <message>-        <location line="+20"/>+        <location filename="mainwindow.ui" line="987"/>         <source>Output for&amp;mat:</source>-        <oldsource>Output format:</oldsource>-        <translation type="unfinished">输出格式:</translation>+        <translation>输出格式:</translation>     </message>     <message>-        <location line="+22"/>+        <location filename="mainwindow.ui" line="1009"/>         <source>Choose an output format.</source>-        <translation>选择一个输出格式.</translation>+        <translation>选择输出格式。</translation>     </message>     <message>-        <location line="+4"/>+        <location filename="mainwindow.ui" line="1013"/>         <source>HTML</source>-        <translation></translation>+        <translation>HTML</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1018"/>         <source>XHTML</source>-        <translation></translation>+        <translation>XHTML</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1023"/>         <source>LaTeX</source>-        <translation></translation>+        <translation>LaTeX</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1028"/>         <source>TeX</source>-        <translation></translation>+        <translation>TeX</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1033"/>         <source>RTF</source>-        <translation></translation>+        <translation>RTF</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1038"/>         <source>ODT</source>-        <translation type="unfinished"></translation>+        <translation>ODT</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1043"/>         <source>SVG</source>-        <translation></translation>+        <translation>SVG</translation>     </message>     <message>-        <location line="+39"/>+        <location filename="mainwindow.ui" line="1053"/>+        <source>ANSI ESC</source>+        <translation>ANSI ESC</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1058"/>+        <source>XTerm256 ESC</source>+        <translation>XTerm256 ESC</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1063"/>+        <source>Truecolor ESC</source>+        <translation>Truecolor ESC</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1082"/>         <source>Add line numbers to the output.</source>-        <translation>给输出添加代码行号.</translation>+        <translation>在输出中添加行号。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="1085"/>         <source>Add line numbers</source>         <translation>添加行号</translation>     </message>     <message>-        <location line="+39"/>+        <source>Set line numbering start</source>+        <translation type="vanished">设置行号起始值</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1124"/>         <source>Select the line number width.</source>-        <translation>选择行号宽度.</translation>+        <translation>选择行号宽度。</translation>     </message>     <message>-        <location line="+21"/>+        <location filename="mainwindow.ui" line="1145"/>         <source>Fill leading space of line numbers with zeroes.</source>-        <translation>行号用0补齐.</translation>+        <translation>用零填充行号前导空格。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="1148"/>         <source>Pad with zeroes</source>-        <translation>行号用0补齐</translation>+        <translation>补零</translation>     </message>     <message>-        <location line="+13"/>+        <location filename="mainwindow.ui" line="1161"/>         <source>Generate output without document header and footer.</source>-        <translation>去掉输出文件的头部和尾部声明部分,便于将其插入其他文档中.</translation>+        <translation>生成不含文档页眉和页脚的输出。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="1164"/>         <source>Omit header and footer</source>-        <translation>去掉文档的头部和尾部声明</translation>+        <translation>忽略页眉页脚</translation>     </message>     <message>-        <location line="+7"/>+        <location filename="mainwindow.ui" line="1171"/>         <source>Output any plug-in text injections even if document header and footer is omitted.</source>-        <translation type="unfinished"></translation>+        <translation>即使忽略页眉页脚,仍输出插件注入的文本。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="1174"/>         <source>Keep Plug-In injections</source>-        <translation type="unfinished"></translation>+        <translation>保留插件注入内容</translation>     </message>     <message>-        <location line="+7"/>+        <location filename="mainwindow.ui" line="1181"/>         <source>Test if input data is not binary. Removes Unicode BOM mark.</source>-        <translation>检测输入文件是否是二进制.-清除Unicode的BOM标记.</translation>+        <translation>检查输入数据是否为非二进制。+移除 Unicode BOM 标记。</translation>     </message>     <message>-        <location line="+4"/>+        <location filename="mainwindow.ui" line="1185"/>         <source>Validate input data</source>-        <translation>验证输入文件</translation>+        <translation>验证输入数据</translation>     </message>     <message>         <source>Set the output file ancoding.</source>-        <translation type="vanished">设置输出文件的编码格式.</translation>+        <translation type="vanished">设置输出文件编码。</translation>     </message>     <message>-        <location line="+1478"/>+        <location filename="mainwindow.ui" line="2022"/>+        <source>I&amp;mage width:</source>+        <translation>图像宽度(&amp;M):</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="2070"/>+        <source>Height:</source>+        <translation>高度:</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="2331"/>+        <source>Reformat and indent your code.+This feature is enabled for C, C++, C# and Java code.</source>+        <translation>重新格式化并缩进代码。+此功能支持 C、C++、C# 和 Java 代码。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="2663"/>         <source>&amp;Plug-Ins</source>-        <translation type="unfinished"></translation>+        <translation>插件(&amp;P)</translation>     </message>     <message>         <source>Encoding:</source>-        <translation type="obsolete">Codificación:</translation>+        <translation type="obsolete">编码:</translation>     </message>     <message>-        <location line="-1449"/>+        <location filename="mainwindow.ui" line="1214"/>         <source>Select or define the encoding. The result has to match the input file encoding.</source>-        <translation>选择或者定义编码格式.-结果必须和输出文件的编码格式相符合.</translation>+        <translation>选择或定义编码。+结果必须与输入文件编码一致。</translation>     </message>     <message>-        <location line="+11"/>+        <location filename="mainwindow.ui" line="1225"/>         <source>ISO-8859-1</source>-        <translation></translation>+        <translation>ISO-8859-1</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1230"/>         <source>ISO-8859-2</source>-        <translation></translation>+        <translation>ISO-8859-2</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1235"/>         <source>ISO-8859-3</source>-        <translation></translation>+        <translation>ISO-8859-3</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1240"/>         <source>ISO-8859-4</source>-        <translation></translation>+        <translation>ISO-8859-4</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1245"/>         <source>ISO-8859-5</source>-        <translation></translation>+        <translation>ISO-8859-5</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1250"/>         <source>ISO-8859-6</source>-        <translation></translation>+        <translation>ISO-8859-6</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1255"/>         <source>ISO-8859-7</source>-        <translation></translation>+        <translation>ISO-8859-7</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1260"/>         <source>ISO-8859-8</source>-        <translation></translation>+        <translation>ISO-8859-8</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1265"/>         <source>ISO-8859-9</source>-        <translation></translation>+        <translation>ISO-8859-9</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1270"/>         <source>ISO-8859-10</source>-        <translation></translation>+        <translation>ISO-8859-10</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1275"/>         <source>ISO-8859-11</source>-        <translation></translation>+        <translation>ISO-8859-11</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1280"/>         <source>ISO-8859-12</source>-        <translation></translation>+        <translation>ISO-8859-12</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1285"/>         <source>ISO-8859-13</source>-        <translation></translation>+        <translation>ISO-8859-13</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1290"/>         <source>ISO-8859-14</source>-        <translation></translation>+        <translation>ISO-8859-14</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1295"/>         <source>ISO-8859-15</source>-        <translation></translation>+        <translation>ISO-8859-15</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1300"/>         <source>UTF-8</source>-        <translation></translation>+        <translation>UTF-8</translation>     </message>     <message>-        <location line="+24"/>+        <location filename="mainwindow.ui" line="1324"/>         <source>Output specific</source>-        <translation>输出细节</translation>+        <translation>输出特定选项</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1557"/>+        <source>Add an anchor to each line.</source>+        <translation>为每一行添加锚点。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1621"/>+        <source>Add HTML MIME Type when copying code to the clipboard</source>+        <translation>复制代码到剪贴板时添加 HTML MIME 类型</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1624"/>+        <source>Copy with MIME type</source>+        <translation>带 MIME 类型复制</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1662"/>+        <source>Adapt output for the Babel package</source>+        <translation>为 Babel 宏包调整输出</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1672"/>+        <source>Adapt output for the Beamer package</source>+        <translation>为 Beamer 宏包调整输出</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1675"/>+        <source>Add Beamer compatibility</source>+        <translation>添加 Beamer 兼容性</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1926"/>+        <source>Set page color attribute to background color.</source>+        <translation>将页面颜色属性设置为背景色。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="2668"/>+        <source>&amp;File access trace (W32)</source>+        <translation>文件访问跟踪(&amp;F)(W32)</translation>     </message>     <message>         <source>HTML options</source>-        <translation type="obsolete">Opciones de HTML</translation>+        <translation type="obsolete">HTML 选项</translation>     </message>     <message>         <source>Style</source>-        <translation type="obsolete">Hoja de estilo</translation>+        <translation type="obsolete">样式</translation>     </message>     <message>-        <location line="+49"/>-        <location line="+326"/>-        <location line="+108"/>-        <location line="+295"/>+        <location filename="mainwindow.ui" line="1373"/>+        <location filename="mainwindow.ui" line="1699"/>+        <location filename="mainwindow.ui" line="1807"/>+        <location filename="mainwindow.ui" line="2102"/>         <source>Include the style information in each output file.</source>-        <translation>将样式表信息保存到每个输出文件中.</translation>+        <translation>在每个输出文件中包含样式信息。</translation>     </message>     <message>-        <location line="-726"/>-        <location line="+729"/>+        <location filename="mainwindow.ui" line="1376"/>+        <location filename="mainwindow.ui" line="2105"/>         <source>Embed style (CSS)</source>-        <translation>内嵌样式表 (CSS)</translation>+        <translation>嵌入样式(CSS)</translation>     </message>     <message>-        <location line="-716"/>+        <location filename="mainwindow.ui" line="1389"/>         <source>Add CSS information to each tag (do not use CSS class definitions).</source>-        <translation>CSS信息保存到每个Tag中(不使用CSS的类定义).</translation>+        <translation>为每个标签添加 CSS 信息(不使用 CSS 类定义)。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="1392"/>         <source>Inline CSS</source>-        <translation>Inline CSS</translation>+        <translation>内联 CSS</translation>     </message>     <message>         <source>Style file:</source>-        <translation type="obsolete">Archivo de estilo:</translation>-    </message>-    <message>-        <location line="+60"/>-        <location line="+383"/>-        <location line="+295"/>-        <source>Name of the referenced style file.</source>-        <translation>外链样式表文件的名字.</translation>+        <translation type="obsolete">样式文件:</translation>     </message>     <message>-        <location line="-675"/>-        <location line="+678"/>+        <location filename="mainwindow.ui" line="1455"/>+        <location filename="mainwindow.ui" line="2133"/>         <source>highlight.css</source>-        <translation></translation>+        <translation>highlight.css</translation>     </message>     <message>         <source>Style include file:</source>-        <translation type="obsolete">Archivo de estilo a incluir:</translation>+        <translation type="obsolete">样式包含文件:</translation>     </message>     <message>-        <location line="-637"/>-        <location line="+672"/>+        <location filename="mainwindow.ui" line="1496"/>+        <location filename="mainwindow.ui" line="2168"/>         <source>Path of the CSS include file.</source>-        <translation>外链样式表的路径.</translation>+        <translation>CSS 包含文件路径。</translation>     </message>     <message>-        <location line="-659"/>+        <location filename="mainwindow.ui" line="1509"/>         <source>Select a CSS include file.</source>-        <translation>选择一个外链的样式表.</translation>+        <translation>选择 CSS 包含文件。</translation>     </message>     <message>-        <location line="-103"/>+        <location filename="mainwindow.ui" line="1406"/>         <source>CSS class prefix:</source>-        <translation>CSS类前缀:</translation>+        <translation>CSS 类前缀:</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="736"/>+        <source>Shows description of a selected script.</source>+        <translation>显示选中脚本的描述。</translation>     </message>     <message>-        <location line="+13"/>+        <location filename="mainwindow.ui" line="1419"/>         <source>Add a CSS class name prefix to avoid namespace clashes.</source>-        <translation>给CSS类添加前缀以避免由于命名空间引起的冲突..</translation>+        <translation>添加 CSS 类名前缀以避免命名空间冲突。</translation>     </message>     <message>         <source>Tags and index files</source>-        <translation type="obsolete">Archivos de etiquetas e índice</translation>+        <translation type="obsolete">标签与索引文件</translation>     </message>     <message>-        <location line="+175"/>+        <location filename="mainwindow.ui" line="1594"/>         <source>Generate an index file with hyperlinks to all outputted files.</source>-        <translation>生成一个包含所有输出文件超链接的index文件.</translation>+        <translation>生成包含所有输出文件超链接的索引文件。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="1597"/>         <source>Generate index file</source>-        <translation>生成index文件</translation>+        <translation>生成索引文件</translation>     </message>     <message>         <source>Read a ctags file and add the included metainformation as tooltips. See ctags.sf.net for details.</source>-        <translatorcomment>This text will be emoved soon</translatorcomment>-        <translation type="obsolete">根据读取的一个ctags文件添加提示.-更多详情请访问 ctags.sf.net.</translation>+        <translation type="obsolete">读取 ctags 文件并将元信息作为提示添加。+详情请查看 ctags.sf.net。</translation>     </message>     <message>         <source>Ctags file:</source>-        <translation type="obsolete">Archivo de ctags:</translation>+        <translation type="obsolete">Ctags 文件:</translation>     </message>     <message>         <source>Path of the ctags file.</source>-        <translation type="obsolete">ctags文件路径..</translation>+        <translation type="obsolete">ctags 文件路径。</translation>     </message>     <message>         <source>Choose a ctags file.</source>-        <translation type="obsolete">选择一个ctags文件.</translation>+        <translation type="obsolete">选择 ctags 文件。</translation>     </message>     <message>-        <location line="-59"/>+        <location filename="mainwindow.ui" line="1538"/>         <source>Misc</source>         <translation>杂项</translation>     </message>     <message>         <source>Add an achor to each line.</source>-        <translation type="vanished">给每一行代码添加锚点..</translation>+        <translation type="vanished">为每一行添加锚点。</translation>     </message>     <message>-        <location line="+22"/>+        <location filename="mainwindow.ui" line="1560"/>         <source>Add line anchors</source>-        <translation>给每一行代码添加Anchor(锚点)</translation>+        <translation>添加行锚点</translation>     </message>     <message>-        <location line="+7"/>+        <location filename="mainwindow.ui" line="1567"/>         <source>Add the filename as prefix to the anchors.</source>-        <translation>将文件名作为Anchors(锚点)的前缀.</translation>+        <translation>将文件名作为前缀添加到锚点。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="1570"/>         <source>Include file name in anchor</source>-        <translation>将文件名包含在Anchor(锚点)中</translation>+        <translation>在锚点中包含文件名</translation>     </message>     <message>-        <location line="+7"/>+        <location filename="mainwindow.ui" line="1577"/>         <source>Output the lines within an ordered list.</source>-        <translation>根据列表顺序输出文档..</translation>+        <translation>以有序列表形式输出行。</translation>     </message>     <message>         <source>Ordered list</source>-        <translation type="obsolete">Lista ordenada</translation>+        <translation type="obsolete">有序列表</translation>     </message>     <message>-        <location line="+27"/>+        <location filename="mainwindow.ui" line="1604"/>         <source>Add &amp;lt;pre&amp;gt; tags to the output, if the flag &quot;No document header and footer&quot; is selected.</source>-        <translation>当选中“忽略文档的header和footer”时,给输出添加&lt;pre&gt;标签.</translation>+        <translation>如果勾选“无文档页眉页脚”,则在输出中添加 &amp;lt;pre&amp;gt; 标签。</translation>     </message>     <message>         <source>Enclose in &lt;pre&gt;</source>-        <translation type="obsolete">Meter entre &amp;lt;pre&amp;gt;</translation>+        <translation type="obsolete">包含在 &lt;pre&gt; 中</translation>     </message>     <message>         <source>LaTeX options</source>-        <translation type="obsolete">Opciones de LaTeX</translation>+        <translation type="obsolete">LaTeX 选项</translation>     </message>     <message>-        <location line="+48"/>+        <location filename="mainwindow.ui" line="1652"/>         <source>Replace quotes by dq sequences.</source>-        <translatorcomment>Replace apostrophes by dq strings</translatorcomment>-        <translation>用dq序列替换引号.</translation>+        <translation>将引号替换为 \dq 序列。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="1655"/>         <source>Escape quotes</source>-        <translatorcomment>Replace apostrophes</translatorcomment>-        <translation>替换引号</translation>+        <translation>转义引号</translation>     </message>     <message>         <source>Make output Babel compatible.</source>-        <translatorcomment>Make output work with Babel package</translatorcomment>-        <translation type="vanished">使输出与Babel宏包兼容.</translation>+        <translation type="vanished">使输出兼容 Babel。</translation>     </message>     <message>         <source>Babel compatibility</source>-        <translation type="obsolete">Compatibilidad con Babel</translation>+        <translation type="obsolete">Babel 兼容性</translation>     </message>     <message>-        <location line="+27"/>+        <location filename="mainwindow.ui" line="1682"/>         <source>Replace default symbols (brackets, tilde) by nice redefinitions.</source>-        <translatorcomment>User more pleasant symbols</translatorcomment>-        <translation>用更友好的定义替换默认符号 (如:括号, 波浪符号).</translation>+        <translation>将默认符号(括号、波浪号)替换为优化样式。</translation>     </message>     <message>         <source>Pretty symbols</source>-        <translation type="obsolete">Símbolos lindos</translation>+        <translation type="obsolete">优化符号</translation>     </message>     <message>-        <location line="+20"/>+        <location filename="mainwindow.ui" line="1702"/>         <source>Embed style (defs)</source>-        <translatorcomment>Include style information in output</translatorcomment>-        <translation>内嵌页面样式 (defs)</translation>+        <translation>嵌入样式(defs)</translation>     </message>     <message>-        <location line="+25"/>-        <source>Name of the referenced  style file.</source>-        <translatorcomment>Name of external style file</translatorcomment>-        <translation>被引用的样式表的文件名.</translation>+        <location filename="mainwindow.ui" line="1727"/>+        <source>Name of the referenced style file.</source>+        <translation>引用的样式文件名称。</translation>     </message>     <message>-        <location line="+3"/>-        <location line="+108"/>+        <location filename="mainwindow.ui" line="1730"/>+        <location filename="mainwindow.ui" line="1838"/>         <source>highlight.sty</source>-        <translation></translation>+        <translation>highlight.sty</translation>     </message>     <message>         <source>Style include:</source>-        <translation type="obsolete">Incluir estilo:</translation>+        <translation type="obsolete">样式包含:</translation>     </message>     <message>-        <location line="-631"/>+        <location filename="mainwindow.ui" line="1207"/>         <source>Set encoding:</source>-        <translation>编码设置:</translation>+        <translation>设置编码:</translation>     </message>     <message>-        <location line="-941"/>-        <source>Output destination:</source>-        <translation>输出路径:</translation>+        <source>Read ctags file:</source>+        <translation type="obsolete">读取 ctags 文件:</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1580"/>+        <source>Output as ordered list</source>+        <translation>以有序列表输出</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1607"/>+        <source>Enclose in pre tags</source>+        <translation>包含在 pre 标签中</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1665"/>+        <source>Add Babel compatibility</source>+        <translation>添加 Babel 兼容性</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1685"/>+        <source>Add pretty symbols</source>+        <translation>添加优化符号</translation>     </message>     <message>-        <location line="+1167"/>-        <location line="+278"/>-        <location line="+108"/>-        <location line="+295"/>+        <location filename="mainwindow.ui" line="1433"/>+        <location filename="mainwindow.ui" line="1711"/>+        <location filename="mainwindow.ui" line="1819"/>+        <location filename="mainwindow.ui" line="2114"/>         <source>Stylesheet file:</source>-        <translation>外链样式表文件名:</translation>+        <translation>样式表文件:</translation>     </message>     <message>-        <location line="-648"/>-        <location line="+275"/>-        <location line="+108"/>-        <location line="+295"/>-        <source>Stylesheet include file:</source>-        <translation>包含的样式表文件:</translation>+        <location filename="mainwindow.ui" line="266"/>+        <source>Output destination:</source>+        <translation>输出目标:</translation>     </message>     <message>-        <source>Read ctags file:</source>-        <translation type="obsolete">读取ctags文件:</translation>+        <location filename="mainwindow.ui" line="322"/>+        <source>Browse output directory</source>+        <translation>浏览输出目录</translation>     </message>     <message>-        <location line="-2127"/>-        <source>Highlight</source>-        <translation>Highlight</translation>+        <location filename="mainwindow.ui" line="389"/>+        <source>Copy highlighted code of the selected file into the clipboard.</source>+        <translation>将选中文件的高亮代码复制到剪贴板。</translation>     </message>     <message>-        <location line="+150"/>-        <source>Files</source>-        <translation>文件</translation>+        <location filename="mainwindow.ui" line="474"/>+        <source>Paste code from clipboard and copy the output back in one step</source>+        <translation>从剪贴板粘贴代码并一步转换后复制回去</translation>     </message>     <message>-        <location line="+261"/>-        <source>Paste clipboard content into the preview window.</source>-        <translation>将剪贴板中的代码粘贴到预览窗口.</translation>+        <location filename="mainwindow.ui" line="480"/>+        <source>Paste, Convert and Copy</source>+        <translation>粘贴、转换并复制</translation>     </message>     <message>-        <location line="+3"/>-        <source>Paste from clipboard (%1)</source>-        <oldsource>Paste from clipboard</oldsource>-        <translation type="unfinished">从剪贴板获取代码</translation>+        <location filename="mainwindow.ui" line="506"/>+        <source>Only output the selected lines of the preview.</source>+        <translation>仅输出预览中选中的行。</translation>     </message>     <message>-        <location line="+17"/>-        <source>Copy highlighted code into the clipboard.</source>-        <translation>将高亮代码复制到剪贴板.</translation>+        <location filename="mainwindow.ui" line="509"/>+        <source>Output selected lines only</source>+        <translation>仅输出选中行</translation>     </message>     <message>-        <location line="+3"/>-        <source>Copy preview to clipboard (%1)</source>-        <oldsource>Copy preview to clipboard</oldsource>-        <translation type="unfinished">将预览结果复制到剪贴板</translation>+        <location filename="mainwindow.ui" line="606"/>+        <source>Shows description of a selected plug-in script.</source>+        <translation>显示选中插件脚本的描述。</translation>     </message>     <message>-        <location line="-39"/>-        <source>Select syntax:</source>-        <translation>代码语言:</translation>+        <location filename="mainwindow.ui" line="676"/>+        <source>Scripts</source>+        <translation>脚本</translation>     </message>     <message>-        <source>Wi&amp;ndows</source>-        <oldsource>&amp;Windows</oldsource>-        <translation type="obsolete">窗口(&amp;W)</translation>+        <location filename="mainwindow.ui" line="682"/>+        <source>Choose a custom syntax or theme script.</source>+        <translation>选择自定义语法或主题脚本。</translation>     </message>     <message>-        <location line="-290"/>-        <source>Highlighting options</source>-        <oldsource>H&amp;ighlighting options</oldsource>-        <translation type="unfinished">代码高亮选项</translation>+        <location filename="mainwindow.ui" line="685"/>+        <source>Add custom script to pool</source>+        <translation>添加自定义脚本到列表</translation>     </message>     <message>-        <location line="+297"/>-        <source>Select the correct syntax of the code snippet.</source>-        <translation>给代码片段选择对应的语言格式.</translation>+        <location filename="mainwindow.ui" line="699"/>+        <source>You can check one file of each type (syntax and theme) to override the default behaviour. If checked, the scripts will be watched for changes.</source>+        <translation>你可以勾选每种类型(语法/主题)各一个文件以覆盖默认行为。+勾选后,脚本会自动监控文件变化。</translation>     </message>     <message>-        <location line="+115"/>-        <source>Plug-ins</source>-        <translation>插件</translation>+        <location filename="mainwindow.ui" line="708"/>+        <source>Remove the selected scripts.</source>+        <translation>移除选中的脚本。</translation>     </message>     <message>-        <location line="+9"/>-        <source>Add plug-in to pool</source>-        <translation>添加插件</translation>+        <location filename="mainwindow.ui" line="718"/>+        <source>Remove all scripts.</source>+        <translation>移除所有脚本。</translation>     </message>     <message>-        <location line="+51"/>-        <location line="+136"/>-        <source>Description</source>-        <translation>描述</translation>+        <source>Shows decription of a selected script.</source>+        <translation type="vanished">显示选中脚本的描述。</translation>     </message>     <message>-        <source>Shows decription of a selected plug-in script.</source>-        <translation type="vanished">显示选中插件的描述.</translation>+        <location filename="mainwindow.ui" line="739"/>+        <source>Script description</source>+        <translation>脚本描述</translation>     </message>     <message>-        <location line="-121"/>-        <source>Plug-In description</source>-        <translation>插件描述</translation>+        <location filename="mainwindow.ui" line="750"/>+        <source>Configure the LSP Client</source>+        <translation>配置 LSP 客户端</translation>     </message>     <message>-        <location line="+28"/>-        <source>Plug-in parameter</source>-        <oldsource>Plug-in input file</oldsource>-        <translation type="unfinished">输入插件的文件</translation>+        <location filename="mainwindow.ui" line="757"/>+        <source>LSP</source>+        <translation>LSP</translation>     </message>     <message>-        <location line="+9"/>-        <source>Optional plug-in parameter, this may be a path to a plug-in input file</source>-        <oldsource>Optional path to a plug-in input file</oldsource>-        <translation type="unfinished">传递给插件的一个可选路径</translation>+        <location filename="mainwindow.ui" line="799"/>+        <source>Language Server:</source>+        <translation>语言服务器:</translation>     </message>     <message>-        <location line="+13"/>-        <source>Select the plug-in input file.</source>-        <translation>选择传递给插件的文件.</translation>+        <location filename="mainwindow.ui" line="806"/>+        <source>Select a Language Server profile.</source>+        <translation>选择一个语言服务器配置文件。</translation>     </message>     <message>-        <location line="+77"/>-        <source>Shows description of a selected script.</source>-        <translation type="unfinished"></translation>+        <location filename="mainwindow.ui" line="765"/>+        <source>Executable:</source>+        <translation>可执行文件:</translation>     </message>     <message>-        <location line="+312"/>-        <source>BBCode</source>-        <translation>BBCode</translation>+        <location filename="mainwindow.ui" line="772"/>+        <source>Path of the server executable.</source>+        <translation>服务器可执行文件路径。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="785"/>+        <source>Select the server executable.</source>+        <translation>选择服务器可执行文件。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="823"/>+        <source>Print LSP messages to standard error</source>+        <translation>将 LSP 消息输出到标准错误流</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="826"/>+        <source>Output Logs</source>+        <translation>输出日志</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="833"/>+        <source>Start an initialization request.</source>+        <translation>发起初始化请求。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="836"/>+        <source>Check Capabilities</source>+        <translation>检查功能支持</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="847"/>+        <source>Workspace:</source>+        <translation>工作区:</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="854"/>+        <source>The workspace directory.</source>+        <translation>工作区目录。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="867"/>+        <source>Select the workspace directory of your project.</source>+        <translation>选择项目的工作区目录。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="912"/>+        <source>Run hover requests to add tooltips to your output (HTML only).</source>+        <translation>执行悬停请求以在输出中添加提示(仅 HTML)。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="915"/>+        <source>Hover</source>+        <translation>悬停提示</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="886"/>+        <source>Improve token recognition with semantic highlighting.</source>+        <translation>使用语义高亮提升标记识别效果。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="889"/>+        <source>Semantic Highlighting</source>+        <translation>语义高亮</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="899"/>+        <source>Show syntax errors and messages (depends on output format).</source>+        <translation>显示语法错误与消息(取决于输出格式)。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="902"/>+        <source>Show Syntax Errors</source>+        <translation>显示语法错误</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="925"/>+        <source>Do not require a server capabilities response</source>+        <translation>无需等待服务器功能响应</translation>     </message>     <message>-        <location line="+57"/>+        <location filename="mainwindow.ui" line="928"/>+        <source>Legacy Protocol</source>+        <translation>旧版协议</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1105"/>         <source>Set line numbering start.</source>-        <translation type="unfinished"></translation>+        <translation>设置行号起始值。</translation>     </message>     <message>-        <location line="+260"/>-        <source>Stylesheets</source>-        <translation>样式表</translation>+        <location filename="mainwindow.ui" line="1192"/>+        <source>Generate output without version information comment.</source>+        <translation>生成不含版本信息注释的输出。</translation>     </message>     <message>-        <source>Include:</source>-        <translation type="vanished">包含:</translation>+        <location filename="mainwindow.ui" line="1195"/>+        <source>Omit version info comment</source>+        <translation>忽略版本信息注释</translation>     </message>     <message>-        <source>Index/ctags</source>-        <translation type="obsolete">Index/ctags</translation>+        <location filename="mainwindow.ui" line="1204"/>+        <source>Set the output file encoding.</source>+        <translation>设置输出文件编码。</translation>     </message>     <message>-        <location line="+185"/>+        <location filename="mainwindow.ui" line="1466"/>+        <location filename="mainwindow.ui" line="1741"/>+        <location filename="mainwindow.ui" line="1849"/>+        <location filename="mainwindow.ui" line="2144"/>+        <source>Stylesheet include file:</source>+        <translation>样式表包含文件:</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1550"/>         <source>Line numbering options:</source>         <translation>行号选项:</translation>     </message>     <message>-        <location line="+30"/>-        <source>Output as ordered list</source>-        <translation>根据列表顺序输出</translation>+        <location filename="mainwindow.ui" line="17"/>+        <source>Highlight</source>+        <translation>高亮</translation>     </message>     <message>-        <location line="+27"/>-        <source>Enclose in pre tags</source>-        <translation>包含在pre标记中</translation>+        <location filename="mainwindow.ui" line="167"/>+        <source>Files</source>+        <translation>文件</translation>     </message>     <message>-        <location line="+58"/>-        <source>Add Babel compatibility</source>-        <translation>兼容Babel宏包</translation>+        <location filename="mainwindow.ui" line="428"/>+        <source>Paste clipboard content into the preview window.</source>+        <translation>将剪贴板内容粘贴到预览窗口。</translation>     </message>     <message>-        <location line="+20"/>-        <source>Add pretty symbols</source>-        <translatorcomment>User nicer symbols</translatorcomment>-        <translation>使用更友好的符号</translation>+        <location filename="mainwindow.ui" line="431"/>+        <source>Paste from clipboard (%1)</source>+        <translation>从剪贴板粘贴 (%1)</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="448"/>+        <source>Copy highlighted code into the clipboard.</source>+        <translation>将高亮代码复制到剪贴板。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="451"/>+        <source>Copy preview to clipboard (%1)</source>+        <translation>复制预览到剪贴板 (%1)</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="412"/>+        <source>Select syntax:</source>+        <translation>选择语法:</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="419"/>+        <source>Select the correct syntax of the code snippet.</source>+        <translation>为代码片段选择正确的语法。</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="534"/>+        <source>Plug-ins</source>+        <translation>插件</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="543"/>+        <source>Add plug-in to pool</source>+        <translation>添加插件到列表</translation>+    </message>+    <message>+        <source>List of plug-ins.</source>+        <translation type="obsolete">插件列表。</translation>+    </message>+    <message>+        <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;+p, li { white-space: pre-wrap; }+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Remove the selected plug-ins.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>+        <translation type="obsolete">移除选中的插件。</translation>+    </message>+    <message>+        <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;+p, li { white-space: pre-wrap; }+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Remove all plug-ins.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>+        <translation type="obsolete">移除所有插件。</translation>+    </message>+    <message>+        <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;+p, li { white-space: pre-wrap; }+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Use the selected plugin.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>+        <translation type="obsolete">使用选中的插件。</translation>+    </message>+    <message>+        <source>Enable selected plug-in script</source>+        <translation type="obsolete">启用选中的插件脚本</translation>     </message>     <message>-        <location line="+80"/>-        <location line="+108"/>+        <location filename="mainwindow.ui" line="1048"/>+        <source>BBCode</source>+        <translation>BBCode</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1365"/>+        <source>Stylesheets</source>+        <translation>样式表</translation>+    </message>+    <message>+        <source>Include:</source>+        <translation type="vanished">包含:</translation>+    </message>+    <message>+        <source>Index/ctags</source>+        <translation type="obsolete">索引/ctags</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1765"/>+        <location filename="mainwindow.ui" line="1873"/>         <source>Path of the style include file.</source>-        <translatorcomment>Ptah of file to be included in document style</translatorcomment>-        <translation>外链样式表的路径.</translation>+        <translation>样式包含文件路径。</translation>     </message>     <message>-        <location line="-95"/>-        <location line="+108"/>-        <location line="+295"/>+        <location filename="mainwindow.ui" line="1778"/>+        <location filename="mainwindow.ui" line="1886"/>+        <location filename="mainwindow.ui" line="2181"/>         <source>Select a style include file.</source>-        <translation>选择一个样式表文件.</translation>+        <translation>选择样式包含文件。</translation>     </message>     <message>         <source>TeX options</source>-        <translation type="obsolete">Opciones de TeX</translation>+        <translation type="obsolete">TeX 选项</translation>     </message>     <message>-        <location line="-371"/>+        <location filename="mainwindow.ui" line="1810"/>         <source>Embed style (macros)</source>-        <translation>内嵌页面样式 (macros)</translation>+        <translation>嵌入样式(宏)</translation>     </message>     <message>         <source>RTF options</source>-        <translation type="obsolete">Opciones de RTF</translation>+        <translation type="obsolete">RTF 选项</translation>     </message>     <message>-        <location line="+105"/>+        <location filename="mainwindow.ui" line="1915"/>         <source>Add character stylesheets with formatting information. You can select the stylesheets in your word processor to reformat additional text.</source>-        <translatorcomment>For RTF output, Openoffice supports character stylesheets</translatorcomment>-        <translation>将高亮风格的格式信息添加到字体样式中.-你可以在你的文字处理软件中通过选择对应的样式来格式化附加的文字.</translation>+        <translation>添加带格式信息的字符样式表。+你可以在文字处理软件中选择这些样式表来格式化其他文本。</translation>     </message>     <message>-        <location line="+4"/>+        <location filename="mainwindow.ui" line="1919"/>         <source>Add character styles</source>-        <translation>添加字体样式</translation>+        <translation>添加字符样式</translation>     </message>     <message>-        <location line="+7"/>-        <source>Set page color attribute to background color.</source>-        <translation type="unfinished"></translation>+        <source>Set page color attribute to background color</source>+        <translation type="vanished">将页面颜色属性设为背景色</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="1929"/>+        <source>Set page color</source>+        <translation>设置页面颜色</translation>     </message>     <message>-        <location line="+12"/>+        <location filename="mainwindow.ui" line="1938"/>         <source>Page size:</source>-        <translation>页面大小:</translation>+        <translation>页面尺寸:</translation>     </message>     <message>-        <location line="+13"/>+        <location filename="mainwindow.ui" line="1951"/>         <source>Select a page size.</source>-        <translation>设置页面大小.</translation>+        <translation>选择页面尺寸。</translation>     </message>     <message>-        <location line="+7"/>+        <location filename="mainwindow.ui" line="1958"/>         <source>A3</source>-        <translation></translation>+        <translation>A3</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1963"/>         <source>A4</source>-        <translation></translation>+        <translation>A4</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1968"/>         <source>A5</source>-        <translation></translation>+        <translation>A5</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1973"/>         <source>B4</source>-        <translation></translation>+        <translation>B4</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1978"/>         <source>B5</source>-        <translation></translation>+        <translation>B5</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1983"/>         <source>B6</source>-        <translation></translation>+        <translation>B6</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1988"/>         <source>Letter</source>         <translation>Letter</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="1993"/>         <source>Legal</source>-        <translation>正规</translation>+        <translation>Legal</translation>     </message>     <message>         <source>SVG options</source>-        <translation type="obsolete">Opciones de SVG</translation>+        <translation type="obsolete">SVG 选项</translation>     </message>     <message>         <source>Image size:</source>-        <translation type="vanished">图像大小:</translation>+        <translation type="vanished">图像尺寸:</translation>     </message>     <message>         <source>Width:</source>         <translation type="vanished">宽度:</translation>     </message>     <message>-        <location line="+57"/>+        <location filename="mainwindow.ui" line="2050"/>         <source>Enter the SVG width (may contain units).</source>-        <translatorcomment>Input SVG image width</translatorcomment>-        <translation>输入SVG图像宽度.</translation>-    </message>-    <message>-        <location line="+20"/>-        <source>Height:</source>-        <translation>高度:</translation>+        <translation>输入 SVG 宽度(可包含单位)。</translation>     </message>     <message>-        <location line="+16"/>+        <location filename="mainwindow.ui" line="2086"/>         <source>Enter the SVG height (may contain units).</source>-        <translatorcomment>Input SVG image height</translatorcomment>-        <translation>输入SVG图像高度.</translation>+        <translation>输入 SVG 高度(可包含单位)。</translation>     </message>     <message>-        <location line="+124"/>+        <location filename="mainwindow.ui" line="2210"/>         <source>No options defined.</source>-        <translation>没有可供选择的选项..</translation>+        <translation>未定义选项。</translation>     </message>     <message>-        <location line="+25"/>+        <location filename="mainwindow.ui" line="2235"/>         <source>Formatting</source>         <translation>格式化</translation>     </message>     <message>-        <location line="+29"/>+        <location filename="mainwindow.ui" line="2264"/>         <source>Color theme:</source>-        <translation>高亮主题:</translation>+        <translation>颜色主题:</translation>     </message>     <message>-        <location line="+47"/>+        <source>Toggle classic theme or Base16 theme selection.</source>+        <translation type="vanished">切换经典主题或 Base16 主题选择。</translation>+    </message>+    <message>+        <source>Base16</source>+        <translation type="vanished">Base16</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="2311"/>         <source>Select a colour theme.</source>-        <translation>选择一个用于高亮的颜色主题.</translation>+        <translation>选择一个颜色主题。</translation>     </message>     <message>         <source>Reformat and indent your code. This feature is enabled tor C, C++, C# and Java code.</source>-        <translation type="vanished">重新格式化排版你的代码.-这项功能仅支持 C, C++, C# 和 Java.</translation>+        <translation type="vanished">重新格式化并缩进代码。+此功能支持 C、C++、C# 和 Java 代码。</translation>     </message>     <message>-        <location line="+24"/>+        <location filename="mainwindow.ui" line="2335"/>         <source>Reformat:</source>-        <translation>格式化代码:</translation>+        <translation>重新格式化:</translation>     </message>     <message>-        <location line="+19"/>+        <location filename="mainwindow.ui" line="2354"/>         <source>Choose a formatting scheme.</source>-        <translation>选择一种代码格式化风格.</translation>+        <translation>选择格式化方案。</translation>     </message>     <message>-        <source>Linux</source>-        <translation type="obsolete">Linux</translation>-    </message>-    <message>-        <location line="+14"/>+        <location filename="mainwindow.ui" line="2368"/>         <source>Change the keyword case.</source>-        <translation>改变关键字大小写.</translation>+        <translation>更改关键字大小写(仅对不区分大小写的语法生效)。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="2371"/>         <source>Keyword case:</source>         <translation>关键字大小写:</translation>     </message>     <message>-        <location line="+19"/>+        <location filename="mainwindow.ui" line="2390"/>         <source>Select a keyword case.</source>-        <translation>这是关键字大小写.</translation>+        <translation>选择关键字大小写格式。</translation>     </message>     <message>-        <location line="+7"/>+        <location filename="mainwindow.ui" line="2397"/>         <source>UPPER</source>         <translation>大写</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2402"/>         <source>lower</source>         <translation>小写</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2407"/>         <source>Capitalize</source>         <translation>首字母大写</translation>     </message>     <message>-        <location line="+18"/>+        <location filename="mainwindow.ui" line="2425"/>         <source>Tab width:</source>-        <translation>制表符(Tab)宽度:</translation>+        <translation>制表符宽度:</translation>     </message>     <message>-        <location line="+16"/>+        <location filename="mainwindow.ui" line="2441"/>         <source>Enter the number of spaces which replace a tab. Set the width to 0 to keep tabs.</source>-        <translation>设置多少个空格替换一个制表符(Tab).-设置为0时保留制表符(Tab).</translation>+        <translation>输入替换制表符的空格数。+设置为 0 表示保留制表符。</translation>     </message>     <message>-        <location line="+15"/>+        <location filename="mainwindow.ui" line="2456"/>         <source>Enable line wrapping.</source>-        <translation>启用自动换行.</translation>+        <translation>启用自动换行。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="2459"/>         <source>Line wrapping</source>         <translation>自动换行</translation>     </message>     <message>-        <location line="+13"/>+        <location filename="mainwindow.ui" line="2472"/>         <source>Enter the maximum line length.</source>-        <translation>设定每行代码的最大长度.</translation>+        <translation>输入最大行长度。</translation>     </message>     <message>-        <location line="+19"/>+        <location filename="mainwindow.ui" line="2491"/>         <source>Indent statements and function parameters after wrapping.</source>-        <translation>换行后自动缩进语句和函数参数.</translation>+        <translation>换行后缩进语句和函数参数。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="2494"/>         <source>Intelligent wrapping</source>-        <translation>自动缩进</translation>+        <translation>智能换行</translation>     </message>     <message>-        <location line="+21"/>+        <location filename="mainwindow.ui" line="2515"/>         <source>Font na&amp;me:</source>-        <oldsource>Font name:</oldsource>-        <translation type="unfinished">字体:</translation>+        <translation>字体(&amp;M):</translation>     </message>     <message>         <source>Select or enter the font name.</source>-        <translation type="obsolete">Seleccionar o introduzcir el nombre de la fuente.</translation>+        <translation type="obsolete">选择或输入字体名称。</translation>     </message>     <message>         <source>Font size:</source>         <translation type="vanished">字体大小:</translation>     </message>     <message>-        <location line="+56"/>+        <location filename="mainwindow.ui" line="2571"/>         <source>Enter the font size.</source>-        <translation>输入字体大小.</translation>+        <translation>输入字体大小。</translation>     </message>     <message>-        <location line="+76"/>+        <location filename="mainwindow.ui" line="2647"/>         <source>&amp;Visit andre-simon.de</source>-        <oldsource>Visit andre-simon.de</oldsource>-        <translation type="unfinished">访问 andre-simon.de</translation>+        <translation>访问官网 andre-simon.de(&amp;V)</translation>     </message>     <message>-        <location line="+11"/>+        <location filename="mainwindow.ui" line="2658"/>         <source>&amp;Dock floating panels</source>         <translation>停靠浮动面板(&amp;D)</translation>     </message>     <message>-        <location line="-2628"/>+        <location filename="mainwindow.ui" line="30"/>         <source>Preview</source>         <translation>预览</translation>     </message>     <message>-        <location line="+346"/>+        <source>Visit website</source>+        <translation type="obsolete">访问网站</translation>+    </message>+    <message>+        <location filename="mainwindow.ui" line="376"/>         <source>Start the conversion of your input files.</source>-        <translation>点击按钮开始转换文件.</translation>+        <translation>开始转换输入文件。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="379"/>         <source>Convert files</source>         <translation>转换文件</translation>     </message>     <message>         <source>Copy highlighted code of the seleted file into the clipboard.</source>-        <translation type="vanished">将选中文件的高亮代码复制到剪贴板中.</translation>+        <translation type="vanished">将选中文件的高亮代码复制到剪贴板。</translation>     </message>     <message>-        <location line="+25"/>+        <location filename="mainwindow.ui" line="404"/>         <source>Clipboard</source>         <translation>剪贴板</translation>     </message>     <message>-        <location line="-12"/>+        <location filename="mainwindow.ui" line="392"/>         <source>Copy file to clipboard</source>-        <translation>将输出文件内容复制到剪贴板</translation>+        <translation>复制文件到剪贴板</translation>     </message>     <message>-        <location line="+148"/>+        <location filename="mainwindow.ui" line="540"/>         <source>Choose a plug-in script.</source>-        <translation>选择一个插件脚本.</translation>+        <translation>选择一个插件脚本。</translation>     </message>     <message>-        <location line="+14"/>+        <location filename="mainwindow.ui" line="554"/>         <source>List of plug-ins. Toggle checkbox to enable the scripts. The preview window may not display all plug-in effects.</source>-        <oldsource>List of plug-ins. Toggle checkbox to enable the scripts.</oldsource>-        <translation type="unfinished">插件列表. 打钩激活对应脚本.</translation>+        <translation>插件列表。勾选复选框以启用脚本。预览窗口可能不会显示所有插件效果。</translation>     </message>     <message>-        <location line="+18"/>+        <location filename="mainwindow.ui" line="572"/>         <source>Remove the selected plug-ins.</source>-        <translation>移除所有选中的插件.</translation>+        <translation>移除选中的插件。</translation>     </message>     <message>-        <location line="+10"/>+        <location filename="mainwindow.ui" line="582"/>         <source>Remove all plug-ins.</source>-        <translation>移除所有插件.</translation>+        <translation>移除所有插件。</translation>+    </message>+    <message>+        <source>Use the selected plugin.</source>+        <translation type="obsolete">使用选中的插件。</translation>     </message>     <message>-        <location line="-524"/>+        <location filename="mainwindow.ui" line="58"/>         <source>Output progress:</source>         <translation>输出进度:</translation>     </message>     <message>-        <location line="+28"/>+        <location filename="mainwindow.ui" line="86"/>         <source>&amp;File</source>         <translation>文件(&amp;F)</translation>     </message>     <message>-        <location line="+8"/>+        <location filename="mainwindow.ui" line="94"/>         <source>&amp;Help</source>         <translation>帮助(&amp;H)</translation>     </message>     <message>-        <location line="+228"/>-        <source>Browse output directory</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+67"/>-        <source>Copy highlighted code of the selected file into the clipboard.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+85"/>-        <source>Paste code from clipboard and copy the output back in one step</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+6"/>-        <source>Paste, Convert and Copy</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+26"/>-        <source>Only output the selected lines of the preview.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+3"/>-        <source>Output selected lines only</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+97"/>-        <source>Shows description of a selected plug-in script.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+70"/>-        <source>Scripts</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+6"/>-        <source>Choose a custom syntax or theme script.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+3"/>-        <source>Add custom script to pool</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+14"/>-        <source>You can check one file of each type (syntax and theme) to override the default behaviour. If checked, the scripts will be watched for changes.</source>-        <oldsource>You can check one file of each type (syntax and theme) to override the default behaviour.</oldsource>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+9"/>-        <source>Remove the selected scripts.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+10"/>-        <source>Remove all scripts.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+21"/>-        <source>Script description</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+11"/>-        <source>Configure the LSP Client</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+7"/>-        <source>LSP</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+42"/>-        <source>Language Server:</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+7"/>-        <source>Select a Language Server profile.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="-41"/>-        <source>Executable:</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+7"/>-        <source>Path of the server executable.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+13"/>-        <source>Select the server executable.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+38"/>-        <source>Print LSP messages to standard error</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+3"/>-        <source>Output Logs</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+7"/>-        <source>Start an initialization request.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+3"/>-        <source>Check Capabilities</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+11"/>-        <source>Workspace:</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+7"/>-        <source>The workspace directory.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+13"/>-        <source>Select the workspace directory of your project.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+45"/>-        <source>Run hover requests to add tooltips to your output (HTML only).</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+3"/>-        <source>Hover</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="-29"/>-        <source>Improve token recognition with semantic highlighting.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+3"/>-        <source>Semantic Highlighting</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+10"/>-        <source>Show syntax errors and messages (depends on output format).</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+3"/>-        <source>Show Syntax Errors</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+23"/>-        <source>Do not require a server capabilities response</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+3"/>-        <source>Legacy Protocol</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+125"/>-        <source>ANSI ESC</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+5"/>-        <source>XTerm256 ESC</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+5"/>-        <source>Truecolor ESC</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+129"/>-        <source>Generate output without version information comment.</source>-        <translation type="unfinished"></translation>+        <source>Wi&amp;ndows</source>+        <translation type="vanished">窗口(&amp;n)</translation>     </message>     <message>-        <location line="+3"/>-        <source>Omit version info comment</source>-        <translation type="unfinished"></translation>+        <location filename="mainwindow.ui" line="122"/>+        <source>Highlighting options</source>+        <translation>高亮选项</translation>     </message>     <message>-        <location line="+9"/>-        <source>Set the output file encoding.</source>-        <translation type="unfinished"></translation>+        <source>You can apply system shortcuts for copy and paste.</source>+        <translation type="vanished">你可以使用系统快捷键进行复制和粘贴。</translation>     </message>     <message>-        <location line="+353"/>-        <source>Add an anchor to each line.</source>-        <translation type="unfinished"></translation>-    </message>-    <message>-        <location line="+64"/>-        <source>Add HTML MIME Type when copying code to the clipboard</source>-        <translation type="unfinished"></translation>+        <location filename="mainwindow.ui" line="594"/>+        <location filename="mainwindow.ui" line="730"/>+        <source>Description</source>+        <translation>描述</translation>     </message>     <message>-        <location line="+3"/>-        <source>Copy with MIME type</source>-        <translation type="unfinished"></translation>+        <source>Shows decription of a selected plug-in script.</source>+        <translation type="vanished">显示选中插件脚本的描述。</translation>     </message>     <message>-        <location line="+38"/>-        <source>Adapt output for the Babel package</source>-        <translation type="unfinished"></translation>+        <location filename="mainwindow.ui" line="609"/>+        <source>Plug-In description</source>+        <translation>插件描述</translation>     </message>     <message>-        <location line="+10"/>-        <source>Adapt output for the Beamer package</source>-        <translation type="unfinished"></translation>+        <location filename="mainwindow.ui" line="637"/>+        <source>Plug-in parameter</source>+        <translation>插件参数</translation>     </message>     <message>-        <location line="+3"/>-        <source>Add Beamer compatibility</source>-        <translation type="unfinished"></translation>+        <location filename="mainwindow.ui" line="646"/>+        <source>Optional plug-in parameter, this may be a path to a plug-in input file</source>+        <translation>可选插件参数,可以是插件输入文件的路径</translation>     </message>     <message>-        <location line="+254"/>-        <source>Set page color</source>-        <translation type="unfinished"></translation>+        <location filename="mainwindow.ui" line="659"/>+        <source>Select the plug-in input file.</source>+        <translation>选择插件输入文件。</translation>     </message>     <message>-        <location line="+93"/>-        <source>I&amp;mage width:</source>-        <translation type="unfinished"></translation>+        <source>Replace spaces by nbsp entities.</source>+        <translation type="obsolete">将空格替换为不换行空格实体。</translation>     </message>     <message>-        <location line="+309"/>-        <source>Reformat and indent your code.-This feature is enabled for C, C++, C# and Java code.</source>-        <translation type="unfinished"></translation>+        <source>Use non breaking spaces</source>+        <translation type="obsolete">使用不换行空格</translation>     </message>     <message>-        <location line="+170"/>+        <location filename="mainwindow.ui" line="2501"/>         <source>Do not add line numbering to lines which were automatically wrapped.</source>-        <translation type="unfinished"></translation>+        <translation>自动换行的行不添加行号。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="mainwindow.ui" line="2504"/>         <source>Omit line numbers of wrapped lines</source>-        <translation type="unfinished"></translation>+        <translation>换行行忽略行号</translation>     </message>     <message>-        <location line="+30"/>+        <location filename="mainwindow.ui" line="2534"/>         <source>Select or enter the font name. HTML supports a list of fonts, separated with comma.</source>-        <translation>选择或者输入字体名. HTML支持用逗号分隔的字体列表.</translation>+        <translation>选择或输入字体名称。HTML 支持用逗号分隔的字体列表。</translation>     </message>     <message>-        <location line="+15"/>+        <location filename="mainwindow.ui" line="2549"/>         <source>Font si&amp;ze:</source>-        <translation type="unfinished"></translation>+        <translation>字体大小(&amp;z):</translation>     </message>     <message>-        <location line="+25"/>+        <location filename="mainwindow.ui" line="2574"/>         <source>10</source>-        <translation type="unfinished"></translation>+        <translation>10</translation>     </message>     <message>-        <location line="+15"/>+        <location filename="mainwindow.ui" line="2589"/>         <source>&amp;Open files</source>-        <translation>打开(&amp;O)</translation>+        <translation>打开文件(&amp;O)</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2594"/>         <source>&amp;Exit</source>         <translation>退出(&amp;E)</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2599"/>         <source>&amp;Load</source>         <translation>加载(&amp;L)</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2604"/>         <source>&amp;Save</source>         <translation>保存(&amp;S)</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2609"/>         <source>Load &amp;default project</source>-        <translation>加载默认工程(&amp;D)</translation>+        <translation>加载默认项目(&amp;D)</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2614"/>         <source>&amp;Readme</source>-        <oldsource>Readme</oldsource>-        <translation type="unfinished">ReadMe</translation>+        <translation>说明文档(&amp;R)</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2619"/>         <source>&amp;Tips</source>-        <translation>小贴士(&amp;T)</translation>+        <translation>使用技巧(&amp;T)</translation>     </message>     <message>-        <location line="+8"/>+        <location filename="mainwindow.ui" line="2627"/>         <source>&amp;Changelog</source>-        <translation>查看变更(&amp;C)</translation>+        <translation>更新日志(&amp;C)</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2632"/>         <source>&amp;License</source>         <translation>许可证(&amp;L)</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2637"/>         <source>&amp;About Highlight</source>-        <translation>关于Highlight(&amp;A)</translation>+        <translation>关于 Highlight(&amp;A)</translation>     </message>     <message>-        <location line="+5"/>+        <location filename="mainwindow.ui" line="2642"/>         <source>A&amp;bout translations</source>-        <oldsource>About &amp;translations</oldsource>-        <translation type="unfinished">关于翻译(&amp;T)</translation>-    </message>-    <message>-        <location line="+26"/>-        <source>&amp;File access trace (W32)</source>-        <translation type="unfinished"></translation>+        <translation>关于翻译(&amp;b)</translation>     </message> </context> <context>     <name>ShowTextFile</name>     <message>-        <location filename="showtextfile.ui" line="+17"/>+        <location filename="showtextfile.ui" line="17"/>         <source>Show text</source>-        <translation>文本显示</translation>+        <translation>显示文本</translation>     </message>     <message>-        <location line="+20"/>+        <location filename="showtextfile.ui" line="37"/>         <source>TextLabel</source>-        <translation></translation>+        <translation>文本标签</translation>     </message>     <message>-        <location line="+34"/>+        <location filename="showtextfile.ui" line="71"/>         <source>OK</source>         <translation>确定</translation>     </message>@@ -1764,74 +1687,74 @@ This feature is enabled for C, C++, C# and Java code.</source> <context>     <name>io_report</name>     <message>-        <location filename="io_report.ui" line="+14"/>+        <location filename="io_report.ui" line="14"/>         <source>Error summary</source>-        <translatorcomment>错误总结</translatorcomment>-        <translation>Resumen de Error</translation>+        <translation>错误汇总</translation>     </message>     <message>-        <location line="+10"/>+        <location filename="io_report.ui" line="24"/>         <source>Input errors:</source>-        <translation>输入错误:</translation>+        <translation>输入错误:</translation>     </message>     <message>-        <location line="+10"/>+        <location filename="io_report.ui" line="34"/>         <source>Remove files above from input file list</source>-        <translation>将以上文件从输入文件列表中移除</translation>+        <translation>从输入列表中移除以上文件</translation>     </message>     <message>-        <location line="+14"/>+        <location filename="io_report.ui" line="48"/>         <source>Output errors:</source>-        <translation>输出错误:</translation>+        <translation>输出错误:</translation>     </message>     <message>-        <location line="+17"/>+        <location filename="io_report.ui" line="65"/>         <source>Reformatting not possible:</source>-        <translation>不支持代码格式化的文件:</translation>+        <translation>无法重新格式化:</translation>     </message>     <message>-        <location line="+17"/>+        <location filename="io_report.ui" line="82"/>         <source>Failed syntax tests:</source>-        <translation type="unfinished"></translation>+        <translation>语法测试失败:</translation>     </message> </context> <context>     <name>syntax_chooser</name>     <message>-        <location filename="syntax_chooser.ui" line="+14"/>+        <location filename="syntax_chooser.ui" line="14"/>         <source>Syntax selection</source>-        <translation type="unfinished"></translation>+        <translation>语法选择</translation>     </message>     <message>-        <location line="+18"/>+        <location filename="syntax_chooser.ui" line="32"/>         <source>Select correct syntax</source>-        <translation type="unfinished"></translation>+        <translation>选择正确的语法</translation>     </message>     <message>-        <location line="+18"/>+        <location filename="syntax_chooser.ui" line="50"/>         <source>TextLabel</source>-        <translation type="unfinished"></translation>+        <translation>文本标签</translation>     </message>     <message>-        <location line="+24"/>+        <location filename="syntax_chooser.ui" line="74"/>         <source>These entries are configured in filetypes.conf.</source>-        <translation type="unfinished"></translation>+        <translation>这些条目在 filetypes.conf 中配置。</translation>     </message>     <message>-        <location line="+7"/>+        <location filename="syntax_chooser.ui" line="81"/>         <source>The selection will be remembered for this session.</source>-        <translation type="unfinished"></translation>+        <translation>本次会话将记住你的选择。</translation>     </message>     <message>-        <location line="+3"/>+        <location filename="syntax_chooser.ui" line="84"/>         <source>Remember selection</source>-        <translation type="unfinished"></translation>+        <translation>记住选择</translation>     </message>     <message>-        <location filename="syntax_chooser.cpp" line="+57"/>+        <location filename="syntax_chooser.cpp" line="57"/>         <source>The file extension %1 is assigned to multiple syntax definitions. Select the correct one:</source>-        <translation type="unfinished"></translation>+        <translation>文件扩展名 %1 对应多个语法定义。+请选择正确的一项:</translation>     </message> </context> </TS>

src/gui-qt/mainwindow.cpp

@@ -35,6 +35,7 @@ along with Highlight.  If not, see <http://www.gnu.org/licenses/>.  #include "io_report.h" #include "syntax_chooser.h"+#include "themeswatchdelegate.h"   #ifdef Q_OS_WIN@@ -76,7 +77,7 @@ MainWindow::MainWindow(QWidget *parent)         fileOpenFilter="All files (*)";     } -    // fill themes combo+    // fill theme gallery  #ifdef Q_OS_MACOS     QDir themesDirClassic(QCoreApplication::applicationDirPath() + "/../Resources/themes");@@ -92,64 +93,29 @@ MainWindow::MainWindow(QWidget *parent)     #endif #endif -    QStringList filesClassic = themesDirClassic.entryList(QStringList("*.theme"), QDir::Files, QDir::Name);-    QStringList filesBase16 = themesDirBase16.entryList(QStringList("*.theme"), QDir::Files, QDir::Name);--    Diluculum::LuaState ls;-    Diluculum::LuaValueMap categoryMap;--    try {--        for (const auto& fileName : filesClassic) {-            QString tPath(fileName);-            QString tCat;--            ls.doFile (themesDirClassic.absoluteFilePath(tPath).toStdString());-            QString tDesc (QString::fromStdString(ls["Description"].value().asString()));-            if (ls["Categories"].value() !=Diluculum::Nil){--                categoryMap = ls["Categories"].value().asTable();--                for(auto it = categoryMap.begin(); it != categoryMap.end(); ++it)-                {-                    tCat.append( QString::fromStdString( it->second.asString()));-                    tCat.append(",");-                }-            }-            QList<QString> themeEntry = {tPath.section('.',0, 0), tDesc, tCat, "0"};-            themesList.append(themeEntry);-        }--        for (const auto& fileName : filesBase16) {-            QString tPath(fileName);-            QString tCat;--            ls.doFile (themesDirBase16.absoluteFilePath(tPath).toStdString());-            QString tDesc (QString::fromStdString(ls["Description"].value().asString()));-            if (ls["Categories"].value() !=Diluculum::Nil){--                categoryMap = ls["Categories"].value().asTable();--                for(auto it = categoryMap.begin(); it != categoryMap.end(); ++it)-                {-                    tCat.append( QString::fromStdString( it->second.asString()));-                    tCat.append(",");-                }-            }-            QList<QString> themeEntry = { tPath.section('.',0, 0), tDesc, tCat, "1"};-            themesList.append(themeEntry);-        }-    }  catch (Diluculum::LuaError &err) {+    themeModel = new ThemeListModel(this);+    QStringList themeErrors = themeModel->addThemes(themesDirClassic);+    themeErrors << themeModel->addThemes(themesDirBase16, "base16/");+    if (!themeErrors.isEmpty()) {         QMessageBox::warning(this, tr("Initialization error"),-                             tr("Could not read a colour theme: ") + QString::fromStdString(err.what()));+                             tr("Could not read a colour theme: ") + themeErrors.join("\n"));     }-    ui->comboTheme->setCurrentIndex(0); -    ui->comboThemeFilter->addItem(tr("light"), "light");-    ui->comboThemeFilter->addItem(tr("dark"), "dark");-    ui->comboThemeFilter->addItem(tr("B16 light"), "light");-    ui->comboThemeFilter->addItem(tr("B16 dark"), "dark");-    ui->comboThemeFilter->setCurrentIndex(0);+    themeProxy = new ThemeFilterProxyModel(this);+    themeProxy->setSourceModel(themeModel);+    ui->lvThemes->setModel(themeProxy);+    ui->lvThemes->setItemDelegate(new ThemeSwatchDelegate(ui->lvThemes));+    ui->lvThemes->setMouseTracking(true);++    QObject::connect(ui->leThemeSearch, &QLineEdit::textChanged, this, [this](const QString& text) {+        // filtering may move the view's current index; this must not change the selected theme+        ignoreThemeChange = true;+        themeProxy->setSearchText(text);+        selectTheme(selectedThemeId);+        ignoreThemeChange = false;+    });+    QObject::connect(ui->lvThemes->selectionModel(), &QItemSelectionModel::currentChanged,+                     this, &MainWindow::onThemeCurrentChanged);      ui->comboLSProfiles->addItem(tr("Please select a Server")); @@ -186,6 +152,21 @@ MainWindow::MainWindow(QWidget *parent)     ui->tabIOSelection->setDocumentMode(false);     #endif +    // only the tabs scroll, so the convert button below them stays visible in small windows+    QWidget* optionsPane = new QWidget();+    QVBoxLayout* optionsLayout = new QVBoxLayout(optionsPane);+    optionsLayout->setContentsMargins(0, 0, 0, 0);+    ui->verticalLayout_16->removeWidget(ui->tabIOSelection);+    ui->verticalLayout_16->removeWidget(ui->tabWidgetOptions);+    optionsLayout->addWidget(ui->tabIOSelection);+    optionsLayout->addWidget(ui->tabWidgetOptions);+    QScrollArea* optionsScrollArea = new QScrollArea();+    optionsScrollArea->setWidgetResizable(true);+    optionsScrollArea->setFrameShape(QFrame::NoFrame);+    optionsScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);+    optionsScrollArea->setWidget(optionsPane);+    ui->verticalLayout_16->insertWidget(0, optionsScrollArea);+     #ifdef Q_OS_WIN     // https://forum.qt.io/topic/101391/windows-10-dark-theme/     if (QSysInfo::productVersion()=="10") {@@ -239,11 +220,16 @@ MainWindow::MainWindow(QWidget *parent)     QObject::connect(ui->cbFragment, SIGNAL(clicked()), this, SLOT(plausibility()));     QObject::connect(ui->cbLSHover, SIGNAL(clicked()), this, SLOT(plausibility()));     QObject::connect(ui->cbLSSemantic, SIGNAL(clicked()), this, SLOT(plausibility()));+    QObject::connect(ui->cbLSHover, SIGNAL(clicked()), this, SLOT(updatePreview()));+    QObject::connect(ui->cbLSSemantic, SIGNAL(clicked()), this, SLOT(updatePreview()));+    QObject::connect(ui->cbLSSyntaxErrors, SIGNAL(clicked()), this, SLOT(updatePreview()));      QObject::connect(ui->tabIOSelection, SIGNAL(currentChanged(int)), this, SLOT(plausibility()));      QObject::connect(ui->lvInputFiles, SIGNAL(itemSelectionChanged()), this, SLOT(updatePreview()));     QObject::connect(ui->lvPluginScripts, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(updatePreview()));+    // must run first: keeps one checked script per type before the preview is updated+    QObject::connect(ui->lvUserScripts, &QListWidget::itemChanged, this, &MainWindow::onUserScriptChanged);     QObject::connect(ui->lvUserScripts, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(updatePreview()));     QObject::connect(ui->lvUserScripts, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(plausibility())); @@ -257,18 +243,31 @@ MainWindow::MainWindow(QWidget *parent)     QObject::connect(ui->cbEncoding, SIGNAL(clicked()), this, SLOT(updatePreview()));     QObject::connect(ui->comboEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePreview())); -    QObject::connect(ui->comboFontName, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePreview()));+    // the font combo is editable, so typed names must update the preview too+    QObject::connect(ui->comboFontName, SIGNAL(currentTextChanged(QString)), this, SLOT(updatePreview()));     QObject::connect(ui->comboKwCase, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePreview()));     QObject::connect(ui->comboReformat, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePreview()));-    QObject::connect(ui->comboTheme, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePreview()));     QObject::connect(ui->comboSelectSyntax, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePreview()));-    QObject::connect(ui->comboThemeFilter, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePreview()));++    // the hidden syntax combo keeps the selection, the palette only offers a searchable view of its entries+    ui->comboSelectSyntax->hide();+    syntaxPalette = new SyntaxPalette(ui->comboSelectSyntax->model(), this);+    QObject::connect(ui->tbSelectSyntax, &QToolButton::clicked, this, [this]() {+        syntaxPalette->popup(ui->tbSelectSyntax, ui->comboSelectSyntax->currentIndex());+    });+    QObject::connect(syntaxPalette, &SyntaxPalette::syntaxSelected, ui->comboSelectSyntax, &QComboBox::setCurrentIndex);+    QObject::connect(ui->comboSelectSyntax, QOverload<int>::of(&QComboBox::currentIndexChanged),+                     this, &MainWindow::updateSyntaxChip);      QObject::connect(ui->comboLSProfiles, SIGNAL(currentIndexChanged(int)), this, SLOT(loadLSProfile()));      QObject::connect(ui->sbLineNoWidth, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()));     QObject::connect(ui->sbLineNoStart, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()));     QObject::connect(ui->leFontSize, SIGNAL(textChanged(QString)), this, SLOT(updatePreview()));+    QObject::connect(ui->sbTabWidth, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()));+    QObject::connect(ui->sbLineLength, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()));+    // the parameter may be a file path, so do not run the plug-ins with each typed character+    QObject::connect(ui->lePluginReadFilePath, SIGNAL(editingFinished()), this, SLOT(updatePreview()));     QObject::connect(ui->cbOmitWrappedLineNumbers, SIGNAL(clicked()), this, SLOT(updatePreview()));      QObject::connect(&scriptWatcher, SIGNAL(fileChanged(QString)), this, SLOT(updatePreview()));@@ -286,11 +285,21 @@ MainWindow::MainWindow(QWidget *parent)      readSettings(); -    fillThemeCombo(oldThemeIndex);+    selectTheme(selectedThemeId);      twoPassOutFile=QDir::tempPath() + "/highlight_twopass.lua"; +    // keep the always visible convert button in sync with the input file list+    QObject::connect(ui->lvInputFiles->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(plausibility()));+    QObject::connect(ui->lvInputFiles->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(plausibility()));+    QObject::connect(ui->lvInputFiles->model(), SIGNAL(modelReset()), this, SLOT(plausibility()));+     plausibility();+    updateSyntaxChip();++    // the options panel must not shrink below the width of its widest element+    optionsScrollArea->setMinimumWidth(optionsPane->minimumSizeHint().width()+                                       + optionsScrollArea->verticalScrollBar()->sizeHint().width());      if (runFirstTime && shortNamesDisabled()) {         QMessageBox::warning(this, tr("NTFS Short Names"), tr("NTFS short names may be disabled on your volumes. Highlight can not read input with multibyte file names if no short name is available. This information will no longer bother you."));@@ -299,6 +308,11 @@ MainWindow::MainWindow(QWidget *parent)     statusBar()->showMessage(tr("Always at your service"), 2500); } +void MainWindow::updateSyntaxChip()+{+    ui->tbSelectSyntax->setText(ui->comboSelectSyntax->currentText());+}+ bool MainWindow::shortNamesDisabled() { #ifdef Q_OS_WIN     QSettings reg("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\FileSystem",@@ -310,20 +324,36 @@ bool MainWindow::shortNamesDisabled() { #endif } -void MainWindow::fillThemeCombo(int restoreVal)+void MainWindow::selectTheme(const QString& themeId) {-    QString catFilter = ui->comboThemeFilter->currentData().toString();-    bool isBase16 = ui->comboThemeFilter->currentIndex() >1;--    ui->comboTheme->clear();--    for (int i = 0; i < themesList.size(); ++i) {-        QList<QString> curTheme = themesList.at(i);-        if ( (!isBase16 && curTheme.at(2).contains( catFilter) && !curTheme.at(2).contains( "base16")) ||-             (isBase16 && curTheme.at(2).contains( catFilter) && curTheme.at(2).contains( "base16")))-          ui->comboTheme->addItem(curTheme.at(1), curTheme.at(0));+    int sourceRow = themeModel->rowOfTheme(themeId);+    if (sourceRow < 0) {+        if (!themeModel->rowCount())+            return;+        sourceRow = 0;     }-    ui->comboTheme->setCurrentIndex(restoreVal);+    QModelIndex sourceIdx = themeModel->index(sourceRow);+    selectedThemeId = sourceIdx.data(ThemeListModel::ThemeIdRole).toString();++    // the selected theme stays active even if it is hidden by the search filter+    QModelIndex proxyIdx = themeProxy->mapFromSource(sourceIdx);+    if (proxyIdx.isValid()) {+        ui->lvThemes->setCurrentIndex(proxyIdx);+        ui->lvThemes->scrollTo(proxyIdx);+    } else {+        ui->lvThemes->selectionModel()->clear();+    }+}++void MainWindow::onThemeCurrentChanged(const QModelIndex& current)+{+    if (ignoreThemeChange || !current.isValid())+        return;+    QString themeId = current.data(ThemeListModel::ThemeIdRole).toString();+    if (themeId == selectedThemeId)+        return;+    selectedThemeId = themeId;+    updatePreview(); }  MainWindow::~MainWindow()@@ -359,13 +389,17 @@ void MainWindow::addToView(const QStringList& list, QListWidget* listWidget, con     QString croppedName;     for (const auto& listElement : list) { +        bool isListed = false;         for (int i = 0; i < listWidget->count(); ++i) {-            if (listWidget->item(i)->data(Qt::UserRole).toString()==listElement)-                return;+            if (listWidget->item(i)->data(Qt::UserRole).toString()==listElement) {+                isListed = true;+                break;+            }         }+        if (isListed) continue;          croppedName = baseName ? QFileInfo(listElement).baseName(): QFileInfo(listElement).fileName() ;-        if (croppedName.isEmpty()) break;+        if (croppedName.isEmpty()) continue;         listItem=new QListWidgetItem(QIcon(iconName), croppedName );         listItem->setData(Qt::UserRole, listElement);         listItem->setToolTip(listElement);@@ -376,7 +410,8 @@ void MainWindow::addToView(const QStringList& list, QListWidget* listWidget, con  void MainWindow::on_pbOutputDest_clicked() {-    ui->leOutputDest->setText(QFileDialog::getExistingDirectory(this, tr("Select destination directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks));+    QString dir = QFileDialog::getExistingDirectory(this, tr("Select destination directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);+    if (!dir.isEmpty()) ui->leOutputDest->setText(dir); }  @@ -427,8 +462,11 @@ void MainWindow::readSettings()     auto setSelectedItems = [&](QListWidget* view, const QString& key) {         QVariantList selected = settings.value(key).toList();         for (const auto& item : std::as_const(selected)) {-            view->item(item.toInt())->setCheckState(Qt::Checked);-            if (view == ui->lvUserScripts) on_lvUserScripts_itemClicked(view->item(item.toInt()));+            // the saved index may be stale if the list could not be restored completely+            QListWidgetItem* listItem = view->item(item.toInt());+            if (!listItem) continue;+            listItem->setCheckState(Qt::Checked);+            if (view == ui->lvUserScripts) on_lvUserScripts_itemClicked(listItem);         }     }; @@ -476,7 +514,6 @@ void MainWindow::readSettings()     setComboBox(ui->comboRTFPageSize);     setComboBox(ui->comboSelectSyntax);     setComboBox(ui->comboLSProfiles);-    setComboBox(ui->comboThemeFilter);      setLineEdit(ui->leHTMLStyleFile);     setLineEdit(ui->leHTMLStyleIncFile);@@ -500,7 +537,8 @@ void MainWindow::readSettings()     setTabWidget(ui->tabIOSelection);     setTabWidget(ui->tabWidgetOptions); -    oldThemeIndex = settings.value(ui->comboTheme->property(name).toString()).toInt();+    selectedThemeId = settings.value("selectedTheme").toString();+    ui->leThemeSearch->setText(settings.value(ui->leThemeSearch->property(name).toString()).toString());      runFirstTime = settings.value("runFirstTime", true).toBool();     settings.endGroup();@@ -519,17 +557,18 @@ void MainWindow::writeSettings()     QStringList inFiles, plugins, userScripts;     QVariantList selectedPlugins, selectedUserScripts; -    auto collectItems = [&](QListWidget* view, QStringList& list, QVariantList& selected) {+    auto collectItems = [&](QListWidget* view, QStringList& list, QVariantList* selected) {         for (int i = 0; i < view->count(); ++i) {             list << view->item(i)->data(Qt::UserRole).toString();-            if (view->item(i)->checkState() == Qt::Checked)-                selected.push_back(QVariant(i));+            if (selected && view->item(i)->checkState() == Qt::Checked)+                selected->push_back(QVariant(i));         }     }; -    collectItems(ui->lvInputFiles, inFiles, selectedPlugins);-    collectItems(ui->lvPluginScripts, plugins, selectedPlugins);-    collectItems(ui->lvUserScripts, userScripts, selectedUserScripts);+    // input files are not checkable, so only their paths are saved+    collectItems(ui->lvInputFiles, inFiles, nullptr);+    collectItems(ui->lvPluginScripts, plugins, &selectedPlugins);+    collectItems(ui->lvUserScripts, userScripts, &selectedUserScripts);      const char* name = "objectName";     settings.setValue(ui->lvInputFiles->property(name).toString(), inFiles);@@ -601,13 +640,13 @@ void MainWindow::writeSettings()     saveComboBox(ui->comboReformat);     saveComboBox(ui->comboRTFPageSize);     saveComboBox(ui->comboLSProfiles);-    saveComboBox(ui->comboTheme);-    saveComboBox(ui->comboThemeFilter);     saveComboBox(ui->comboSelectSyntax);     saveComboBox(ui->comboEncoding, true);     saveComboBox(ui->comboFontName, true);      saveLineEdit(ui->leOutputDest);+    saveLineEdit(ui->leThemeSearch);+    settings.setValue("selectedTheme", selectedThemeId);     saveLineEdit(ui->leHTMLStyleFile);     saveLineEdit(ui->leHTMLStyleIncFile);     saveLineEdit(ui->leLATEXStyleFile);@@ -952,8 +991,9 @@ void MainWindow::applyCtrlValues(highlight::CodeGenerator* generator, bool previ         if (embedStyle)             generator->setIncludeStyle(embedStyle->isChecked()); -        generator->setFragmentCode(ui->cbFragment->isChecked());-        generator->setKeepInjections(ui->cbKeepInjections->isChecked());+        // disabled options are not supported by the current output format+        generator->setFragmentCode(ui->cbFragment->isEnabled() && ui->cbFragment->isChecked());+        generator->setKeepInjections(ui->cbKeepInjections->isEnabled() && ui->cbKeepInjections->isChecked());          generator->setHTMLAttachAnchors(ui->cbHTMLAnchors->isChecked());         generator->setHTMLOrderedList(ui->cbIncLineNo->isChecked() && ui->cbHTMLOrderedList->isChecked());@@ -1371,8 +1411,7 @@ void MainWindow::on_pbStartConversion_clicked()     statusBar()->showMessage(tr("Converted %1 files in %2 ms").arg(ui->lvInputFiles->count()).arg(t.elapsed()));     ui->progressBar->reset();     this->setCursor(Qt::ArrowCursor);-    ui->pbStartConversion->setEnabled(true);-    ui->pbCopyFile2CP->setEnabled(true);+    plausibility();      if (!inputErrors.isEmpty() || !outputErrors.isEmpty() || !reformatErrors.isEmpty() || !syntaxTestErrors.isEmpty()) {         io_report report;@@ -1605,15 +1644,16 @@ void MainWindow::plausibility()     ui->cbReformat->setEnabled( !semanticOptionIsChecked);     ui->comboReformat->setEnabled(ui->cbReformat->isChecked() && !semanticOptionIsChecked);     ui->comboKwCase->setEnabled(ui->cbKwCase->isChecked());-    ui->comboTheme->setEnabled(getUserScriptPath("theme").isEmpty());+    ui->lvThemes->setEnabled(getUserScriptPath("theme").isEmpty());+    ui->leThemeSearch->setEnabled(getUserScriptPath("theme").isEmpty());     ui->comboSelectSyntax->setEnabled(getUserScriptPath("lang").isEmpty());+    ui->tbSelectSyntax->setEnabled(getUserScriptPath("lang").isEmpty());      ui->cbHTMLInlineCSS->setEnabled(ui->cbHTMLEmbedStyle->isChecked());-    ui->cbHTMLFileNameAnchor->setEnabled(ui->cbHTMLAnchors->isChecked());     ui->leHTMLStyleFile->setEnabled(!ui->cbHTMLEmbedStyle->isChecked());     ui->leHTMLStyleIncFile->setEnabled(!(ui->cbHTMLInlineCSS->isEnabled() && ui->cbHTMLInlineCSS->isChecked()));     ui->pbHTMLChooseStyleIncFile->setEnabled(!(ui->cbHTMLInlineCSS->isEnabled() && ui->cbHTMLInlineCSS->isChecked()));-    ui->leHTMLCssPrefix->setEnabled(!ui->cbHTMLInlineCSS->isChecked());+    ui->leHTMLCssPrefix->setEnabled(!(ui->cbHTMLInlineCSS->isEnabled() && ui->cbHTMLInlineCSS->isChecked()));     ui->leLATEXStyleFile->setEnabled(!ui->cbLATEXEmbedStyle->isChecked());     ui->leTEXStyleFile->setEnabled(!ui->cbTEXEmbedStyle->isChecked());     ui->leSVGStyleFile->setEnabled(!ui->cbSVGEmbedStyle->isChecked());@@ -1625,9 +1665,12 @@ void MainWindow::plausibility()     ui->cbHTMLEnclosePreTags->setEnabled(ui->cbFragment->isChecked());     ui->cbKeepInjections->setEnabled(ui->cbFragment->isEnabled() && ui->cbFragment->isChecked());     ui->cbHTMLAnchors->setEnabled(ui->cbIncLineNo->isChecked());-    ui->cbHTMLFileNameAnchor->setEnabled(ui->cbIncLineNo->isChecked());+    ui->cbHTMLFileNameAnchor->setEnabled(ui->cbHTMLAnchors->isEnabled() && ui->cbHTMLAnchors->isChecked());     ui->cbHTMLOrderedList->setEnabled(ui->cbIncLineNo->isChecked());     ui->pbCopyToCP->setEnabled(!savedClipboardContent.isEmpty());+    ui->pbStartConversion->setEnabled(ui->lvInputFiles->count() > 0);+    ui->pbCopyFile2CP->setEnabled(ui->lvInputFiles->count() > 0+                                  && ui->tabIOSelection->currentWidget()!=ui->tab_clipboard);      copyShortcut->setEnabled(ui->tabIOSelection->currentWidget()==ui->tab_clipboard);     pasteShortcut->setEnabled(ui->tabIOSelection->currentWidget()==ui->tab_clipboard);@@ -1663,7 +1706,7 @@ void MainWindow::updatePreview()         getDataFromCP = sender()==ui->pbPasteFromCB;     } -    if ( ui->comboTheme->currentIndex()<0+    if ( selectedThemeId.isEmpty()          || (!getDataFromCP && NULL==ui->lvInputFiles->currentItem())          || (getDataFromCP && savedClipboardContent.isEmpty())) return; @@ -1923,16 +1966,20 @@ void MainWindow::on_pbClearSelPlugin_clicked()         delete selectedItems.at(i);     }     ui->lblPluginDescription->setText("");+    updatePreview(); }  void MainWindow::on_pbClearSelScript_clicked() {     QList<QListWidgetItem *> selectedItems = ui->lvUserScripts->selectedItems();     for (int i = 0; i < selectedItems.size(); ++i) {-        scriptWatcher.removePath( ui->lvUserScripts->item(i)->data(Qt::UserRole).toString());+        scriptWatcher.removePath( selectedItems.at(i)->data(Qt::UserRole).toString());         delete selectedItems.at(i);     }     ui->lblScriptDescription->setText("");+    // deleting items emits no itemChanged signal, so refresh the dependent controls here+    plausibility();+    updatePreview(); } void MainWindow::on_pbClearSelection_clicked() {@@ -1950,12 +1997,18 @@ void MainWindow::on_pbClearAll_clicked() void MainWindow::on_pbClearAllPlugins_clicked() {     ui->lvPluginScripts->clear();+    ui->lblPluginDescription->setText("");+    updatePreview(); }  void MainWindow::on_pbClearAllScripts_clicked() {     ui->lvUserScripts->clear();-    scriptWatcher.removePaths(scriptWatcher.files());+    if (!scriptWatcher.files().isEmpty())+        scriptWatcher.removePaths(scriptWatcher.files());+    ui->lblScriptDescription->setText("");+    plausibility();+    updatePreview(); }  void MainWindow::on_actionVisit_website_triggered()@@ -1966,6 +2019,8 @@ void MainWindow::on_actionVisit_website_triggered() void MainWindow::on_pbPluginReadFilePath_clicked() {     selectSingleFile(ui->lePluginReadFilePath, tr("Choose a plug-in input file"), "*");+    // setText() emits no editingFinished signal+    updatePreview(); }  void MainWindow::on_pbCopyAndPaste_clicked()@@ -1986,26 +2041,30 @@ void MainWindow::on_lvUserScripts_itemClicked(QListWidgetItem *item)          Diluculum::LuaState ls;          ls.doFile ( scriptPath.toStdString());          ui->lblScriptDescription->setText(QString::fromStdString(ls["Description"].value().asString()));--         if (item->checkState()==Qt::Checked){-             scriptWatcher.addPath(scriptPath);-             QString fileExt=QFileInfo(scriptPath).completeSuffix();-             QString otherScriptPath;-             for (int i = 0; i < ui->lvUserScripts->count(); ++i) {-                 otherScriptPath = ui->lvUserScripts->item(i)->data(Qt::UserRole).toString();-                 if (ui->lvUserScripts->item(i)!=item && otherScriptPath.endsWith(fileExt)){-                     ui->lvUserScripts->item(i)->setCheckState(Qt::Unchecked);-                     scriptWatcher.removePath(otherScriptPath);-                 }-             }-         } else {-             scriptWatcher.removePath(scriptPath);-         }      } catch (Diluculum::LuaError &err) {          QMessageBox::warning(this, "User script error", QString::fromStdString( err.what()));      } } +void MainWindow::onUserScriptChanged(QListWidgetItem *item)+{+    // handled here instead of in itemClicked, which is not emitted if the check box is toggled by keyboard+    QString scriptPath = item->data(Qt::UserRole).toString();+    if (item->checkState()==Qt::Checked){+        scriptWatcher.addPath(scriptPath);+        QString fileExt = QFileInfo(scriptPath).suffix();+        for (int i = 0; i < ui->lvUserScripts->count(); ++i) {+            QListWidgetItem* otherItem = ui->lvUserScripts->item(i);+            if (otherItem!=item && otherItem->checkState()==Qt::Checked+                && QFileInfo(otherItem->data(Qt::UserRole).toString()).suffix()==fileExt){+                otherItem->setCheckState(Qt::Unchecked);+            }+        }+    } else {+        scriptWatcher.removePath(scriptPath);+    }+}+ QString MainWindow::getUserScriptPath(QString type){     for (int i = 0; i < ui->lvUserScripts->count(); ++i) {         QString path=ui->lvUserScripts->item(i)->data(Qt::UserRole).toString();@@ -2031,8 +2090,8 @@ void MainWindow::on_lvPluginScripts_itemClicked(QListWidgetItem *item)   QString MainWindow::getDistThemePath(){-    QString themeLocation =  ui->comboThemeFilter->currentIndex() >1 ? "themes/base16" : "themes";-    QString selectedTheme = ui->comboTheme->currentData().toString();+    QString themeLocation = "themes";+    const QString& selectedTheme = selectedThemeId; #ifdef Q_OS_MACOS      return QString("%1/../Resources/%3/%2.theme").arg(                             QCoreApplication::applicationDirPath()).arg(selectedTheme, themeLocation);@@ -2099,12 +2158,6 @@ QString MainWindow::getDistFileFilterPath(){ #endif } -void MainWindow::on_comboThemeFilter_currentIndexChanged(int /*index*/ )-{-    if (ui->comboTheme->count())-        fillThemeCombo(0);-}- QString MainWindow::getWindowsShortPath(const QString & path){      QString shortPath(path);@@ -2125,8 +2178,22 @@ QString MainWindow::getWindowsShortPath(const QString & path){  void MainWindow::loadLSProfile() { -    if (ui->comboLSProfiles->currentIndex()==0)+    // capabilities detected for the previous server do not apply to the new one+    for (QCheckBox* cb : {ui->cbLSHover, ui->cbLSSemantic}) {+        cb->setIcon(QIcon());+        cb->setEnabled(true);+    }+    plausibility();++    if (ui->comboLSProfiles->currentIndex()==0) {+        // no server selected: forget the previous one, an empty syntax disables the LSP features+        lsProfile.clear();+        lsSyntax.clear();+        lsOptions.clear();+        lsDelay = 0;+        ui->leLSExec->clear(); // also clears lsExecutable via on_leLSExec_textChanged()         return;+    }      lsProfile=ui->comboLSProfiles->currentText().toStdString(); @@ -2182,6 +2249,8 @@ bool MainWindow::initializeLS(highlight::CodeGenerator* generator, bool tellMe)                 ui->cbLSSemantic->setEnabled(false);             }             generator->exitLanguageServer();+            // setChecked() emits no clicked signal, so update the dependent controls here+            plausibility();             QMessageBox::information(this, "LSP Init. OK", tr("Language server initialization successful"));         }         return true;@@ -2217,7 +2286,8 @@ void MainWindow::on_leLSExec_textChanged(){ }  void MainWindow::on_pbSelWorkspace_clicked(){-    ui->leLSWorkspace->setText(QFileDialog::getExistingDirectory(this, tr("Select workspace directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks));+    QString dir = QFileDialog::getExistingDirectory(this, tr("Select workspace directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);+    if (!dir.isEmpty()) ui->leLSWorkspace->setText(dir); }  void MainWindow::on_pbSelExecutable_clicked(){

src/gui-qt/mainwindow.h

@@ -57,12 +57,15 @@ along with Highlight.  If not, see <http://www.gnu.org/licenses/>. #include <QFileSystemWatcher> #include <QDesktopServices> #include <QStyleFactory>+#include <QScrollArea>  #include "version.h" #include "codegenerator.h" #include "htmlgenerator.h" #include "lspprofile.h" #include "lspclient.h"+#include "thememodel.h"+#include "syntaxpalette.h"  #include <map> #include <vector>@@ -105,13 +108,12 @@ private:     QShortcut *copyShortcut;     QShortcut *pasteShortcut;     QFileSystemWatcher scriptWatcher;-    QStringList themesClassic;-    QStringList themesBase16;-    QList< QList<QString> > themesList;+    ThemeListModel *themeModel;+    ThemeFilterProxyModel *themeProxy;+    QString selectedThemeId;+    SyntaxPalette *syntaxPalette; -    int oldThemeIndex{0};--    bool getDataFromCP{false}, runFirstTime{true};+    bool getDataFromCP{false}, runFirstTime{true}, ignoreThemeChange{false};      void readSettings();     void writeSettings();@@ -128,6 +130,8 @@ private:      QString getWindowsShortPath(const QString & path); +    void updateSyntaxChip();+     void applyCtrlValues(highlight::CodeGenerator* generator, bool previewMode);     void applyEncoding(highlight::CodeGenerator* generator, QString &langDefPath); @@ -146,7 +150,7 @@ private:     std::string getFileSuffix(const std::string& fileName);     std::string getFileBaseName(const std::string& fileName);     void readLuaList(const std::string& paramName, const std::string& langName, Diluculum::LuaValue &luaVal, MMap* extMap);-    void fillThemeCombo(int);+    void selectTheme(const QString& themeId);     void showHelpFile(const QString& file);      void dragEnterEvent(QDragEnterEvent *event);@@ -206,10 +210,11 @@ private slots:      void on_pbBrowseOutDir_clicked();     void on_lvUserScripts_itemClicked(QListWidgetItem *item);+    void onUserScriptChanged(QListWidgetItem *item);     void on_lvPluginScripts_itemClicked(QListWidgetItem *item);      void on_browserPreview_selectionChanged();-    void on_comboThemeFilter_currentIndexChanged(int index);+    void onThemeCurrentChanged(const QModelIndex& current); };  #endif // MAINWINDOW_H

src/gui-qt/mainwindow.ui

@@ -246,151 +246,87 @@           </layout>          </item>          <item>-          <widget class="Line" name="line_11">-           <property name="orientation">-            <enum>Qt::Horizontal</enum>-           </property>-          </widget>-         </item>-         <item>-          <layout class="QVBoxLayout" name="verticalLayout">-           <item>-            <widget class="QLabel" name="label_11">-             <property name="font">-              <font>-               <weight>75</weight>-               <bold>true</bold>-              </font>-             </property>-             <property name="text">-              <string>Output destination:</string>-             </property>-            </widget>-           </item>-           <item>-            <layout class="QHBoxLayout" name="horizontalLayout_22">-             <item>-              <widget class="QLineEdit" name="leOutputDest">-               <property name="sizePolicy">-                <sizepolicy hsizetype="Minimum" vsizetype="Preferred">-                 <horstretch>0</horstretch>-                 <verstretch>0</verstretch>-                </sizepolicy>-               </property>-               <property name="toolTip">-                <string>Output directory</string>-               </property>-              </widget>-             </item>-             <item>-              <widget class="QPushButton" name="pbOutputDest">-               <property name="sizePolicy">-                <sizepolicy hsizetype="Fixed" vsizetype="Fixed">-                 <horstretch>0</horstretch>-                 <verstretch>0</verstretch>-                </sizepolicy>-               </property>-               <property name="minimumSize">-                <size>-                 <width>20</width>-                 <height>0</height>-                </size>-               </property>-               <property name="toolTip">-                <string>Select the output directory.</string>-               </property>-               <property name="text">-                <string>...</string>-               </property>-              </widget>-             </item>-             <item>-              <widget class="QPushButton" name="pbBrowseOutDir">-               <property name="sizePolicy">-                <sizepolicy hsizetype="Fixed" vsizetype="Fixed">-                 <horstretch>0</horstretch>-                 <verstretch>0</verstretch>-                </sizepolicy>-               </property>-               <property name="minimumSize">-                <size>-                 <width>20</width>-                 <height>0</height>-                </size>-               </property>-               <property name="toolTip">-                <string>Browse output directory</string>-               </property>-               <property name="text">-                <string/>-               </property>-               <property name="icon">-                <iconset resource="highlight-gui.qrc">-                 <normaloff>:/folder.png</normaloff>:/folder.png</iconset>-               </property>-              </widget>-             </item>-            </layout>-           </item>-           <item>-            <widget class="QCheckBox" name="cbWrite2Src">-             <property name="toolTip">-              <string>Save output in the input file directories.</string>-             </property>-             <property name="text">-              <string>Write to source directories</string>-             </property>-            </widget>-           </item>-          </layout>-         </item>-         <item>-          <widget class="Line" name="line_2">-           <property name="orientation">-            <enum>Qt::Horizontal</enum>-           </property>-          </widget>-         </item>-         <item>-          <widget class="QPushButton" name="pbStartConversion">-           <property name="sizePolicy">-            <sizepolicy hsizetype="Preferred" vsizetype="Fixed">-             <horstretch>0</horstretch>-             <verstretch>0</verstretch>-            </sizepolicy>-           </property>-           <property name="minimumSize">-            <size>-             <width>120</width>-             <height>0</height>-            </size>-           </property>-           <property name="font">-            <font>-             <pointsize>11</pointsize>-             <weight>75</weight>-             <bold>true</bold>-            </font>-           </property>-           <property name="toolTip">-            <string>Start the conversion of your input files.</string>-           </property>-           <property name="text">-            <string>Convert files</string>-           </property>-           <property name="default">-            <bool>true</bool>-           </property>-          </widget>-         </item>-         <item>-          <widget class="QPushButton" name="pbCopyFile2CP">-           <property name="toolTip">-            <string>Copy highlighted code of the selected file into the clipboard.</string>-           </property>-           <property name="text">-            <string>Copy file to clipboard</string>-           </property>+          <widget class="QGroupBox" name="groupOutputDest">+           <property name="title">+            <string>Output destination</string>+           </property>+           <layout class="QVBoxLayout" name="verticalLayout">+            <item>+             <layout class="QHBoxLayout" name="horizontalLayout_22">+              <item>+               <widget class="QLineEdit" name="leOutputDest">+                <property name="sizePolicy">+                 <sizepolicy hsizetype="Minimum" vsizetype="Preferred">+                  <horstretch>0</horstretch>+                  <verstretch>0</verstretch>+                 </sizepolicy>+                </property>+                <property name="toolTip">+                 <string>Output directory</string>+                </property>+               </widget>+              </item>+              <item>+               <widget class="QPushButton" name="pbOutputDest">+                <property name="sizePolicy">+                 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">+                  <horstretch>0</horstretch>+                  <verstretch>0</verstretch>+                 </sizepolicy>+                </property>+                <property name="minimumSize">+                 <size>+                  <width>20</width>+                  <height>0</height>+                 </size>+                </property>+                <property name="toolTip">+                 <string>Select the output directory.</string>+                </property>+                <property name="text">+                 <string>...</string>+                </property>+               </widget>+              </item>+              <item>+               <widget class="QPushButton" name="pbBrowseOutDir">+                <property name="sizePolicy">+                 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">+                  <horstretch>0</horstretch>+                  <verstretch>0</verstretch>+                 </sizepolicy>+                </property>+                <property name="minimumSize">+                 <size>+                  <width>20</width>+                  <height>0</height>+                 </size>+                </property>+                <property name="toolTip">+                 <string>Browse output directory</string>+                </property>+                <property name="text">+                 <string/>+                </property>+                <property name="icon">+                 <iconset resource="highlight-gui.qrc">+                  <normaloff>:/folder.png</normaloff>:/folder.png</iconset>+                </property>+               </widget>+              </item>+             </layout>+            </item>+            <item>+             <widget class="QCheckBox" name="cbWrite2Src">+              <property name="toolTip">+               <string>Save output in the input file directories.</string>+              </property>+              <property name="text">+               <string>Write to source directories</string>+              </property>+             </widget>+            </item>+           </layout>           </widget>          </item>         </layout>@@ -420,6 +356,25 @@              </property>             </widget>            </item>+           <item>+            <widget class="QToolButton" name="tbSelectSyntax">+             <property name="sizePolicy">+              <sizepolicy hsizetype="Expanding" vsizetype="Fixed">+               <horstretch>0</horstretch>+               <verstretch>0</verstretch>+              </sizepolicy>+             </property>+             <property name="toolTip">+              <string>Select the correct syntax of the code snippet.</string>+             </property>+             <property name="toolButtonStyle">+              <enum>Qt::ToolButtonTextBesideIcon</enum>+             </property>+             <property name="arrowType">+              <enum>Qt::DownArrow</enum>+             </property>+            </widget>+           </item>           </layout>          </item>          <item>@@ -626,45 +581,37 @@           </widget>          </item>          <item>-          <widget class="QLabel" name="label_15">-           <property name="font">-            <font>-             <weight>75</weight>-             <bold>true</bold>-            </font>-           </property>-           <property name="text">+          <widget class="QGroupBox" name="groupPluginParameter">+           <property name="title">             <string>Plug-in parameter</string>            </property>+           <layout class="QHBoxLayout" name="horizontalLayout_29">+            <item>+             <widget class="QLineEdit" name="lePluginReadFilePath">+              <property name="toolTip">+               <string>Optional plug-in parameter, this may be a path to a plug-in input file</string>+              </property>+             </widget>+            </item>+            <item>+             <widget class="QPushButton" name="pbPluginReadFilePath">+              <property name="minimumSize">+               <size>+                <width>20</width>+                <height>0</height>+               </size>+              </property>+              <property name="toolTip">+               <string>Select the plug-in input file.</string>+              </property>+              <property name="text">+               <string>...</string>+              </property>+             </widget>+            </item>+           </layout>           </widget>          </item>-         <item>-          <layout class="QHBoxLayout" name="horizontalLayout_29">-           <item>-            <widget class="QLineEdit" name="lePluginReadFilePath">-             <property name="toolTip">-              <string>Optional plug-in parameter, this may be a path to a plug-in input file</string>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QPushButton" name="pbPluginReadFilePath">-             <property name="minimumSize">-              <size>-               <width>20</width>-               <height>0</height>-              </size>-             </property>-             <property name="toolTip">-              <string>Select the plug-in input file.</string>-             </property>-             <property name="text">-              <string>...</string>-             </property>-            </widget>-           </item>-          </layout>-         </item>         </layout>        </widget>        <widget class="QWidget" name="tab_scripts">@@ -756,178 +703,202 @@         <attribute name="title">          <string>LSP</string>         </attribute>-        <layout class="QGridLayout" name="gridLayout_5">-         <item row="1" column="0">-          <layout class="QHBoxLayout" name="horizontalLayout_32">-           <item>-            <widget class="QLabel" name="label_17">-             <property name="text">-              <string>Executable:</string>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QLineEdit" name="leLSExec">-             <property name="toolTip">-              <string>Path of the server executable.</string>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QPushButton" name="pbSelExecutable">-             <property name="minimumSize">-              <size>-               <width>20</width>-               <height>0</height>-              </size>-             </property>-             <property name="toolTip">-              <string>Select the server executable.</string>-             </property>-             <property name="text">-              <string>...</string>-             </property>-            </widget>-           </item>-          </layout>-         </item>-         <item row="0" column="0">-          <layout class="QHBoxLayout" name="horizontalLayout_31">-           <item>-            <widget class="QLabel" name="label_10">-             <property name="text">-              <string>Language Server:</string>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QComboBox" name="comboLSProfiles">-             <property name="toolTip">-              <string>Select a Language Server profile.</string>-             </property>-             <property name="editable">-              <bool>false</bool>-             </property>-             <property name="currentText">-              <string notr="true"/>-             </property>-            </widget>-           </item>-          </layout>-         </item>-         <item row="2" column="0">-          <layout class="QHBoxLayout" name="horizontalLayout_34">-           <item>-            <widget class="QCheckBox" name="cbLSDebug">-             <property name="toolTip">-              <string>Print LSP messages to standard error</string>-             </property>-             <property name="text">-              <string>Output Logs</string>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QPushButton" name="pbLSInitialize">-             <property name="toolTip">-              <string>Start an initialization request.</string>-             </property>-             <property name="text">-              <string>Check Capabilities</string>-             </property>-            </widget>-           </item>-          </layout>+        <layout class="QVBoxLayout" name="verticalLayoutLSP">+         <item>+          <widget class="QGroupBox" name="groupLSServer">+           <property name="title">+            <string>Server</string>+           </property>+           <layout class="QVBoxLayout" name="verticalLayoutLSServer">+            <item>+             <layout class="QHBoxLayout" name="horizontalLayout_31">+              <item>+               <widget class="QLabel" name="label_10">+                <property name="text">+                 <string>Language Server:</string>+                </property>+               </widget>+              </item>+              <item>+               <widget class="QComboBox" name="comboLSProfiles">+                <property name="toolTip">+                 <string>Select a Language Server profile.</string>+                </property>+                <property name="editable">+                 <bool>false</bool>+                </property>+                <property name="currentText">+                 <string notr="true"/>+                </property>+               </widget>+              </item>+             </layout>+            </item>+            <item>+             <layout class="QHBoxLayout" name="horizontalLayout_32">+              <item>+               <widget class="QLabel" name="label_17">+                <property name="text">+                 <string>Executable:</string>+                </property>+               </widget>+              </item>+              <item>+               <widget class="QLineEdit" name="leLSExec">+                <property name="toolTip">+                 <string>Path of the server executable.</string>+                </property>+               </widget>+              </item>+              <item>+               <widget class="QPushButton" name="pbSelExecutable">+                <property name="minimumSize">+                 <size>+                  <width>20</width>+                  <height>0</height>+                 </size>+                </property>+                <property name="toolTip">+                 <string>Select the server executable.</string>+                </property>+                <property name="text">+                 <string>...</string>+                </property>+               </widget>+              </item>+             </layout>+            </item>+            <item>+             <layout class="QHBoxLayout" name="horizontalLayout_33">+              <item>+               <widget class="QLabel" name="label_16">+                <property name="text">+                 <string>Workspace:</string>+                </property>+               </widget>+              </item>+              <item>+               <widget class="QLineEdit" name="leLSWorkspace">+                <property name="toolTip">+                 <string>The workspace directory.</string>+                </property>+               </widget>+              </item>+              <item>+               <widget class="QPushButton" name="pbSelWorkspace">+                <property name="minimumSize">+                 <size>+                  <width>20</width>+                  <height>0</height>+                 </size>+                </property>+                <property name="toolTip">+                 <string>Select the workspace directory of your project.</string>+                </property>+                <property name="text">+                 <string>...</string>+                </property>+               </widget>+              </item>+             </layout>+            </item>+            <item>+             <layout class="QHBoxLayout" name="horizontalLayout_34">+              <item>+               <widget class="QCheckBox" name="cbLSDebug">+                <property name="toolTip">+                 <string>Print LSP messages to standard error</string>+                </property>+                <property name="text">+                 <string>Output Logs</string>+                </property>+               </widget>+              </item>+              <item>+               <widget class="QPushButton" name="pbLSInitialize">+                <property name="toolTip">+                 <string>Start an initialization request.</string>+                </property>+                <property name="text">+                 <string>Check Capabilities</string>+                </property>+               </widget>+              </item>+             </layout>+            </item>+           </layout>+          </widget>          </item>-         <item row="4" column="0">-          <layout class="QHBoxLayout" name="horizontalLayout_33">-           <item>-            <widget class="QLabel" name="label_16">-             <property name="text">-              <string>Workspace:</string>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QLineEdit" name="leLSWorkspace">-             <property name="toolTip">-              <string>The workspace directory.</string>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QPushButton" name="pbSelWorkspace">-             <property name="minimumSize">-              <size>-               <width>20</width>-               <height>0</height>-              </size>-             </property>-             <property name="toolTip">-              <string>Select the workspace directory of your project.</string>-             </property>-             <property name="text">-              <string>...</string>-             </property>-            </widget>-           </item>-          </layout>-         </item>-         <item row="3" column="0">-          <widget class="Line" name="line_6">-           <property name="orientation">-            <enum>Qt::Horizontal</enum>-           </property>-          </widget>-         </item>-         <item row="6" column="0">-          <widget class="QCheckBox" name="cbLSSemantic">-           <property name="toolTip">-            <string>Improve token recognition with semantic highlighting.</string>-           </property>-           <property name="text">-            <string>Semantic Highlighting</string>-           </property>-           <property name="checkable">-            <bool>true</bool>-           </property>-          </widget>-         </item>-         <item row="7" column="0">-          <widget class="QCheckBox" name="cbLSSyntaxErrors">-           <property name="toolTip">-            <string>Show syntax errors and messages (depends on output format).</string>-           </property>-           <property name="text">-            <string>Show Syntax Errors</string>-           </property>-           <property name="checkable">-            <bool>true</bool>-           </property>-          </widget>-         </item>-         <item row="5" column="0">-          <widget class="QCheckBox" name="cbLSHover">-           <property name="toolTip">-            <string>Run hover requests to add tooltips to your output (HTML only).</string>-           </property>-           <property name="text">-            <string>Hover</string>-           </property>-           <property name="checkable">-            <bool>true</bool>+         <item>+          <widget class="QGroupBox" name="groupLSFeatures">+           <property name="title">+            <string>Features</string>            </property>+           <layout class="QVBoxLayout" name="verticalLayoutLSFeatures">+            <item>+             <widget class="QCheckBox" name="cbLSHover">+              <property name="toolTip">+               <string>Run hover requests to add tooltips to your output (HTML only).</string>+              </property>+              <property name="text">+               <string>Hover</string>+              </property>+              <property name="checkable">+               <bool>true</bool>+              </property>+             </widget>+            </item>+            <item>+             <widget class="QCheckBox" name="cbLSSemantic">+              <property name="toolTip">+               <string>Improve token recognition with semantic highlighting.</string>+              </property>+              <property name="text">+               <string>Semantic Highlighting</string>+              </property>+              <property name="checkable">+               <bool>true</bool>+              </property>+             </widget>+            </item>+            <item>+             <widget class="QCheckBox" name="cbLSSyntaxErrors">+              <property name="toolTip">+               <string>Show syntax errors and messages (depends on output format).</string>+              </property>+              <property name="text">+               <string>Show Syntax Errors</string>+              </property>+              <property name="checkable">+               <bool>true</bool>+              </property>+             </widget>+            </item>+            <item>+             <widget class="QCheckBox" name="cbLSLegacy">+              <property name="toolTip">+               <string>Do not require a server capabilities response</string>+              </property>+              <property name="text">+               <string>Legacy Protocol</string>+              </property>+             </widget>+            </item>+           </layout>           </widget>          </item>-         <item row="8" column="0">-          <widget class="QCheckBox" name="cbLSLegacy">-           <property name="toolTip">-            <string>Do not require a server capabilities response</string>+         <item>+          <spacer name="verticalSpacerLSP">+           <property name="orientation">+            <enum>Qt::Vertical</enum>            </property>-           <property name="text">-            <string>Legacy Protocol</string>+           <property name="sizeHint" stdset="0">+            <size>+             <width>20</width>+             <height>0</height>+            </size>            </property>-          </widget>+          </spacer>          </item>         </layout>        </widget>@@ -999,12 +970,6 @@                <verstretch>0</verstretch>               </sizepolicy>              </property>-             <property name="font">-              <font>-               <weight>75</weight>-               <bold>true</bold>-              </font>-             </property>              <property name="toolTip">               <string>Choose an output format.</string>              </property>@@ -1068,241 +1033,252 @@           </layout>          </item>          <item>-          <widget class="Line" name="line_9">-           <property name="orientation">-            <enum>Qt::Horizontal</enum>-           </property>-          </widget>-         </item>-         <item>-          <layout class="QHBoxLayout" name="horizontalLayout_21">-           <item>-            <widget class="QCheckBox" name="cbIncLineNo">-             <property name="toolTip">-              <string>Add line numbers to the output.</string>-             </property>-             <property name="text">-              <string>Add line numbers</string>-             </property>-            </widget>-           </item>-           <item>-            <spacer name="horizontalSpacer_4">-             <property name="orientation">-              <enum>Qt::Horizontal</enum>-             </property>-             <property name="sizeHint" stdset="0">-              <size>-               <width>10</width>-               <height>20</height>-              </size>-             </property>-            </spacer>-           </item>-           <item>-            <widget class="QSpinBox" name="sbLineNoStart">-             <property name="toolTip">-              <string>Set line numbering start.</string>-             </property>-             <property name="buttonSymbols">-              <enum>QAbstractSpinBox::UpDownArrows</enum>-             </property>-             <property name="accelerated">-              <bool>true</bool>-             </property>-             <property name="maximum">-              <number>500</number>-             </property>-             <property name="value">-              <number>1</number>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QSpinBox" name="sbLineNoWidth">-             <property name="toolTip">-              <string>Select the line number width.</string>-             </property>-             <property name="minimum">-              <number>1</number>-             </property>-             <property name="maximum">-              <number>6</number>-             </property>-             <property name="value">-              <number>2</number>-             </property>-            </widget>-           </item>-          </layout>-         </item>-         <item>-          <widget class="QCheckBox" name="cbPadZeroes">-           <property name="enabled">-            <bool>false</bool>-           </property>-           <property name="toolTip">-            <string>Fill leading space of line numbers with zeroes.</string>-           </property>-           <property name="text">-            <string>Pad with zeroes</string>-           </property>-          </widget>-         </item>-         <item>-          <widget class="QCheckBox" name="cbFragment">-           <property name="sizePolicy">-            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">-             <horstretch>0</horstretch>-             <verstretch>0</verstretch>-            </sizepolicy>-           </property>-           <property name="toolTip">-            <string>Generate output without document header and footer.</string>-           </property>-           <property name="text">-            <string>Omit header and footer</string>-           </property>-          </widget>-         </item>-         <item>-          <widget class="QCheckBox" name="cbKeepInjections">-           <property name="toolTip">-            <string>Output any plug-in text injections even if document header and footer is omitted.</string>-           </property>-           <property name="text">-            <string>Keep Plug-In injections</string>-           </property>-          </widget>-         </item>-         <item>-          <widget class="QCheckBox" name="cbValidateInput">-           <property name="toolTip">-            <string>Test if input data is not binary.-Removes Unicode BOM mark.</string>-           </property>-           <property name="text">-            <string>Validate input data</string>-           </property>-          </widget>-         </item>-         <item>-          <widget class="QCheckBox" name="cbOmitVersionInfo">-           <property name="toolTip">-            <string>Generate output without version information comment.</string>-           </property>-           <property name="text">-            <string>Omit version info comment</string>-           </property>-          </widget>-         </item>-         <item>-          <layout class="QHBoxLayout" name="horizontalLayout_2">-           <item>-            <widget class="QCheckBox" name="cbEncoding">-             <property name="toolTip">-              <string>Set the output file encoding.</string>-             </property>-             <property name="text">-              <string>Set encoding:</string>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QComboBox" name="comboEncoding">-             <property name="toolTip">-              <string>Select or define the encoding.-The result has to match the input file encoding.</string>-             </property>-             <property name="editable">-              <bool>true</bool>-             </property>-             <property name="insertPolicy">-              <enum>QComboBox::InsertAtBottom</enum>-             </property>-             <item>-              <property name="text">-               <string>ISO-8859-1</string>-              </property>-             </item>-             <item>-              <property name="text">-               <string>ISO-8859-2</string>-              </property>-             </item>-             <item>-              <property name="text">-               <string>ISO-8859-3</string>-              </property>-             </item>-             <item>-              <property name="text">-               <string>ISO-8859-4</string>+          <widget class="QGroupBox" name="groupLineNumbers">+           <property name="title">+            <string>Line numbers</string>+           </property>+           <layout class="QVBoxLayout" name="verticalLayoutLineNumbers">+            <item>+             <layout class="QHBoxLayout" name="horizontalLayout_21">+              <item>+               <widget class="QCheckBox" name="cbIncLineNo">+                <property name="toolTip">+                 <string>Add line numbers to the output.</string>+                </property>+                <property name="text">+                 <string>Add line numbers</string>+                </property>+               </widget>+              </item>+              <item>+               <spacer name="horizontalSpacer_4">+                <property name="orientation">+                 <enum>Qt::Horizontal</enum>+                </property>+                <property name="sizeHint" stdset="0">+                 <size>+                  <width>10</width>+                  <height>20</height>+                 </size>+                </property>+               </spacer>+              </item>+              <item>+               <widget class="QSpinBox" name="sbLineNoStart">+                <property name="toolTip">+                 <string>Set line numbering start.</string>+                </property>+                <property name="buttonSymbols">+                 <enum>QAbstractSpinBox::UpDownArrows</enum>+                </property>+                <property name="accelerated">+                 <bool>true</bool>+                </property>+                <property name="maximum">+                 <number>500</number>+                </property>+                <property name="value">+                 <number>1</number>+                </property>+               </widget>+              </item>+              <item>+               <widget class="QSpinBox" name="sbLineNoWidth">+                <property name="toolTip">+                 <string>Select the line number width.</string>+                </property>+                <property name="minimum">+                 <number>1</number>+                </property>+                <property name="maximum">+                 <number>6</number>+                </property>+                <property name="value">+                 <number>2</number>+                </property>+               </widget>+              </item>+             </layout>+            </item>+            <item>+             <widget class="QCheckBox" name="cbPadZeroes">+              <property name="enabled">+               <bool>false</bool>               </property>-             </item>-             <item>-              <property name="text">-               <string>ISO-8859-5</string>+              <property name="toolTip">+               <string>Fill leading space of line numbers with zeroes.</string>               </property>-             </item>-             <item>               <property name="text">-               <string>ISO-8859-6</string>+               <string>Pad with zeroes</string>               </property>-             </item>-             <item>-              <property name="text">-               <string>ISO-8859-7</string>+             </widget>+            </item>+           </layout>+          </widget>+         </item>+         <item>+          <widget class="QGroupBox" name="groupDocument">+           <property name="title">+            <string>Document</string>+           </property>+           <layout class="QVBoxLayout" name="verticalLayoutDocument">+            <item>+             <widget class="QCheckBox" name="cbFragment">+              <property name="sizePolicy">+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">+                <horstretch>0</horstretch>+                <verstretch>0</verstretch>+               </sizepolicy>               </property>-             </item>-             <item>-              <property name="text">-               <string>ISO-8859-8</string>+              <property name="toolTip">+               <string>Generate output without document header and footer.</string>               </property>-             </item>-             <item>               <property name="text">-               <string>ISO-8859-9</string>+               <string>Omit header and footer</string>               </property>-             </item>-             <item>-              <property name="text">-               <string>ISO-8859-10</string>+             </widget>+            </item>+            <item>+             <widget class="QCheckBox" name="cbKeepInjections">+              <property name="toolTip">+               <string>Output any plug-in text injections even if document header and footer is omitted.</string>               </property>-             </item>-             <item>               <property name="text">-               <string>ISO-8859-11</string>+               <string>Keep Plug-In injections</string>               </property>-             </item>-             <item>-              <property name="text">-               <string>ISO-8859-12</string>+             </widget>+            </item>+            <item>+             <widget class="QCheckBox" name="cbValidateInput">+              <property name="toolTip">+               <string>Test if input data is not binary.+Removes Unicode BOM mark.</string>               </property>-             </item>-             <item>               <property name="text">-               <string>ISO-8859-13</string>+               <string>Validate input data</string>               </property>-             </item>-             <item>-              <property name="text">-               <string>ISO-8859-14</string>+             </widget>+            </item>+            <item>+             <widget class="QCheckBox" name="cbOmitVersionInfo">+              <property name="toolTip">+               <string>Generate output without version information comment.</string>               </property>-             </item>-             <item>               <property name="text">-               <string>ISO-8859-15</string>+               <string>Omit version info comment</string>               </property>-             </item>-             <item>-              <property name="text">-               <string>UTF-8</string>-              </property>-             </item>-            </widget>-           </item>-          </layout>+             </widget>+            </item>+            <item>+             <layout class="QHBoxLayout" name="horizontalLayout_2">+              <item>+               <widget class="QCheckBox" name="cbEncoding">+                <property name="toolTip">+                 <string>Set the output file encoding.</string>+                </property>+                <property name="text">+                 <string>Set encoding:</string>+                </property>+               </widget>+              </item>+              <item>+               <widget class="QComboBox" name="comboEncoding">+                <property name="toolTip">+                 <string>Select or define the encoding.+The result has to match the input file encoding.</string>+                </property>+                <property name="editable">+                 <bool>true</bool>+                </property>+                <property name="insertPolicy">+                 <enum>QComboBox::InsertAtBottom</enum>+                </property>+                <item>+                 <property name="text">+                  <string>ISO-8859-1</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-2</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-3</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-4</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-5</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-6</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-7</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-8</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-9</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-10</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-11</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-12</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-13</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-14</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>ISO-8859-15</string>+                 </property>+                </item>+                <item>+                 <property name="text">+                  <string>UTF-8</string>+                 </property>+                </item>+               </widget>+              </item>+             </layout>+            </item>+           </layout>+          </widget>          </item>          <item>           <spacer name="verticalSpacer_2">@@ -1539,90 +1515,81 @@ The result has to match the input file encoding.</string>                 </attribute>                 <layout class="QVBoxLayout" name="verticalLayout_4">                  <item>-                  <widget class="QLabel" name="label_8">-                   <property name="font">-                    <font>-                     <weight>50</weight>-                     <bold>false</bold>-                    </font>-                   </property>-                   <property name="text">-                    <string>Line numbering options:</string>-                   </property>-                  </widget>-                 </item>-                 <item>-                  <widget class="QCheckBox" name="cbHTMLAnchors">-                   <property name="toolTip">-                    <string>Add an anchor to each line.</string>-                   </property>-                   <property name="text">-                    <string>Add line anchors</string>-                   </property>-                  </widget>-                 </item>-                 <item>-                  <widget class="QCheckBox" name="cbHTMLFileNameAnchor">-                   <property name="toolTip">-                    <string>Add the filename as prefix to the anchors.</string>-                   </property>-                   <property name="text">-                    <string>Include file name in anchor</string>-                   </property>-                  </widget>-                 </item>-                 <item>-                  <widget class="QCheckBox" name="cbHTMLOrderedList">-                   <property name="toolTip">-                    <string>Output the lines within an ordered list.</string>-                   </property>-                   <property name="text">-                    <string>Output as ordered list</string>-                   </property>-                  </widget>-                 </item>-                 <item>-                  <widget class="Line" name="line">-                   <property name="orientation">-                    <enum>Qt::Horizontal</enum>-                   </property>-                  </widget>-                 </item>-                 <item>-                  <widget class="QCheckBox" name="cbHTMLIndex">-                   <property name="toolTip">-                    <string>Generate an index file with hyperlinks to all outputted files.</string>-                   </property>-                   <property name="text">-                    <string>Generate index file</string>-                   </property>-                  </widget>-                 </item>-                 <item>-                  <widget class="QCheckBox" name="cbHTMLEnclosePreTags">-                   <property name="toolTip">-                    <string>Add &amp;lt;pre&amp;gt; tags to the output, if the flag &quot;No document header and footer&quot; is selected.</string>-                   </property>-                   <property name="text">-                    <string>Enclose in pre tags</string>-                   </property>-                  </widget>-                 </item>-                 <item>-                  <widget class="Line" name="line_5">-                   <property name="orientation">-                    <enum>Qt::Horizontal</enum>+                  <widget class="QGroupBox" name="groupHTMLLineNumbering">+                   <property name="title">+                    <string>Line numbering</string>                    </property>+                   <layout class="QVBoxLayout" name="verticalLayoutHTMLLineNumbering">+                    <item>+                     <widget class="QCheckBox" name="cbHTMLAnchors">+                      <property name="toolTip">+                       <string>Add an anchor to each line.</string>+                      </property>+                      <property name="text">+                       <string>Add line anchors</string>+                      </property>+                     </widget>+                    </item>+                    <item>+                     <widget class="QCheckBox" name="cbHTMLFileNameAnchor">+                      <property name="toolTip">+                       <string>Add the filename as prefix to the anchors.</string>+                      </property>+                      <property name="text">+                       <string>Include file name in anchor</string>+                      </property>+                     </widget>+                    </item>+                    <item>+                     <widget class="QCheckBox" name="cbHTMLOrderedList">+                      <property name="toolTip">+                       <string>Output the lines within an ordered list.</string>+                      </property>+                      <property name="text">+                       <string>Output as ordered list</string>+                      </property>+                     </widget>+                    </item>+                   </layout>                   </widget>                  </item>                  <item>-                  <widget class="QCheckBox" name="cbHTMLPasteMIME">-                   <property name="toolTip">-                    <string>Add HTML MIME Type when copying code to the clipboard</string>-                   </property>-                   <property name="text">-                    <string>Copy with MIME type</string>+                  <widget class="QGroupBox" name="groupHTMLOutput">+                   <property name="title">+                    <string>Output</string>                    </property>+                   <layout class="QVBoxLayout" name="verticalLayoutHTMLOutput">+                    <item>+                     <widget class="QCheckBox" name="cbHTMLIndex">+                      <property name="toolTip">+                       <string>Generate an index file with hyperlinks to all outputted files.</string>+                      </property>+                      <property name="text">+                       <string>Generate index file</string>+                      </property>+                     </widget>+                    </item>+                    <item>+                     <widget class="QCheckBox" name="cbHTMLEnclosePreTags">+                      <property name="toolTip">+                       <string>Add &amp;lt;pre&amp;gt; tags to the output, if the flag &quot;No document header and footer&quot; is selected.</string>+                      </property>+                      <property name="text">+                       <string>Enclose in pre tags</string>+                      </property>+                     </widget>+                    </item>+                    <item>+                     <widget class="QCheckBox" name="cbHTMLPasteMIME">+                      <property name="toolTip">+                       <string>Add HTML MIME Type when copying code to the clipboard</string>+                      </property>+                      <property name="text">+                       <string>Copy with MIME type</string>+                      </property>+                     </widget>+                    </item>+                   </layout>                   </widget>                  </item>                  <item>@@ -1647,143 +1614,154 @@ The result has to match the input file encoding.</string>            <widget class="QWidget" name="LATEXOptions">             <layout class="QVBoxLayout" name="verticalLayout_12">              <item>-              <widget class="QCheckBox" name="cbLATEXEscQuotes">-               <property name="toolTip">-                <string>Replace quotes by dq sequences.</string>-               </property>-               <property name="text">-                <string>Escape quotes</string>-               </property>-              </widget>-             </item>-             <item>-              <widget class="QCheckBox" name="cbLATEXBabel">-               <property name="toolTip">-                <string>Adapt output for the Babel package</string>-               </property>-               <property name="text">-                <string>Add Babel compatibility</string>-               </property>-              </widget>-             </item>-             <item>-              <widget class="QCheckBox" name="cbLATEXBeamer">-               <property name="toolTip">-                <string>Adapt output for the Beamer package</string>-               </property>-               <property name="text">-                <string>Add Beamer compatibility</string>-               </property>-              </widget>-             </item>-             <item>-              <widget class="QCheckBox" name="cbLATEXPrettySymbols">-               <property name="toolTip">-                <string>Replace default symbols (brackets, tilde) by nice redefinitions.</string>-               </property>-               <property name="text">-                <string>Add pretty symbols</string>-               </property>-              </widget>-             </item>-             <item>-              <widget class="Line" name="line_4">-               <property name="orientation">-                <enum>Qt::Horizontal</enum>+              <widget class="QGroupBox" name="groupLATEXCompatibility">+               <property name="title">+                <string>Compatibility</string>                </property>+               <layout class="QVBoxLayout" name="verticalLayoutLATEXCompatibility">+                <item>+                 <widget class="QCheckBox" name="cbLATEXEscQuotes">+                  <property name="toolTip">+                   <string>Replace quotes by dq sequences.</string>+                  </property>+                  <property name="text">+                   <string>Escape quotes</string>+                  </property>+                 </widget>+                </item>+                <item>+                 <widget class="QCheckBox" name="cbLATEXBabel">+                  <property name="toolTip">+                   <string>Adapt output for the Babel package</string>+                  </property>+                  <property name="text">+                   <string>Add Babel compatibility</string>+                  </property>+                 </widget>+                </item>+                <item>+                 <widget class="QCheckBox" name="cbLATEXBeamer">+                  <property name="toolTip">+                   <string>Adapt output for the Beamer package</string>+                  </property>+                  <property name="text">+                   <string>Add Beamer compatibility</string>+                  </property>+                 </widget>+                </item>+                <item>+                 <widget class="QCheckBox" name="cbLATEXPrettySymbols">+                  <property name="toolTip">+                   <string>Replace default symbols (brackets, tilde) by nice redefinitions.</string>+                  </property>+                  <property name="text">+                   <string>Add pretty symbols</string>+                  </property>+                 </widget>+                </item>+               </layout>               </widget>              </item>              <item>-              <widget class="QCheckBox" name="cbLATEXEmbedStyle">-               <property name="toolTip">-                <string>Include the style information in each output file.</string>-               </property>-               <property name="text">-                <string>Embed style (defs)</string>+              <widget class="QGroupBox" name="groupLATEXStylesheet">+               <property name="title">+                <string>Stylesheet</string>                </property>+               <layout class="QVBoxLayout" name="verticalLayoutLATEXStylesheet">+                <item>+                 <widget class="QCheckBox" name="cbLATEXEmbedStyle">+                  <property name="toolTip">+                   <string>Include the style information in each output file.</string>+                  </property>+                  <property name="text">+                   <string>Embed style (defs)</string>+                  </property>+                 </widget>+                </item>+                <item>+                 <layout class="QHBoxLayout" name="horizontalLayout_17">+                  <item>+                   <widget class="QLabel" name="label_21">+                    <property name="text">+                     <string>Stylesheet file:</string>+                    </property>+                    <property name="buddy">+                     <cstring>leLATEXStyleFile</cstring>+                    </property>+                   </widget>+                  </item>+                  <item>+                   <widget class="QLineEdit" name="leLATEXStyleFile">+                    <property name="maximumSize">+                     <size>+                      <width>100</width>+                      <height>16777215</height>+                     </size>+                    </property>+                    <property name="toolTip">+                     <string>Name of the referenced  style file.</string>+                    </property>+                    <property name="text">+                     <string>highlight.sty</string>+                    </property>+                   </widget>+                  </item>+                 </layout>+                </item>+                <item>+                 <layout class="QHBoxLayout" name="horizontalLayout_15">+                  <item>+                   <widget class="QLabel" name="label_22">+                    <property name="text">+                     <string>Stylesheet include file:</string>+                    </property>+                   </widget>+                  </item>+                  <item>+                   <spacer name="horizontalSpacer_2">+                    <property name="orientation">+                     <enum>Qt::Horizontal</enum>+                    </property>+                    <property name="sizeHint" stdset="0">+                     <size>+                      <width>40</width>+                      <height>20</height>+                     </size>+                    </property>+                   </spacer>+                  </item>+                 </layout>+                </item>+                <item>+                 <layout class="QHBoxLayout" name="horizontalLayout_16">+                  <item>+                   <widget class="QLineEdit" name="leLATEXStyleIncFile">+                    <property name="toolTip">+                     <string>Path of the style include file.</string>+                    </property>+                   </widget>+                  </item>+                  <item>+                   <widget class="QPushButton" name="pbLATEXChooseStyleIncFile">+                    <property name="minimumSize">+                     <size>+                      <width>20</width>+                      <height>0</height>+                     </size>+                    </property>+                    <property name="toolTip">+                     <string>Select a style include file.</string>+                    </property>+                    <property name="text">+                     <string>...</string>+                    </property>+                   </widget>+                  </item>+                 </layout>+                </item>+               </layout>               </widget>              </item>-             <item>-              <layout class="QHBoxLayout" name="horizontalLayout_17">-               <item>-                <widget class="QLabel" name="label_21">-                 <property name="text">-                  <string>Stylesheet file:</string>-                 </property>-                 <property name="buddy">-                  <cstring>leLATEXStyleFile</cstring>-                 </property>-                </widget>-               </item>-               <item>-                <widget class="QLineEdit" name="leLATEXStyleFile">-                 <property name="maximumSize">-                  <size>-                   <width>100</width>-                   <height>16777215</height>-                  </size>-                 </property>-                 <property name="toolTip">-                  <string>Name of the referenced  style file.</string>-                 </property>-                 <property name="text">-                  <string>highlight.sty</string>-                 </property>-                </widget>-               </item>-              </layout>-             </item>-             <item>-              <layout class="QHBoxLayout" name="horizontalLayout_15">-               <item>-                <widget class="QLabel" name="label_22">-                 <property name="text">-                  <string>Stylesheet include file:</string>-                 </property>-                </widget>-               </item>-               <item>-                <spacer name="horizontalSpacer_2">-                 <property name="orientation">-                  <enum>Qt::Horizontal</enum>-                 </property>-                 <property name="sizeHint" stdset="0">-                  <size>-                   <width>40</width>-                   <height>20</height>-                  </size>-                 </property>-                </spacer>-               </item>-              </layout>-             </item>-             <item>-              <layout class="QHBoxLayout" name="horizontalLayout_16">-               <item>-                <widget class="QLineEdit" name="leLATEXStyleIncFile">-                 <property name="toolTip">-                  <string>Path of the style include file.</string>-                 </property>-                </widget>-               </item>-               <item>-                <widget class="QPushButton" name="pbLATEXChooseStyleIncFile">-                 <property name="minimumSize">-                  <size>-                   <width>20</width>-                   <height>0</height>-                  </size>-                 </property>-                 <property name="toolTip">-                  <string>Select a style include file.</string>-                 </property>-                 <property name="text">-                  <string>...</string>-                 </property>-                </widget>-               </item>-              </layout>-             </item>              <item>               <spacer name="verticalSpacer_4">                <property name="orientation">@@ -1802,96 +1780,105 @@ The result has to match the input file encoding.</string>            <widget class="QWidget" name="TEXOptions">             <layout class="QVBoxLayout" name="verticalLayout_14">              <item>-              <widget class="QCheckBox" name="cbTEXEmbedStyle">-               <property name="toolTip">-                <string>Include the style information in each output file.</string>-               </property>-               <property name="text">-                <string>Embed style (macros)</string>+              <widget class="QGroupBox" name="groupTEXStylesheet">+               <property name="title">+                <string>Stylesheet</string>                </property>+               <layout class="QVBoxLayout" name="verticalLayoutTEXStylesheet">+                <item>+                 <widget class="QCheckBox" name="cbTEXEmbedStyle">+                  <property name="toolTip">+                   <string>Include the style information in each output file.</string>+                  </property>+                  <property name="text">+                   <string>Embed style (macros)</string>+                  </property>+                 </widget>+                </item>+                <item>+                 <layout class="QHBoxLayout" name="horizontalLayout_18">+                  <item>+                   <widget class="QLabel" name="label_24">+                    <property name="text">+                     <string>Stylesheet file:</string>+                    </property>+                    <property name="buddy">+                     <cstring>leTEXStyleFile</cstring>+                    </property>+                   </widget>+                  </item>+                  <item>+                   <widget class="QLineEdit" name="leTEXStyleFile">+                    <property name="maximumSize">+                     <size>+                      <width>100</width>+                      <height>16777215</height>+                     </size>+                    </property>+                    <property name="toolTip">+                     <string>Name of the referenced style file.</string>+                    </property>+                    <property name="text">+                     <string>highlight.sty</string>+                    </property>+                   </widget>+                  </item>+                 </layout>+                </item>+                <item>+                 <layout class="QHBoxLayout" name="horizontalLayout_19">+                  <item>+                   <widget class="QLabel" name="label_25">+                    <property name="text">+                     <string>Stylesheet include file:</string>+                    </property>+                   </widget>+                  </item>+                  <item>+                   <spacer name="horizontalSpacer_3">+                    <property name="orientation">+                     <enum>Qt::Horizontal</enum>+                    </property>+                    <property name="sizeHint" stdset="0">+                     <size>+                      <width>40</width>+                      <height>20</height>+                     </size>+                    </property>+                   </spacer>+                  </item>+                 </layout>+                </item>+                <item>+                 <layout class="QHBoxLayout" name="horizontalLayout_20">+                  <item>+                   <widget class="QLineEdit" name="leTEXStyleIncFile">+                    <property name="toolTip">+                     <string>Path of the style include file.</string>+                    </property>+                   </widget>+                  </item>+                  <item>+                   <widget class="QPushButton" name="pbTEXChooseStyleIncFile">+                    <property name="minimumSize">+                     <size>+                      <width>20</width>+                      <height>0</height>+                     </size>+                    </property>+                    <property name="toolTip">+                     <string>Select a style include file.</string>+                    </property>+                    <property name="text">+                     <string>...</string>+                    </property>+                   </widget>+                  </item>+                 </layout>+                </item>+               </layout>               </widget>              </item>-             <item>-              <layout class="QHBoxLayout" name="horizontalLayout_18">-               <item>-                <widget class="QLabel" name="label_24">-                 <property name="text">-                  <string>Stylesheet file:</string>-                 </property>-                 <property name="buddy">-                  <cstring>leTEXStyleFile</cstring>-                 </property>-                </widget>-               </item>-               <item>-                <widget class="QLineEdit" name="leTEXStyleFile">-                 <property name="maximumSize">-                  <size>-                   <width>100</width>-                   <height>16777215</height>-                  </size>-                 </property>-                 <property name="toolTip">-                  <string>Name of the referenced style file.</string>-                 </property>-                 <property name="text">-                  <string>highlight.sty</string>-                 </property>-                </widget>-               </item>-              </layout>-             </item>-             <item>-              <layout class="QHBoxLayout" name="horizontalLayout_19">-               <item>-                <widget class="QLabel" name="label_25">-                 <property name="text">-                  <string>Stylesheet include file:</string>-                 </property>-                </widget>-               </item>-               <item>-                <spacer name="horizontalSpacer_3">-                 <property name="orientation">-                  <enum>Qt::Horizontal</enum>-                 </property>-                 <property name="sizeHint" stdset="0">-                  <size>-                   <width>40</width>-                   <height>20</height>-                  </size>-                 </property>-                </spacer>-               </item>-              </layout>-             </item>-             <item>-              <layout class="QHBoxLayout" name="horizontalLayout_20">-               <item>-                <widget class="QLineEdit" name="leTEXStyleIncFile">-                 <property name="toolTip">-                  <string>Path of the style include file.</string>-                 </property>-                </widget>-               </item>-               <item>-                <widget class="QPushButton" name="pbTEXChooseStyleIncFile">-                 <property name="minimumSize">-                  <size>-                   <width>20</width>-                   <height>0</height>-                  </size>-                 </property>-                 <property name="toolTip">-                  <string>Select a style include file.</string>-                 </property>-                 <property name="text">-                  <string>...</string>-                 </property>-                </widget>-               </item>-              </layout>-             </item>              <item>               <spacer name="verticalSpacer_5">                <property name="orientation">@@ -2015,178 +2002,185 @@ You can select the stylesheets in your word processor to reformat additional tex            <widget class="QWidget" name="SVGOptions">             <layout class="QVBoxLayout" name="verticalLayout_8">              <item>-              <layout class="QHBoxLayout" name="horizontalLayout_12">-               <item>-                <widget class="QLabel" name="label_3">-                 <property name="text">-                  <string>I&amp;mage width:</string>-                 </property>-                 <property name="buddy">-                  <cstring>leSVGWidth</cstring>-                 </property>-                </widget>-               </item>-               <item>-                <widget class="QLineEdit" name="leSVGWidth">-                 <property name="sizePolicy">-                  <sizepolicy hsizetype="Expanding" vsizetype="Fixed">-                   <horstretch>0</horstretch>-                   <verstretch>0</verstretch>-                  </sizepolicy>-                 </property>-                 <property name="minimumSize">-                  <size>-                   <width>50</width>-                   <height>0</height>-                  </size>-                 </property>-                 <property name="maximumSize">-                  <size>-                   <width>50</width>-                   <height>16777215</height>-                  </size>-                 </property>-                 <property name="toolTip">-                  <string>Enter the SVG width (may contain units).</string>-                 </property>-                </widget>-               </item>-               <item>-                <spacer name="horizontalSpacer">-                 <property name="orientation">-                  <enum>Qt::Horizontal</enum>-                 </property>-                 <property name="sizeHint" stdset="0">-                  <size>-                   <width>18</width>-                   <height>20</height>-                  </size>-                 </property>-                </spacer>-               </item>-               <item>-                <widget class="QLabel" name="label_12">-                 <property name="text">-                  <string>Height:</string>-                 </property>-                 <property name="buddy">-                  <cstring>leSVGHeight</cstring>-                 </property>-                </widget>-               </item>-               <item>-                <widget class="QLineEdit" name="leSVGHeight">-                 <property name="maximumSize">-                  <size>-                   <width>50</width>-                   <height>16777215</height>-                  </size>-                 </property>-                 <property name="toolTip">-                  <string>Enter the SVG height (may contain units).</string>-                 </property>-                </widget>-               </item>-              </layout>-             </item>-             <item>-              <widget class="Line" name="line_3">-               <property name="orientation">-                <enum>Qt::Horizontal</enum>+              <widget class="QGroupBox" name="groupSVGImageSize">+               <property name="title">+                <string>Image size</string>                </property>+               <layout class="QHBoxLayout" name="horizontalLayout_12">+                <item>+                 <widget class="QLabel" name="label_3">+                  <property name="text">+                   <string>I&amp;mage width:</string>+                  </property>+                  <property name="buddy">+                   <cstring>leSVGWidth</cstring>+                  </property>+                 </widget>+                </item>+                <item>+                 <widget class="QLineEdit" name="leSVGWidth">+                  <property name="sizePolicy">+                   <sizepolicy hsizetype="Expanding" vsizetype="Fixed">+                    <horstretch>0</horstretch>+                    <verstretch>0</verstretch>+                   </sizepolicy>+                  </property>+                  <property name="minimumSize">+                   <size>+                    <width>50</width>+                    <height>0</height>+                   </size>+                  </property>+                  <property name="maximumSize">+                   <size>+                    <width>50</width>+                    <height>16777215</height>+                   </size>+                  </property>+                  <property name="toolTip">+                   <string>Enter the SVG width (may contain units).</string>+                  </property>+                 </widget>+                </item>+                <item>+                 <spacer name="horizontalSpacer">+                  <property name="orientation">+                   <enum>Qt::Horizontal</enum>+                  </property>+                  <property name="sizeHint" stdset="0">+                   <size>+                    <width>18</width>+                    <height>20</height>+                   </size>+                  </property>+                 </spacer>+                </item>+                <item>+                 <widget class="QLabel" name="label_12">+                  <property name="text">+                   <string>Height:</string>+                  </property>+                  <property name="buddy">+                   <cstring>leSVGHeight</cstring>+                  </property>+                 </widget>+                </item>+                <item>+                 <widget class="QLineEdit" name="leSVGHeight">+                  <property name="maximumSize">+                   <size>+                    <width>50</width>+                    <height>16777215</height>+                   </size>+                  </property>+                  <property name="toolTip">+                   <string>Enter the SVG height (may contain units).</string>+                  </property>+                 </widget>+                </item>+               </layout>               </widget>              </item>              <item>-              <widget class="QCheckBox" name="cbSVGEmbedStyle">-               <property name="toolTip">-                <string>Include the style information in each output file.</string>-               </property>-               <property name="text">-                <string>Embed style (CSS)</string>+              <widget class="QGroupBox" name="groupSVGStylesheet">+               <property name="title">+                <string>Stylesheet</string>                </property>+               <layout class="QVBoxLayout" name="verticalLayoutSVGStylesheet">+                <item>+                 <widget class="QCheckBox" name="cbSVGEmbedStyle">+                  <property name="toolTip">+                   <string>Include the style information in each output file.</string>+                  </property>+                  <property name="text">+                   <string>Embed style (CSS)</string>+                  </property>+                 </widget>+                </item>+                <item>+                 <layout class="QHBoxLayout" name="horizontalLayout_26">+                  <item>+                   <widget class="QLabel" name="label_29">+                    <property name="text">+                     <string>Stylesheet file:</string>+                    </property>+                    <property name="buddy">+                     <cstring>leSVGStyleFile</cstring>+                    </property>+                   </widget>+                  </item>+                  <item>+                   <widget class="QLineEdit" name="leSVGStyleFile">+                    <property name="maximumSize">+                     <size>+                      <width>100</width>+                      <height>16777215</height>+                     </size>+                    </property>+                    <property name="toolTip">+                     <string>Name of the referenced style file.</string>+                    </property>+                    <property name="text">+                     <string>highlight.css</string>+                    </property>+                   </widget>+                  </item>+                 </layout>+                </item>+                <item>+                 <layout class="QHBoxLayout" name="horizontalLayout_27">+                  <item>+                   <widget class="QLabel" name="label_30">+                    <property name="text">+                     <string>Stylesheet include file:</string>+                    </property>+                   </widget>+                  </item>+                  <item>+                   <spacer name="horizontalSpacer_6">+                    <property name="orientation">+                     <enum>Qt::Horizontal</enum>+                    </property>+                    <property name="sizeHint" stdset="0">+                     <size>+                      <width>40</width>+                      <height>20</height>+                     </size>+                    </property>+                   </spacer>+                  </item>+                 </layout>+                </item>+                <item>+                 <layout class="QHBoxLayout" name="horizontalLayout_28">+                  <item>+                   <widget class="QLineEdit" name="leSVGStyleIncFile">+                    <property name="toolTip">+                     <string>Path of the CSS include file.</string>+                    </property>+                   </widget>+                  </item>+                  <item>+                   <widget class="QPushButton" name="pbSVGChooseStyleIncFile">+                    <property name="minimumSize">+                     <size>+                      <width>20</width>+                      <height>0</height>+                     </size>+                    </property>+                    <property name="toolTip">+                     <string>Select a style include file.</string>+                    </property>+                    <property name="text">+                     <string>...</string>+                    </property>+                   </widget>+                  </item>+                 </layout>+                </item>+               </layout>               </widget>              </item>-             <item>-              <layout class="QHBoxLayout" name="horizontalLayout_26">-               <item>-                <widget class="QLabel" name="label_29">-                 <property name="text">-                  <string>Stylesheet file:</string>-                 </property>-                 <property name="buddy">-                  <cstring>leSVGStyleFile</cstring>-                 </property>-                </widget>-               </item>-               <item>-                <widget class="QLineEdit" name="leSVGStyleFile">-                 <property name="maximumSize">-                  <size>-                   <width>100</width>-                   <height>16777215</height>-                  </size>-                 </property>-                 <property name="toolTip">-                  <string>Name of the referenced style file.</string>-                 </property>-                 <property name="text">-                  <string>highlight.css</string>-                 </property>-                </widget>-               </item>-              </layout>-             </item>-             <item>-              <layout class="QHBoxLayout" name="horizontalLayout_27">-               <item>-                <widget class="QLabel" name="label_30">-                 <property name="text">-                  <string>Stylesheet include file:</string>-                 </property>-                </widget>-               </item>-               <item>-                <spacer name="horizontalSpacer_6">-                 <property name="orientation">-                  <enum>Qt::Horizontal</enum>-                 </property>-                 <property name="sizeHint" stdset="0">-                  <size>-                   <width>40</width>-                   <height>20</height>-                  </size>-                 </property>-                </spacer>-               </item>-              </layout>-             </item>-             <item>-              <layout class="QHBoxLayout" name="horizontalLayout_28">-               <item>-                <widget class="QLineEdit" name="leSVGStyleIncFile">-                 <property name="toolTip">-                  <string>Path of the CSS include file.</string>-                 </property>-                </widget>-               </item>-               <item>-                <widget class="QPushButton" name="pbSVGChooseStyleIncFile">-                 <property name="minimumSize">-                  <size>-                   <width>20</width>-                   <height>0</height>-                  </size>-                 </property>-                 <property name="toolTip">-                  <string>Select a style include file.</string>-                 </property>-                 <property name="text">-                  <string>...</string>-                 </property>-                </widget>-               </item>-              </layout>-             </item>              <item>               <spacer name="verticalSpacer_10">                <property name="orientation">@@ -2225,362 +2219,444 @@ You can select the stylesheets in your word processor to reformat additional tex               </spacer>              </item>             </layout>-           </widget>-          </widget>-         </item>-        </layout>-       </widget>-       <widget class="QWidget" name="page_formatting">-        <attribute name="title">-         <string>Formatting</string>-        </attribute>-        <layout class="QVBoxLayout" name="verticalLayout_6">-         <item>-          <layout class="QHBoxLayout" name="horizontalLayout_3">-           <property name="spacing">-            <number>6</number>-           </property>-           <item>-            <widget class="QLabel" name="label_5">-             <property name="sizePolicy">-              <sizepolicy hsizetype="Minimum" vsizetype="Minimum">-               <horstretch>0</horstretch>-               <verstretch>0</verstretch>-              </sizepolicy>-             </property>-             <property name="minimumSize">-              <size>-               <width>110</width>-               <height>0</height>-              </size>-             </property>-             <property name="maximumSize">-              <size>-               <width>110</width>-               <height>16777215</height>-              </size>-             </property>-             <property name="text">-              <string>Color theme:</string>-             </property>-             <property name="buddy">-              <cstring>comboTheme</cstring>-             </property>-            </widget>-           </item>-           <item>-            <spacer name="horizontalSpacer_7">-             <property name="orientation">-              <enum>Qt::Horizontal</enum>-             </property>-             <property name="sizeType">-              <enum>QSizePolicy::Expanding</enum>-             </property>-             <property name="sizeHint" stdset="0">-              <size>-               <width>40</width>-               <height>20</height>-              </size>-             </property>-            </spacer>-           </item>-           <item>-            <widget class="QComboBox" name="comboThemeFilter"/>-           </item>-           <item>-            <widget class="QComboBox" name="comboTheme">-             <property name="sizePolicy">-              <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">-               <horstretch>0</horstretch>-               <verstretch>0</verstretch>-              </sizepolicy>-             </property>-             <property name="minimumSize">-              <size>-               <width>120</width>-               <height>0</height>-              </size>-             </property>-             <property name="maximumSize">-              <size>-               <width>200</width>-               <height>16777215</height>-              </size>-             </property>-             <property name="toolTip">-              <string>Select a colour theme.</string>-             </property>-             <property name="currentIndex">-              <number>-1</number>-             </property>-             <property name="insertPolicy">-              <enum>QComboBox::InsertAlphabetically</enum>-             </property>-             <property name="sizeAdjustPolicy">-              <enum>QComboBox::AdjustToContents</enum>-             </property>-            </widget>-           </item>-          </layout>-         </item>-         <item>-          <layout class="QHBoxLayout" name="horizontalLayout_4">-           <item>-            <widget class="QCheckBox" name="cbReformat">-             <property name="toolTip">-              <string>Reformat and indent your code.-This feature is enabled for C, C++, C# and Java code.</string>-             </property>-             <property name="text">-              <string>Reformat:</string>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QComboBox" name="comboReformat">-             <property name="sizePolicy">-              <sizepolicy hsizetype="Minimum" vsizetype="Fixed">-               <horstretch>0</horstretch>-               <verstretch>0</verstretch>-              </sizepolicy>-             </property>-             <property name="maximumSize">-              <size>-               <width>120</width>-               <height>16777215</height>-              </size>-             </property>-             <property name="toolTip">-              <string>Choose a formatting scheme.</string>-             </property>-             <property name="maxVisibleItems">-              <number>10</number>-             </property>-            </widget>-           </item>-          </layout>-         </item>-         <item>-          <layout class="QHBoxLayout" name="horizontalLayout_5">-           <item>-            <widget class="QCheckBox" name="cbKwCase">-             <property name="toolTip">-              <string>Change the keyword case.</string>-             </property>-             <property name="text">-              <string>Keyword case:</string>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QComboBox" name="comboKwCase">-             <property name="sizePolicy">-              <sizepolicy hsizetype="Minimum" vsizetype="Fixed">-               <horstretch>0</horstretch>-               <verstretch>0</verstretch>-              </sizepolicy>-             </property>-             <property name="maximumSize">-              <size>-               <width>120</width>-               <height>16777215</height>-              </size>-             </property>-             <property name="toolTip">-              <string>Select a keyword case.</string>-             </property>-             <property name="sizeAdjustPolicy">-              <enum>QComboBox::AdjustToContents</enum>-             </property>-             <item>-              <property name="text">-               <string>UPPER</string>-              </property>-             </item>-             <item>-              <property name="text">-               <string>lower</string>-              </property>-             </item>-             <item>-              <property name="text">-               <string>Capitalize</string>-              </property>-             </item>-            </widget>-           </item>-          </layout>-         </item>-         <item>-          <layout class="QHBoxLayout" name="horizontalLayout_6">-           <item>-            <widget class="QLabel" name="label_6">-             <property name="sizePolicy">-              <sizepolicy hsizetype="Minimum" vsizetype="Fixed">-               <horstretch>0</horstretch>-               <verstretch>0</verstretch>-              </sizepolicy>-             </property>-             <property name="text">-              <string>Tab width:</string>-             </property>-             <property name="buddy">-              <cstring>sbTabWidth</cstring>-             </property>-            </widget>-           </item>-           <item>-            <widget class="QSpinBox" name="sbTabWidth">-             <property name="maximumSize">-              <size>-               <width>120</width>-               <height>16777215</height>-              </size>-             </property>-             <property name="toolTip">-              <string>Enter the number of spaces which replace a tab.-Set the width to 0 to keep tabs.</string>-             </property>-             <property name="maximum">-              <number>10</number>-             </property>-            </widget>-           </item>-          </layout>+           </widget>+          </widget>          </item>+        </layout>+       </widget>+       <widget class="QWidget" name="page_formatting">+        <attribute name="title">+         <string>Formatting</string>+        </attribute>+        <layout class="QVBoxLayout" name="verticalLayout_6">          <item>-          <layout class="QGridLayout" name="gridLayout_2">-           <item row="0" column="0">-            <widget class="QCheckBox" name="cbWrapping">-             <property name="toolTip">-              <string>Enable line wrapping.</string>-             </property>-             <property name="text">-              <string>Line wrapping</string>+          <layout class="QHBoxLayout" name="horizontalLayout_3">+           <item>+            <widget class="QLabel" name="label_5">+             <property name="sizePolicy">+              <sizepolicy hsizetype="Minimum" vsizetype="Minimum">+               <horstretch>0</horstretch>+               <verstretch>0</verstretch>+              </sizepolicy>              </property>-            </widget>-           </item>-           <item row="0" column="1">-            <widget class="QSpinBox" name="sbLineLength">-             <property name="maximumSize">+             <property name="minimumSize">               <size>-               <width>60</width>-               <height>16777215</height>+               <width>110</width>+               <height>0</height>               </size>              </property>-             <property name="toolTip">-              <string>Enter the maximum line length.</string>-             </property>-             <property name="minimum">-              <number>60</number>-             </property>-             <property name="maximum">-              <number>120</number>-             </property>-             <property name="singleStep">-              <number>2</number>-             </property>-            </widget>-           </item>-           <item row="1" column="0" colspan="2">-            <widget class="QCheckBox" name="cbAdvWrapping">-             <property name="enabled">-              <bool>false</bool>-             </property>-             <property name="toolTip">-              <string>Indent statements and function parameters after wrapping.</string>-             </property>-             <property name="text">-              <string>Intelligent wrapping</string>-             </property>-            </widget>-           </item>-           <item row="2" column="0" colspan="2">-            <widget class="QCheckBox" name="cbOmitWrappedLineNumbers">-             <property name="toolTip">-              <string>Do not add line numbering to lines which were automatically wrapped.</string>-             </property>-             <property name="text">-              <string>Omit line numbers of wrapped lines</string>-             </property>-            </widget>-           </item>-          </layout>-         </item>-         <item>-          <layout class="QGridLayout" name="gridLayout_9">-           <item row="0" column="0">-            <widget class="QLabel" name="label_23">-             <property name="text">-              <string>Font na&amp;me:</string>-             </property>-             <property name="buddy">-              <cstring>comboFontName</cstring>-             </property>-            </widget>-           </item>-           <item row="0" column="1">-            <widget class="QFontComboBox" name="comboFontName">              <property name="maximumSize">               <size>-               <width>150</width>+               <width>110</width>                <height>16777215</height>               </size>              </property>-             <property name="font">-              <font/>-             </property>-             <property name="toolTip">-              <string>Select or enter the font name. HTML supports a list of fonts, separated with comma.</string>-             </property>-             <property name="fontFilters">-              <set>QFontComboBox::MonospacedFonts</set>-             </property>-             <property name="currentFont">-              <font>-               <family>Consolas</family>-              </font>-             </property>-            </widget>-           </item>-           <item row="1" column="0">-            <widget class="QLabel" name="label_4">              <property name="text">-              <string>Font si&amp;ze:</string>+              <string>Color theme:</string>              </property>              <property name="buddy">-              <cstring>leFontSize</cstring>+              <cstring>leThemeSearch</cstring>              </property>             </widget>            </item>-           <item row="1" column="1">-            <widget class="QLineEdit" name="leFontSize">-             <property name="sizePolicy">-              <sizepolicy hsizetype="Preferred" vsizetype="Fixed">-               <horstretch>0</horstretch>-               <verstretch>0</verstretch>-              </sizepolicy>-             </property>-             <property name="maximumSize">-              <size>-               <width>150</width>-               <height>16777215</height>-              </size>-             </property>+           <item>+            <widget class="QLineEdit" name="leThemeSearch">              <property name="toolTip">-              <string>Enter the font size.</string>+              <string>Filter themes by name or category (e.g. light, dark, base16).</string>              </property>-             <property name="text">-              <string>10</string>+             <property name="placeholderText">+              <string>Search themes (name, light, dark, base16...)</string>+             </property>+             <property name="clearButtonEnabled">+              <bool>true</bool>              </property>             </widget>            </item>           </layout>          </item>+         <item>+          <widget class="QListView" name="lvThemes">+           <property name="sizePolicy">+            <sizepolicy hsizetype="Expanding" vsizetype="Expanding">+             <horstretch>0</horstretch>+             <verstretch>1</verstretch>+            </sizepolicy>+           </property>+           <property name="minimumSize">+            <size>+             <width>0</width>+             <height>200</height>+            </size>+           </property>+           <property name="toolTip">+            <string>Select a colour theme.</string>+           </property>+           <property name="editTriggers">+            <set>QAbstractItemView::NoEditTriggers</set>+           </property>+           <property name="selectionMode">+            <enum>QAbstractItemView::SingleSelection</enum>+           </property>+           <property name="verticalScrollMode">+            <enum>QAbstractItemView::ScrollPerPixel</enum>+           </property>+           <property name="movement">+            <enum>QListView::Static</enum>+           </property>+           <property name="flow">+            <enum>QListView::LeftToRight</enum>+           </property>+           <property name="isWrapping" stdset="0">+            <bool>true</bool>+           </property>+           <property name="resizeMode">+            <enum>QListView::Adjust</enum>+           </property>+           <property name="spacing">+            <number>2</number>+           </property>+           <property name="viewMode">+            <enum>QListView::IconMode</enum>+           </property>+           <property name="uniformItemSizes">+            <bool>true</bool>+           </property>+          </widget>+         </item>+         <item>+          <widget class="QGroupBox" name="groupCodeFormatting">+           <property name="title">+            <string>Code formatting</string>+           </property>+           <layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1">+            <item row="0" column="0">+             <widget class="QCheckBox" name="cbReformat">+              <property name="toolTip">+               <string>Reformat and indent your code.+This feature is enabled for C, C++, C# and Java code.</string>+              </property>+              <property name="text">+               <string>Reformat:</string>+              </property>+             </widget>+            </item>+            <item row="0" column="1">+             <widget class="QComboBox" name="comboReformat">+              <property name="sizePolicy">+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">+                <horstretch>0</horstretch>+                <verstretch>0</verstretch>+               </sizepolicy>+              </property>+              <property name="maximumSize">+               <size>+                <width>120</width>+                <height>16777215</height>+               </size>+              </property>+              <property name="toolTip">+               <string>Choose a formatting scheme.</string>+              </property>+              <property name="maxVisibleItems">+               <number>10</number>+              </property>+             </widget>+            </item>+            <item row="1" column="0">+             <widget class="QCheckBox" name="cbKwCase">+              <property name="toolTip">+               <string>Change the keyword case.</string>+              </property>+              <property name="text">+               <string>Keyword case:</string>+              </property>+             </widget>+            </item>+            <item row="1" column="1">+             <widget class="QComboBox" name="comboKwCase">+              <property name="sizePolicy">+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">+                <horstretch>0</horstretch>+                <verstretch>0</verstretch>+               </sizepolicy>+              </property>+              <property name="maximumSize">+               <size>+                <width>120</width>+                <height>16777215</height>+               </size>+              </property>+              <property name="toolTip">+               <string>Select a keyword case.</string>+              </property>+              <property name="sizeAdjustPolicy">+               <enum>QComboBox::AdjustToContents</enum>+              </property>+              <item>+               <property name="text">+                <string>UPPER</string>+               </property>+              </item>+              <item>+               <property name="text">+                <string>lower</string>+               </property>+              </item>+              <item>+               <property name="text">+                <string>Capitalize</string>+               </property>+              </item>+             </widget>+            </item>+            <item row="2" column="0">+             <widget class="QLabel" name="label_6">+              <property name="sizePolicy">+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">+                <horstretch>0</horstretch>+                <verstretch>0</verstretch>+               </sizepolicy>+              </property>+              <property name="text">+               <string>Tab width:</string>+              </property>+              <property name="buddy">+               <cstring>sbTabWidth</cstring>+              </property>+             </widget>+            </item>+            <item row="2" column="1">+             <widget class="QSpinBox" name="sbTabWidth">+              <property name="maximumSize">+               <size>+                <width>120</width>+                <height>16777215</height>+               </size>+              </property>+              <property name="toolTip">+               <string>Enter the number of spaces which replace a tab.+Set the width to 0 to keep tabs.</string>+              </property>+              <property name="maximum">+               <number>10</number>+              </property>+             </widget>+            </item>+            <item row="3" column="0">+             <widget class="QCheckBox" name="cbWrapping">+              <property name="toolTip">+               <string>Enable line wrapping.</string>+              </property>+              <property name="text">+               <string>Line wrapping</string>+              </property>+             </widget>+            </item>+            <item row="3" column="1">+             <widget class="QSpinBox" name="sbLineLength">+              <property name="maximumSize">+               <size>+                <width>60</width>+                <height>16777215</height>+               </size>+              </property>+              <property name="toolTip">+               <string>Enter the maximum line length.</string>+              </property>+              <property name="minimum">+               <number>60</number>+              </property>+              <property name="maximum">+               <number>120</number>+              </property>+              <property name="singleStep">+               <number>2</number>+              </property>+             </widget>+            </item>+            <item row="4" column="0" colspan="2">+             <widget class="QCheckBox" name="cbAdvWrapping">+              <property name="enabled">+               <bool>false</bool>+              </property>+              <property name="toolTip">+               <string>Indent statements and function parameters after wrapping.</string>+              </property>+              <property name="text">+               <string>Intelligent wrapping</string>+              </property>+             </widget>+            </item>+            <item row="5" column="0" colspan="2">+             <widget class="QCheckBox" name="cbOmitWrappedLineNumbers">+              <property name="toolTip">+               <string>Do not add line numbering to lines which were automatically wrapped.</string>+              </property>+              <property name="text">+               <string>Omit line numbers of wrapped lines</string>+              </property>+             </widget>+            </item>+           </layout>+          </widget>+         </item>+         <item>+          <widget class="QGroupBox" name="groupFont">+           <property name="title">+            <string>Font</string>+           </property>+           <layout class="QGridLayout" name="gridLayout_9" columnstretch="0,1">+            <item row="0" column="0">+             <widget class="QLabel" name="label_23">+              <property name="text">+               <string>Font na&amp;me:</string>+              </property>+              <property name="buddy">+               <cstring>comboFontName</cstring>+              </property>+             </widget>+            </item>+            <item row="0" column="1">+             <widget class="QFontComboBox" name="comboFontName">+              <property name="maximumSize">+               <size>+                <width>150</width>+                <height>16777215</height>+               </size>+              </property>+              <property name="font">+               <font/>+              </property>+              <property name="toolTip">+               <string>Select or enter the font name. HTML supports a list of fonts, separated with comma.</string>+              </property>+              <property name="fontFilters">+               <set>QFontComboBox::MonospacedFonts</set>+              </property>+              <property name="currentFont">+               <font>+                <family>Consolas</family>+               </font>+              </property>+             </widget>+            </item>+            <item row="1" column="0">+             <widget class="QLabel" name="label_4">+              <property name="text">+               <string>Font si&amp;ze:</string>+              </property>+              <property name="buddy">+               <cstring>leFontSize</cstring>+              </property>+             </widget>+            </item>+            <item row="1" column="1">+             <widget class="QLineEdit" name="leFontSize">+              <property name="sizePolicy">+               <sizepolicy hsizetype="Preferred" vsizetype="Fixed">+                <horstretch>0</horstretch>+                <verstretch>0</verstretch>+               </sizepolicy>+              </property>+              <property name="maximumSize">+               <size>+                <width>150</width>+                <height>16777215</height>+               </size>+              </property>+              <property name="toolTip">+               <string>Enter the font size.</string>+              </property>+              <property name="text">+               <string>10</string>+              </property>+             </widget>+            </item>+           </layout>+          </widget>+         </item>         </layout>        </widget>       </widget>      </item>+     <item>+      <layout class="QHBoxLayout" name="horizontalLayoutConvert">+       <item>+        <spacer name="horizontalSpacerConvert">+         <property name="orientation">+          <enum>Qt::Horizontal</enum>+         </property>+         <property name="sizeHint" stdset="0">+          <size>+           <width>40</width>+           <height>20</height>+          </size>+         </property>+        </spacer>+       </item>+       <item>+        <widget class="QPushButton" name="pbCopyFile2CP">+         <property name="sizePolicy">+          <sizepolicy hsizetype="Minimum" vsizetype="Preferred">+           <horstretch>0</horstretch>+           <verstretch>0</verstretch>+          </sizepolicy>+         </property>+         <property name="toolTip">+          <string>Copy highlighted code of the selected file into the clipboard.</string>+         </property>+         <property name="text">+          <string>Copy file to clipboard</string>+         </property>+        </widget>+       </item>+       <item>+        <widget class="QPushButton" name="pbStartConversion">+         <property name="sizePolicy">+          <sizepolicy hsizetype="Preferred" vsizetype="Fixed">+           <horstretch>0</horstretch>+           <verstretch>0</verstretch>+          </sizepolicy>+         </property>+         <property name="minimumSize">+          <size>+           <width>120</width>+           <height>0</height>+          </size>+         </property>+         <property name="font">+          <font>+           <pointsize>11</pointsize>+           <weight>75</weight>+           <bold>true</bold>+          </font>+         </property>+         <property name="toolTip">+          <string>Start the conversion of the files in the input list.</string>+         </property>+         <property name="text">+          <string>Convert files</string>+         </property>+         <property name="default">+          <bool>true</bool>+         </property>+        </widget>+       </item>+       <item>+        <spacer name="horizontalSpacerConvertRight">+         <property name="orientation">+          <enum>Qt::Horizontal</enum>+         </property>+         <property name="sizeHint" stdset="0">+          <size>+           <width>40</width>+           <height>20</height>+          </size>+         </property>+        </spacer>+       </item>+      </layout>+     </item>     </layout>    </widget>   </widget>@@ -2713,7 +2789,8 @@ Set the width to 0 to keep tabs.</string>   <tabstop>leSVGStyleFile</tabstop>   <tabstop>leSVGStyleIncFile</tabstop>   <tabstop>pbSVGChooseStyleIncFile</tabstop>-  <tabstop>comboTheme</tabstop>+  <tabstop>leThemeSearch</tabstop>+  <tabstop>lvThemes</tabstop>   <tabstop>cbReformat</tabstop>   <tabstop>comboReformat</tabstop>   <tabstop>cbKwCase</tabstop>@@ -2724,9 +2801,9 @@ Set the width to 0 to keep tabs.</string>   <tabstop>cbAdvWrapping</tabstop>   <tabstop>comboFontName</tabstop>   <tabstop>leFontSize</tabstop>-  <tabstop>browserPreview</tabstop>-  <tabstop>pbStartConversion</tabstop>   <tabstop>pbCopyFile2CP</tabstop>+  <tabstop>pbStartConversion</tabstop>+  <tabstop>browserPreview</tabstop>  </tabstops>  <resources>   <include location="highlight-gui.qrc"/>

src/gui-qt/syntaxpalette.cpp

new file mode 100644@@ -0,0 +1,163 @@+/***************************************************************************+                               syntaxpalette.cpp+                             -------------------+    begin                : 2026+    copyright            : (C) 2009-2026 by Andre Simon+    email                : a.simon@mailbox.org+ ***************************************************************************/++/*+This file is part of Highlight.++Highlight is free software: you can redistribute it and/or modify+it under the terms of the GNU General Public License as published by+the Free Software Foundation, either version 3 of the License, or+(at your option) any later version.++Highlight is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+GNU General Public License for more details.++You should have received a copy of the GNU General Public License+along with Highlight.  If not, see <http://www.gnu.org/licenses/>.+*/++#include "syntaxpalette.h"++#include <QCoreApplication>+#include <QKeyEvent>+#include <QLineEdit>+#include <QListView>+#include <QScreen>+#include <QVBoxLayout>++SyntaxFilterProxyModel::SyntaxFilterProxyModel(QObject *parent)+    : QSortFilterProxyModel(parent)+{+}++void SyntaxFilterProxyModel::setSearchText(const QString &text)+{+    searchText = text.trimmed();+    invalidate();+}++bool SyntaxFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const+{+    if (searchText.isEmpty())+        return true;++    QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent);+    return idx.data(Qt::DisplayRole).toString().contains(searchText, Qt::CaseInsensitive)+           || idx.data(Qt::UserRole).toString().contains(searchText, Qt::CaseInsensitive);+}++int SyntaxFilterProxyModel::rank(const QModelIndex &index) const+{+    if (searchText.isEmpty())+        return 0;++    if (index.data(Qt::DisplayRole).toString().startsWith(searchText, Qt::CaseInsensitive)+        || index.data(Qt::UserRole).toString().compare(searchText, Qt::CaseInsensitive) == 0)+        return 0;+    return 1;+}++bool SyntaxFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const+{+    int leftRank = rank(left);+    int rightRank = rank(right);+    if (leftRank != rightRank)+        return leftRank < rightRank;++    // keep the order of the source model within a rank+    return left.row() < right.row();+}++SyntaxPalette::SyntaxPalette(QAbstractItemModel *model, QWidget *parent)+    : QFrame(parent, Qt::Popup)+{+    setFrameStyle(QFrame::StyledPanel | QFrame::Raised);++    leSearch = new QLineEdit(this);+    leSearch->setPlaceholderText(tr("Search syntax or file extension"));+    leSearch->setClearButtonEnabled(true);+    leSearch->installEventFilter(this);++    proxy = new SyntaxFilterProxyModel(this);+    proxy->setSourceModel(model);+    proxy->sort(0);++    lvSyntaxes = new QListView(this);+    lvSyntaxes->setModel(proxy);+    lvSyntaxes->setEditTriggers(QAbstractItemView::NoEditTriggers);+    lvSyntaxes->setUniformItemSizes(true);+    lvSyntaxes->setFocusPolicy(Qt::NoFocus);++    QVBoxLayout *layout = new QVBoxLayout(this);+    layout->setContentsMargins(4, 4, 4, 4);+    layout->setSpacing(4);+    layout->addWidget(leSearch);+    layout->addWidget(lvSyntaxes);++    connect(leSearch, &QLineEdit::textChanged, this, &SyntaxPalette::onSearchTextChanged);+    connect(leSearch, &QLineEdit::returnPressed, this, &SyntaxPalette::acceptCurrent);+    connect(lvSyntaxes, &QListView::clicked, this, &SyntaxPalette::acceptCurrent);+}++void SyntaxPalette::popup(QWidget *anchor, int currentRow)+{+    leSearch->clear();++    QModelIndex current = proxy->mapFromSource(proxy->sourceModel()->index(currentRow, 0));+    lvSyntaxes->setCurrentIndex(current);+    lvSyntaxes->scrollTo(current, QAbstractItemView::PositionAtCenter);++    resize(qMax(anchor->width(), 280), 320);++    // open below the anchor, or above it if there is not enough space on the screen+    QPoint pos = anchor->mapToGlobal(QPoint(0, anchor->height()));+    QRect screenRect = anchor->screen()->availableGeometry();+    if (pos.y() + height() > screenRect.bottom())+        pos.setY(anchor->mapToGlobal(QPoint(0, 0)).y() - height());+    pos.setX(qBound(screenRect.left(), pos.x(), screenRect.right() - width()));+    move(pos);++    show();+    leSearch->setFocus();+}++bool SyntaxPalette::eventFilter(QObject *watched, QEvent *event)+{+    // let the list be navigated while the search field keeps the focus+    if (watched == leSearch && event->type() == QEvent::KeyPress) {+        switch (static_cast<QKeyEvent *>(event)->key()) {+        case Qt::Key_Up:+        case Qt::Key_Down:+        case Qt::Key_PageUp:+        case Qt::Key_PageDown:+            QCoreApplication::sendEvent(lvSyntaxes, event);+            return true;+        default:+            break;+        }+    }+    return QFrame::eventFilter(watched, event);+}++void SyntaxPalette::onSearchTextChanged(const QString &text)+{+    proxy->setSearchText(text);+    lvSyntaxes->setCurrentIndex(proxy->index(0, 0));+}++void SyntaxPalette::acceptCurrent()+{+    QModelIndex current = lvSyntaxes->currentIndex();+    if (!current.isValid())+        return;++    close();+    emit syntaxSelected(proxy->mapToSource(current).row());+}

src/gui-qt/syntaxpalette.h

new file mode 100644@@ -0,0 +1,94 @@+/***************************************************************************+                               syntaxpalette.h+                             -------------------+    begin                : 2026+    copyright            : (C) 2009-2026 by Andre Simon+    email                : a.simon@mailbox.org+ ***************************************************************************/++/*+This file is part of Highlight.++Highlight is free software: you can redistribute it and/or modify+it under the terms of the GNU General Public License as published by+the Free Software Foundation, either version 3 of the License, or+(at your option) any later version.++Highlight is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+GNU General Public License for more details.++You should have received a copy of the GNU General Public License+along with Highlight.  If not, see <http://www.gnu.org/licenses/>.+*/++#ifndef SYNTAXPALETTE_H+#define SYNTAXPALETTE_H++#include <QFrame>+#include <QSortFilterProxyModel>+#include <QString>++class QAbstractItemModel;+class QLineEdit;+class QListView;++/** Filters syntax names by a search text which must be contained in the+    name or in the file extension (Qt::UserRole); names starting with the+    search text are listed first */+class SyntaxFilterProxyModel : public QSortFilterProxyModel+{+    Q_OBJECT++public:+    explicit SyntaxFilterProxyModel(QObject *parent = nullptr);++public slots:+    void setSearchText(const QString &text);++protected:+    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;+    bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;++private:+    QString searchText;++    int rank(const QModelIndex &index) const;+};++/** Popup with a search field and a filtered list of syntax names,+    similar to the locator of an IDE */+class SyntaxPalette : public QFrame+{+    Q_OBJECT++public:+    /** \param model list of syntax names (display role) and their file extensions (Qt::UserRole)+        \param parent parent widget */+    explicit SyntaxPalette(QAbstractItemModel *model, QWidget *parent = nullptr);++    /** Show the palette below the anchor widget+        \param anchor widget which opened the palette+        \param currentRow source model row of the current syntax */+    void popup(QWidget *anchor, int currentRow);++signals:+    /** Emitted when the user picked a syntax+        \param row source model row of the selected syntax */+    void syntaxSelected(int row);++protected:+    bool eventFilter(QObject *watched, QEvent *event) override;++private slots:+    void onSearchTextChanged(const QString &text);+    void acceptCurrent();++private:+    QLineEdit *leSearch;+    QListView *lvSyntaxes;+    SyntaxFilterProxyModel *proxy;+};++#endif // SYNTAXPALETTE_H

src/gui-qt/thememodel.cpp

new file mode 100644@@ -0,0 +1,154 @@+/***************************************************************************+                               thememodel.cpp+                             -------------------+    begin                : 2026+    copyright            : (C) 2009-2026 by Andre Simon+    email                : a.simon@mailbox.org+ ***************************************************************************/++/*+This file is part of Highlight.++Highlight is free software: you can redistribute it and/or modify+it under the terms of the GNU General Public License as published by+the Free Software Foundation, either version 3 of the License, or+(at your option) any later version.++Highlight is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+GNU General Public License for more details.++You should have received a copy of the GNU General Public License+along with Highlight.  If not, see <http://www.gnu.org/licenses/>.+*/++#include "thememodel.h"++#include "themereader.h"++namespace+{+QColor toQColor(const highlight::Colour &c)+{+    return QColor(c.getRed(), c.getGreen(), c.getBlue());+}+}++ThemeListModel::ThemeListModel(QObject *parent)+    : QAbstractListModel(parent)+{+}++QStringList ThemeListModel::addThemes(const QDir &dir, const QString &idPrefix)+{+    QStringList errors;+    QList<ThemeEntry> newThemes;++    const QStringList files = dir.entryList(QStringList("*.theme"), QDir::Files, QDir::Name);+    for (const auto &fileName : files) {+        highlight::ThemeReader reader;+        if (!reader.load(dir.absoluteFilePath(fileName).toStdString())) {+            errors << QString("%1: %2").arg(fileName, QString::fromStdString(reader.getErrorMessage()));+            continue;+        }++        ThemeEntry entry;+        entry.id = idPrefix + fileName.section('.', 0, 0);+        entry.description = QString::fromStdString(reader.getDescription());+        if (entry.description.isEmpty())+            entry.description = fileName.section('.', 0, 0);+        entry.categories = QString::fromStdString(reader.getCategoryDescription())+                               .split(',', Qt::SkipEmptyParts);+        entry.background = toQColor(reader.getBgColour());+        entry.foreground = toQColor(reader.getDefaultStyle().getColour());+        entry.keyword = toQColor(reader.getKeywordStyle("kwa").getColour());+        entry.type = toQColor(reader.getKeywordStyle("kwb").getColour());+        entry.string = toQColor(reader.getStringStyle().getColour());+        entry.number = toQColor(reader.getNumberStyle().getColour());+        entry.comment = toQColor(reader.getCommentStyle().getColour());+        newThemes.append(entry);+    }++    if (!newThemes.isEmpty()) {+        beginInsertRows(QModelIndex(), themes.size(), themes.size() + newThemes.size() - 1);+        themes.append(newThemes);+        endInsertRows();+    }+    return errors;+}++int ThemeListModel::rowCount(const QModelIndex &parent) const+{+    return parent.isValid() ? 0 : themes.size();+}++QVariant ThemeListModel::data(const QModelIndex &index, int role) const+{+    if (!index.isValid() || index.row() >= themes.size())+        return QVariant();++    const ThemeEntry &t = themes.at(index.row());+    switch (role) {+    case Qt::DisplayRole:+        return t.description;+    case Qt::ToolTipRole:+        return QString("%1\n%2").arg(t.id, t.categories.join(", "));+    case ThemeIdRole:+        return t.id;+    case CategoriesRole:+        return t.categories;+    case SearchTextRole:+        return QString("%1 %2 %3").arg(t.id, t.description, t.categories.join(' '));+    case BackgroundRole:+        return t.background;+    case ForegroundRole:+        return t.foreground;+    case KeywordRole:+        return t.keyword;+    case TypeRole:+        return t.type;+    case StringRole:+        return t.string;+    case NumberRole:+        return t.number;+    case CommentRole:+        return t.comment;+    default:+        return QVariant();+    }+}++int ThemeListModel::rowOfTheme(const QString &id) const+{+    for (int i = 0; i < themes.size(); ++i) {+        if (themes.at(i).id == id)+            return i;+    }+    return -1;+}++ThemeFilterProxyModel::ThemeFilterProxyModel(QObject *parent)+    : QSortFilterProxyModel(parent)+{+}++void ThemeFilterProxyModel::setSearchText(const QString &text)+{+    searchTerms = text.split(' ', Qt::SkipEmptyParts);+    invalidateFilter();+}++bool ThemeFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const+{+    if (searchTerms.isEmpty())+        return true;++    QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent);+    QString haystack = idx.data(ThemeListModel::SearchTextRole).toString();+    for (const auto &term : searchTerms) {+        if (!haystack.contains(term, Qt::CaseInsensitive))+            return false;+    }+    return true;+}

src/gui-qt/thememodel.h

new file mode 100644@@ -0,0 +1,108 @@+/***************************************************************************+                               thememodel.h+                             -------------------+    begin                : 2026+    copyright            : (C) 2009-2026 by Andre Simon+    email                : a.simon@mailbox.org+ ***************************************************************************/++/*+This file is part of Highlight.++Highlight is free software: you can redistribute it and/or modify+it under the terms of the GNU General Public License as published by+the Free Software Foundation, either version 3 of the License, or+(at your option) any later version.++Highlight is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+GNU General Public License for more details.++You should have received a copy of the GNU General Public License+along with Highlight.  If not, see <http://www.gnu.org/licenses/>.+*/++#ifndef THEMEMODEL_H+#define THEMEMODEL_H++#include <QAbstractListModel>+#include <QSortFilterProxyModel>+#include <QColor>+#include <QDir>+#include <QList>+#include <QString>+#include <QStringList>++/** Metadata and preview colours of one colour theme */+struct ThemeEntry+{+    QString id;           ///< path relative to the themes dir without suffix, e.g. "base16/monokai"+    QString description;+    QStringList categories;+    QColor background;+    QColor foreground;+    QColor keyword;+    QColor type;+    QColor string;+    QColor number;+    QColor comment;+};++/** List model of all installed colour themes */+class ThemeListModel : public QAbstractListModel+{+    Q_OBJECT++public:+    enum Roles {+        ThemeIdRole = Qt::UserRole + 1,+        CategoriesRole,+        SearchTextRole,+        BackgroundRole,+        ForegroundRole,+        KeywordRole,+        TypeRole,+        StringRole,+        NumberRole,+        CommentRole+    };++    explicit ThemeListModel(QObject *parent = nullptr);++    /** Read all *.theme files of dir and append them to the model+        \param dir theme directory+        \param idPrefix prefix of the theme ids (e.g. "base16/")+        \return list of error messages of themes which could not be read */+    QStringList addThemes(const QDir &dir, const QString &idPrefix = QString());++    int rowCount(const QModelIndex &parent = QModelIndex()) const override;+    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;++    /** \return row of theme with the given id, -1 if not found */+    int rowOfTheme(const QString &id) const;++private:+    QList<ThemeEntry> themes;+};++/** Filters themes by whitespace separated search terms, all of which must+    match the theme name, description or one of its categories */+class ThemeFilterProxyModel : public QSortFilterProxyModel+{+    Q_OBJECT++public:+    explicit ThemeFilterProxyModel(QObject *parent = nullptr);++public slots:+    void setSearchText(const QString &text);++protected:+    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;++private:+    QStringList searchTerms;+};++#endif // THEMEMODEL_H

src/gui-qt/themeswatchdelegate.cpp

new file mode 100644@@ -0,0 +1,132 @@+/***************************************************************************+                               themeswatchdelegate.cpp+                             -------------------+    begin                : 2026+    copyright            : (C) 2009-2026 by Andre Simon+    email                : a.simon@mailbox.org+ ***************************************************************************/++/*+This file is part of Highlight.++Highlight is free software: you can redistribute it and/or modify+it under the terms of the GNU General Public License as published by+the Free Software Foundation, either version 3 of the License, or+(at your option) any later version.++Highlight is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+GNU General Public License for more details.++You should have received a copy of the GNU General Public License+along with Highlight.  If not, see <http://www.gnu.org/licenses/>.+*/++#include "themeswatchdelegate.h"+#include "thememodel.h"++#include <QApplication>+#include <QPainter>+#include <QPainterPath>++namespace+{+const int Margin = 4;+const int Radius = 4;++/** One bar of a fake code line: colour role and relative width */+struct Bar+{+    int role;+    qreal width;+};+}++ThemeSwatchDelegate::ThemeSwatchDelegate(QObject *parent)+    : QStyledItemDelegate(parent)+{+}++QSize ThemeSwatchDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex & /*index*/) const+{+    return QSize(CardWidth + 2 * Margin,+                 SwatchHeight + option.fontMetrics.height() + 4 * Margin);+}++void ThemeSwatchDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,+                                const QModelIndex &index) const+{+    painter->save();+    painter->setRenderHint(QPainter::Antialiasing);++    const QPalette &pal = option.palette;+    const bool selected = option.state & QStyle::State_Selected;+    const bool hovered = option.state & QStyle::State_MouseOver;+    const bool enabled = option.state & QStyle::State_Enabled;++    QRectF card = QRectF(option.rect).adjusted(Margin / 2.0, Margin / 2.0, -Margin / 2.0, -Margin / 2.0);++    // card frame+    if (selected) {+        painter->setPen(QPen(pal.color(QPalette::Highlight), 2));+        painter->setBrush(pal.color(QPalette::Highlight).lighter(170));+    } else {+        painter->setPen(QPen(hovered ? pal.color(QPalette::Highlight) : pal.color(QPalette::Mid), 1));+        painter->setBrush(pal.color(QPalette::Base));+    }+    painter->drawRoundedRect(card, Radius, Radius);++    // swatch with background colour and some coloured "code" bars+    QRectF swatch(card.left() + Margin, card.top() + Margin,+                  card.width() - 2 * Margin, SwatchHeight);+    QColor bg = index.data(ThemeListModel::BackgroundRole).value<QColor>();+    painter->setPen(QPen(pal.color(QPalette::Mid), 1));+    painter->setBrush(bg);+    painter->drawRoundedRect(swatch, Radius, Radius);++    const QList<QList<Bar>> lines = {+        { { ThemeListModel::KeywordRole, 0.18 }, { ThemeListModel::TypeRole, 0.22 }, { ThemeListModel::ForegroundRole, 0.25 } },+        { { ThemeListModel::ForegroundRole, 0.12 }, { ThemeListModel::StringRole, 0.40 }, { ThemeListModel::NumberRole, 0.10 } },+        { { ThemeListModel::KeywordRole, 0.14 }, { ThemeListModel::NumberRole, 0.12 }, { ThemeListModel::ForegroundRole, 0.20 } },+        { { ThemeListModel::CommentRole, 0.70 } }+    };++    const qreal pad = 6.0;+    const qreal gap = 4.0;+    const qreal lineHeight = (SwatchHeight - 2 * pad) / lines.size();+    const qreal barHeight = lineHeight * 0.55;+    const qreal usable = swatch.width() - 2 * pad;++    painter->setPen(Qt::NoPen);+    for (int l = 0; l < lines.size(); ++l) {+        qreal x = swatch.left() + pad;+        qreal y = swatch.top() + pad + l * lineHeight + (lineHeight - barHeight) / 2;+        for (const Bar &bar : lines.at(l)) {+            qreal w = usable * bar.width;+            painter->setBrush(index.data(bar.role).value<QColor>());+            painter->drawRoundedRect(QRectF(x, y, w, barHeight), barHeight / 2, barHeight / 2);+            x += w + gap;+        }+    }++    // theme name+    QRectF textRect(card.left() + Margin, swatch.bottom() + Margin,+                    card.width() - 2 * Margin, option.fontMetrics.height());+    QString name = option.fontMetrics.elidedText(index.data(Qt::DisplayRole).toString(),+                                                 Qt::ElideRight, int(textRect.width()));+    QPalette::ColorGroup group = enabled ? QPalette::Normal : QPalette::Disabled;+    painter->setPen(pal.color(group, QPalette::Text));+    painter->setFont(option.font);+    painter->drawText(textRect, Qt::AlignHCenter | Qt::AlignVCenter, name);++    if (!enabled) {+        QColor veil = pal.color(QPalette::Window);+        veil.setAlpha(140);+        painter->setPen(Qt::NoPen);+        painter->setBrush(veil);+        painter->drawRoundedRect(card, Radius, Radius);+    }++    painter->restore();+}

src/gui-qt/themeswatchdelegate.h

new file mode 100644@@ -0,0 +1,48 @@+/***************************************************************************+                               themeswatchdelegate.h+                             -------------------+    begin                : 2026+    copyright            : (C) 2009-2026 by Andre Simon+    email                : a.simon@mailbox.org+ ***************************************************************************/++/*+This file is part of Highlight.++Highlight is free software: you can redistribute it and/or modify+it under the terms of the GNU General Public License as published by+the Free Software Foundation, either version 3 of the License, or+(at your option) any later version.++Highlight is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+GNU General Public License for more details.++You should have received a copy of the GNU General Public License+along with Highlight.  If not, see <http://www.gnu.org/licenses/>.+*/++#ifndef THEMESWATCHDELEGATE_H+#define THEMESWATCHDELEGATE_H++#include <QStyledItemDelegate>++/** Paints a theme of ThemeListModel as a card with a small code-like+    colour swatch and the theme name below */+class ThemeSwatchDelegate : public QStyledItemDelegate+{+    Q_OBJECT++public:+    explicit ThemeSwatchDelegate(QObject *parent = nullptr);++    void paint(QPainter *painter, const QStyleOptionViewItem &option,+               const QModelIndex &index) const override;+    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;++    static constexpr int CardWidth = 150;+    static constexpr int SwatchHeight = 60;+};++#endif // THEMESWATCHDELEGATE_H

src/include/ansigenerator.h

@@ -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; 

src/include/astyle/astyle.h

@@ -8,7 +8,7 @@  // ignore size_t to int conversion warning for now #ifdef _WIN64-	#pragma warning( disable : 4267 )+#pragma warning( disable : 4267 ) #endif  //-----------------------------------------------------------------------------@@ -20,17 +20,19 @@ #include <cctype> #include <iostream> #include <memory>+#include <optional> #include <string> #include <string_view> #include <vector>  #ifdef __GNUC__-	#include <cstring>              // need both string and cstring for GCC+#include <cstring>              // need both string and cstring for GCC #endif -#define ASTYLE_VERSION "3.6.14"+#define ASTYLE_VERSION "3.6.21" -namespace astyle {+namespace astyle+{  //---------------------------------------------------------------------------- // definitions@@ -43,119 +45,131 @@ enum FileType { C_TYPE = 0, JAVA_TYPE = 1, SHARP_TYPE = 2, JS_TYPE = 3, OBJC_TYP */ enum FormatStyle {

The diff stops at 1024 KiB. git show bebfec1 shows the rest.